[win32k]
[reactos.git] / reactos / subsystems / win32 / win32k / ntuser / window.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Windows
5 * FILE: subsystems/win32/win32k/ntuser/window.c
6 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * REVISION HISTORY:
8 * 06-06-2001 CSH Created
9 */
10
11 /* INCLUDES ******************************************************************/
12
13 #include <win32k.h>
14
15 #define NDEBUG
16 #include <debug.h>
17
18
19 /* dialog resources appear to pass this in 16 bits, handle them properly */
20 #define CW_USEDEFAULT16 (0x8000)
21
22 #define POINT_IN_RECT(p, r) (((r.bottom >= p.y) && (r.top <= p.y))&&((r.left <= p.x )&&( r.right >= p.x )))
23
24 /* PRIVATE FUNCTIONS **********************************************************/
25
26 /*
27 * InitWindowImpl
28 *
29 * Initialize windowing implementation.
30 */
31
32 NTSTATUS FASTCALL
33 InitWindowImpl(VOID)
34 {
35 return STATUS_SUCCESS;
36 }
37
38 /*
39 * CleanupWindowImpl
40 *
41 * Cleanup windowing implementation.
42 */
43
44 NTSTATUS FASTCALL
45 CleanupWindowImpl(VOID)
46 {
47 return STATUS_SUCCESS;
48 }
49
50 /* HELPER FUNCTIONS ***********************************************************/
51
52 BOOL FASTCALL UserUpdateUiState(PWND Wnd, WPARAM wParam)
53 {
54 WORD Action = LOWORD(wParam);
55 WORD Flags = HIWORD(wParam);
56
57 if (Flags & ~(UISF_HIDEFOCUS | UISF_HIDEACCEL | UISF_ACTIVE))
58 {
59 SetLastWin32Error(ERROR_INVALID_PARAMETER);
60 return FALSE;
61 }
62
63 switch (Action)
64 {
65 case UIS_INITIALIZE:
66 SetLastWin32Error(ERROR_INVALID_PARAMETER);
67 return FALSE;
68
69 case UIS_SET:
70 if (Flags & UISF_HIDEFOCUS)
71 Wnd->HideFocus = TRUE;
72 if (Flags & UISF_HIDEACCEL)
73 Wnd->HideAccel = TRUE;
74 break;
75
76 case UIS_CLEAR:
77 if (Flags & UISF_HIDEFOCUS)
78 Wnd->HideFocus = FALSE;
79 if (Flags & UISF_HIDEACCEL)
80 Wnd->HideAccel = FALSE;
81 break;
82 }
83
84 return TRUE;
85 }
86
87 PWINDOW_OBJECT FASTCALL IntGetWindowObject(HWND hWnd)
88 {
89 PWINDOW_OBJECT Window;
90
91 if (!hWnd) return NULL;
92
93 Window = UserGetWindowObject(hWnd);
94 if (Window)
95 {
96 ASSERT(Window->head.cLockObj >= 0);
97
98 Window->head.cLockObj++;
99 }
100 return Window;
101 }
102
103 /* temp hack */
104 PWINDOW_OBJECT FASTCALL UserGetWindowObject(HWND hWnd)
105 {
106 PTHREADINFO ti;
107 PWINDOW_OBJECT Window;
108
109 if (PsGetCurrentProcess() != PsInitialSystemProcess)
110 {
111 ti = GetW32ThreadInfo();
112 if (ti == NULL)
113 {
114 SetLastWin32Error(ERROR_ACCESS_DENIED);
115 return NULL;
116 }
117 }
118
119 if (!hWnd)
120 {
121 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
122 return NULL;
123 }
124
125 Window = (PWINDOW_OBJECT)UserGetObject(gHandleTable, hWnd, otWindow);
126 if (!Window || 0 != (Window->state & WINDOWSTATUS_DESTROYED))
127 {
128 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
129 return NULL;
130 }
131
132 ASSERT(Window->head.cLockObj >= 0);
133 return Window;
134 }
135
136
137 /*
138 * IntIsWindow
139 *
140 * The function determines whether the specified window handle identifies
141 * an existing window.
142 *
143 * Parameters
144 * hWnd
145 * Handle to the window to test.
146 *
147 * Return Value
148 * If the window handle identifies an existing window, the return value
149 * is TRUE. If the window handle does not identify an existing window,
150 * the return value is FALSE.
151 */
152
153 BOOL FASTCALL
154 IntIsWindow(HWND hWnd)
155 {
156 PWINDOW_OBJECT Window;
157
158 if (!(Window = UserGetWindowObject(hWnd)))
159 return FALSE;
160
161 return TRUE;
162 }
163
164
165
166 /*
167 Caller must NOT dereference retval!
168 But if caller want the returned value to persist spanning a co_ call,
169 it must reference the value (because the owner is not garanteed to
170 exist just because the owned window exist)!
171 */
172 PWINDOW_OBJECT FASTCALL
173 IntGetParent(PWINDOW_OBJECT Wnd)
174 {
175 if (!Wnd->Wnd) return NULL;
176
177 if (Wnd->Wnd->style & WS_POPUP)
178 {
179 return UserGetWindowObject(Wnd->hOwner);
180 }
181 else if (Wnd->Wnd->style & WS_CHILD)
182 {
183 return Wnd->spwndParent;
184 }
185
186 return NULL;
187 }
188
189
190 /*
191 Caller must NOT dereference retval!
192 But if caller want the returned value to persist spanning a co_ call,
193 it must reference the value (because the owner is not garanteed to
194 exist just because the owned window exist)!
195 */
196 PWINDOW_OBJECT FASTCALL
197 IntGetOwner(PWINDOW_OBJECT Wnd)
198 {
199 return UserGetWindowObject(Wnd->hOwner);
200 }
201
202
203
204 /*
205 * IntWinListChildren
206 *
207 * Compile a list of all child window handles from given window.
208 *
209 * Remarks
210 * This function is similar to Wine WIN_ListChildren. The caller
211 * must free the returned list with ExFreePool.
212 */
213
214 HWND* FASTCALL
215 IntWinListChildren(PWINDOW_OBJECT Window)
216 {
217 PWINDOW_OBJECT Child;
218 HWND *List;
219 UINT Index, NumChildren = 0;
220
221 if (!Window) return NULL;
222
223 for (Child = Window->spwndChild; Child; Child = Child->spwndNext)
224 ++NumChildren;
225
226 List = ExAllocatePoolWithTag(PagedPool, (NumChildren + 1) * sizeof(HWND), TAG_WINLIST);
227 if(!List)
228 {
229 DPRINT1("Failed to allocate memory for children array\n");
230 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
231 return NULL;
232 }
233 for (Child = Window->spwndChild, Index = 0;
234 Child != NULL;
235 Child = Child->spwndNext, ++Index)
236 List[Index] = Child->hSelf;
237 List[Index] = NULL;
238
239 return List;
240 }
241
242 /***********************************************************************
243 * IntSendDestroyMsg
244 */
245 static void IntSendDestroyMsg(HWND hWnd)
246 {
247
248 PWINDOW_OBJECT Window;
249 #if 0 /* FIXME */
250
251 GUITHREADINFO info;
252
253 if (GetGUIThreadInfo(GetCurrentThreadId(), &info))
254 {
255 if (hWnd == info.hwndCaret)
256 {
257 DestroyCaret();
258 }
259 }
260 #endif
261
262 Window = UserGetWindowObject(hWnd);
263 if (Window)
264 {
265 // USER_REFERENCE_ENTRY Ref;
266 // UserRefObjectCo(Window, &Ref);
267
268 if (!IntGetOwner(Window) && !IntGetParent(Window))
269 {
270 co_IntShellHookNotify(HSHELL_WINDOWDESTROYED, (LPARAM) hWnd);
271 }
272
273 // UserDerefObjectCo(Window);
274 }
275
276 /* The window could already be destroyed here */
277
278 /*
279 * Send the WM_DESTROY to the window.
280 */
281
282 co_IntSendMessage(hWnd, WM_DESTROY, 0, 0);
283
284 /*
285 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
286 * make sure that the window still exists when we come back.
287 */
288 #if 0 /* FIXME */
289
290 if (IsWindow(Wnd))
291 {
292 HWND* pWndArray;
293 int i;
294
295 if (!(pWndArray = WIN_ListChildren( hwnd )))
296 return;
297
298 /* start from the end (FIXME: is this needed?) */
299 for (i = 0; pWndArray[i]; i++)
300 ;
301
302 while (--i >= 0)
303 {
304 if (IsWindow( pWndArray[i] ))
305 WIN_SendDestroyMsg( pWndArray[i] );
306 }
307 HeapFree(GetProcessHeap(), 0, pWndArray);
308 }
309 else
310 {
311 DPRINT("destroyed itself while in WM_DESTROY!\n");
312 }
313 #endif
314 }
315
316 static VOID
317 UserFreeWindowInfo(PTHREADINFO ti, PWINDOW_OBJECT WindowObject)
318 {
319 PCLIENTINFO ClientInfo = GetWin32ClientInfo();
320 PWND Wnd = WindowObject->Wnd;
321
322 if (!Wnd) return;
323
324 if (ClientInfo->CallbackWnd.pvWnd == DesktopHeapAddressToUser(WindowObject->Wnd))
325 {
326 ClientInfo->CallbackWnd.hWnd = NULL;
327 ClientInfo->CallbackWnd.pvWnd = NULL;
328 }
329
330 if (Wnd->strName.Buffer != NULL)
331 {
332 Wnd->strName.Length = 0;
333 Wnd->strName.MaximumLength = 0;
334 DesktopHeapFree(Wnd->head.rpdesk,
335 Wnd->strName.Buffer);
336 Wnd->strName.Buffer = NULL;
337 }
338
339 DesktopHeapFree(Wnd->head.rpdesk, Wnd);
340 WindowObject->Wnd = NULL;
341 }
342
343 /***********************************************************************
344 * IntDestroyWindow
345 *
346 * Destroy storage associated to a window. "Internals" p.358
347 *
348 * This is the "functional" DestroyWindows function ei. all stuff
349 * done in CreateWindow is undone here and not in DestroyWindow:-P
350
351 */
352 static LRESULT co_UserFreeWindow(PWINDOW_OBJECT Window,
353 PPROCESSINFO ProcessData,
354 PTHREADINFO ThreadData,
355 BOOLEAN SendMessages)
356 {
357 HWND *Children;
358 HWND *ChildHandle;
359 PWINDOW_OBJECT Child;
360 PMENU_OBJECT Menu;
361 BOOLEAN BelongsToThreadData;
362 PWND Wnd;
363
364 ASSERT(Window);
365
366 Wnd = Window->Wnd;
367
368 if(Window->state & WINDOWSTATUS_DESTROYING)
369 {
370 DPRINT("Tried to call IntDestroyWindow() twice\n");
371 return 0;
372 }
373 Window->state |= WINDOWSTATUS_DESTROYING;
374 Wnd->style &= ~WS_VISIBLE;
375
376 IntNotifyWinEvent(EVENT_OBJECT_DESTROY, Wnd, OBJID_WINDOW, 0);
377
378 /* remove the window already at this point from the thread window list so we
379 don't get into trouble when destroying the thread windows while we're still
380 in IntDestroyWindow() */
381 RemoveEntryList(&Window->ThreadListEntry);
382
383 BelongsToThreadData = IntWndBelongsToThread(Window, ThreadData);
384
385 IntDeRegisterShellHookWindow(Window->hSelf);
386
387 if(SendMessages)
388 {
389 /* Send destroy messages */
390 IntSendDestroyMsg(Window->hSelf);
391 }
392
393 /* free child windows */
394 Children = IntWinListChildren(Window);
395 if (Children)
396 {
397 for (ChildHandle = Children; *ChildHandle; ++ChildHandle)
398 {
399 if ((Child = IntGetWindowObject(*ChildHandle)))
400 {
401 if(!IntWndBelongsToThread(Child, ThreadData))
402 {
403 /* send WM_DESTROY messages to windows not belonging to the same thread */
404 IntSendDestroyMsg(Child->hSelf);
405 }
406 else
407 co_UserFreeWindow(Child, ProcessData, ThreadData, SendMessages);
408
409 UserDereferenceObject(Child);
410 }
411 }
412 ExFreePool(Children);
413 }
414
415 if(SendMessages)
416 {
417 /*
418 * Clear the update region to make sure no WM_PAINT messages will be
419 * generated for this window while processing the WM_NCDESTROY.
420 */
421 co_UserRedrawWindow(Window, NULL, 0,
422 RDW_VALIDATE | RDW_NOFRAME | RDW_NOERASE |
423 RDW_NOINTERNALPAINT | RDW_NOCHILDREN);
424 if(BelongsToThreadData)
425 co_IntSendMessage(Window->hSelf, WM_NCDESTROY, 0, 0);
426 }
427 DestroyTimersForWindow(ThreadData, Window);
428 HOOK_DestroyThreadHooks(ThreadData->pEThread); // This is needed here too!
429
430 /* flush the message queue */
431 MsqRemoveWindowMessagesFromQueue(Window);
432
433 /* from now on no messages can be sent to this window anymore */
434 Window->state |= WINDOWSTATUS_DESTROYED;
435 Wnd->state |= WNDS_DESTROYED;
436 Wnd->fnid |= FNID_FREED;
437
438 /* don't remove the WINDOWSTATUS_DESTROYING bit */
439
440 /* reset shell window handles */
441 if(ThreadData->rpdesk)
442 {
443 if (Window->hSelf == ThreadData->rpdesk->rpwinstaParent->ShellWindow)
444 ThreadData->rpdesk->rpwinstaParent->ShellWindow = NULL;
445
446 if (Window->hSelf == ThreadData->rpdesk->rpwinstaParent->ShellListView)
447 ThreadData->rpdesk->rpwinstaParent->ShellListView = NULL;
448 }
449
450 /* Unregister hot keys */
451 UnregisterWindowHotKeys (Window);
452
453 /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
454
455 #if 0 /* FIXME */
456
457 WinPosCheckInternalPos(Window->hSelf);
458 if (Window->hSelf == GetCapture())
459 {
460 ReleaseCapture();
461 }
462
463 /* free resources associated with the window */
464 TIMER_RemoveWindowTimers(Window->hSelf);
465 #endif
466
467 if (!(Wnd->style & WS_CHILD) && Wnd->IDMenu
468 && (Menu = UserGetMenuObject((HMENU)Wnd->IDMenu)))
469 {
470 IntDestroyMenuObject(Menu, TRUE, TRUE);
471 Wnd->IDMenu = 0;
472 }
473
474 if(Window->SystemMenu
475 && (Menu = UserGetMenuObject(Window->SystemMenu)))
476 {
477 IntDestroyMenuObject(Menu, TRUE, TRUE);
478 Window->SystemMenu = (HMENU)0;
479 }
480
481 DceFreeWindowDCE(Window); /* Always do this to catch orphaned DCs */
482 #if 0 /* FIXME */
483
484 WINPROC_FreeProc(Window->winproc, WIN_PROC_WINDOW);
485 CLASS_RemoveWindow(Window->Class);
486 #endif
487
488 IntUnlinkWindow(Window);
489
490 UserReferenceObject(Window);
491 UserDeleteObject(Window->hSelf, otWindow);
492
493 IntDestroyScrollBars(Window);
494
495 /* dereference the class */
496 IntDereferenceClass(Wnd->pcls,
497 Window->pti->pDeskInfo,
498 Window->pti->ppi);
499 Wnd->pcls = NULL;
500
501 if(Window->hrgnClip)
502 {
503 GreDeleteObject(Window->hrgnClip);
504 }
505
506 ASSERT(Window->Wnd != NULL);
507 UserFreeWindowInfo(Window->pti, Window);
508
509 UserDereferenceObject(Window);
510
511 IntClipboardFreeWindow(Window);
512
513 return 0;
514 }
515
516 VOID FASTCALL
517 IntGetWindowBorderMeasures(PWINDOW_OBJECT Window, UINT *cx, UINT *cy)
518 {
519 PWND Wnd = Window->Wnd;
520 if(HAS_DLGFRAME(Wnd->style, Wnd->ExStyle) && !(Wnd->style & WS_MINIMIZE))
521 {
522 *cx = UserGetSystemMetrics(SM_CXDLGFRAME);
523 *cy = UserGetSystemMetrics(SM_CYDLGFRAME);
524 }
525 else
526 {
527 if(HAS_THICKFRAME(Wnd->style, Wnd->ExStyle)&& !(Wnd->style & WS_MINIMIZE))
528 {
529 *cx = UserGetSystemMetrics(SM_CXFRAME);
530 *cy = UserGetSystemMetrics(SM_CYFRAME);
531 }
532 else if(HAS_THINFRAME(Wnd->style, Wnd->ExStyle))
533 {
534 *cx = UserGetSystemMetrics(SM_CXBORDER);
535 *cy = UserGetSystemMetrics(SM_CYBORDER);
536 }
537 else
538 {
539 *cx = *cy = 0;
540 }
541 }
542 }
543
544 //
545 // Same as User32:IntGetWndProc.
546 //
547 WNDPROC FASTCALL
548 IntGetWindowProc(PWND pWnd,
549 BOOL Ansi)
550 {
551 INT i;
552 PCLS Class;
553 WNDPROC gcpd, Ret = 0;
554
555 ASSERT(UserIsEnteredExclusive() == TRUE);
556
557 Class = pWnd->pcls;
558
559 if (pWnd->state & WNDS_SERVERSIDEWINDOWPROC)
560 {
561 for ( i = FNID_FIRST; i <= FNID_SWITCH; i++)
562 {
563 if (GETPFNSERVER(i) == pWnd->lpfnWndProc)
564 {
565 if (Ansi)
566 Ret = GETPFNCLIENTA(i);
567 else
568 Ret = GETPFNCLIENTW(i);
569 }
570 }
571 return Ret;
572 }
573
574 if (Class->fnid == FNID_EDIT)
575 Ret = pWnd->lpfnWndProc;
576 else
577 {
578 Ret = pWnd->lpfnWndProc;
579
580 if (Class->fnid <= FNID_GHOST && Class->fnid >= FNID_BUTTON)
581 {
582 if (Ansi)
583 {
584 if (GETPFNCLIENTW(Class->fnid) == pWnd->lpfnWndProc)
585 Ret = GETPFNCLIENTA(Class->fnid);
586 }
587 else
588 {
589 if (GETPFNCLIENTA(Class->fnid) == pWnd->lpfnWndProc)
590 Ret = GETPFNCLIENTW(Class->fnid);
591 }
592 }
593 if ( Ret != pWnd->lpfnWndProc)
594 return Ret;
595 }
596 if ( Ansi == !!(pWnd->state & WNDS_ANSIWINDOWPROC) )
597 return Ret;
598
599 gcpd = (WNDPROC)UserGetCPD(
600 pWnd,
601 (Ansi ? UserGetCPDA2U : UserGetCPDU2A )|UserGetCPDWindow,
602 (ULONG_PTR)Ret);
603
604 return (gcpd ? gcpd : Ret);
605 }
606
607 static WNDPROC
608 IntSetWindowProc(PWND pWnd,
609 WNDPROC NewWndProc,
610 BOOL Ansi)
611 {
612 INT i;
613 PCALLPROCDATA CallProc;
614 PCLS Class;
615 WNDPROC Ret, chWndProc = NULL;
616
617 // Retrieve previous window proc.
618 Ret = IntGetWindowProc(pWnd, Ansi);
619
620 Class = pWnd->pcls;
621
622 if (IsCallProcHandle(NewWndProc))
623 {
624 CallProc = UserGetObject(gHandleTable, NewWndProc, otCallProc);
625 if (CallProc)
626 { // Reset new WndProc.
627 NewWndProc = CallProc->pfnClientPrevious;
628 // Reset Ansi from CallProc handle. This is expected with wine "deftest".
629 Ansi = !!(CallProc->wType & UserGetCPDU2A);
630 }
631 }
632 // Switch from Client Side call to Server Side call if match. Ref: "deftest".
633 for ( i = FNID_FIRST; i <= FNID_SWITCH; i++)
634 {
635 if (GETPFNCLIENTW(i) == NewWndProc)
636 {
637 chWndProc = GETPFNSERVER(i);
638 break;
639 }
640 if (GETPFNCLIENTA(i) == NewWndProc)
641 {
642 chWndProc = GETPFNSERVER(i);
643 break;
644 }
645 }
646 // If match, set/reset to Server Side and clear ansi.
647 if (chWndProc)
648 {
649 pWnd->lpfnWndProc = chWndProc;
650 pWnd->Unicode = TRUE;
651 pWnd->state &= ~WNDS_ANSIWINDOWPROC;
652 pWnd->state |= WNDS_SERVERSIDEWINDOWPROC;
653 }
654 else
655 {
656 pWnd->Unicode = !Ansi;
657 // Handle the state change in here.
658 if (Ansi)
659 pWnd->state |= WNDS_ANSIWINDOWPROC;
660 else
661 pWnd->state &= ~WNDS_ANSIWINDOWPROC;
662
663 if (pWnd->state & WNDS_SERVERSIDEWINDOWPROC)
664 pWnd->state &= ~WNDS_SERVERSIDEWINDOWPROC;
665
666 if (!NewWndProc) NewWndProc = pWnd->lpfnWndProc;
667
668 if (Class->fnid <= FNID_GHOST && Class->fnid >= FNID_BUTTON)
669 {
670 if (Ansi)
671 {
672 if (GETPFNCLIENTW(Class->fnid) == NewWndProc)
673 chWndProc = GETPFNCLIENTA(Class->fnid);
674 }
675 else
676 {
677 if (GETPFNCLIENTA(Class->fnid) == NewWndProc)
678 chWndProc = GETPFNCLIENTW(Class->fnid);
679 }
680 }
681 // Now set the new window proc.
682 pWnd->lpfnWndProc = (chWndProc ? chWndProc : NewWndProc);
683 }
684 return Ret;
685 }
686
687 // Move this to user space!
688 BOOL FASTCALL
689 IntGetWindowInfo(PWINDOW_OBJECT Window, PWINDOWINFO pwi)
690 {
691 PWND Wnd = Window->Wnd;
692
693 pwi->cbSize = sizeof(WINDOWINFO);
694 pwi->rcWindow = Window->Wnd->rcWindow;
695 pwi->rcClient = Window->Wnd->rcClient;
696 pwi->dwStyle = Wnd->style;
697 pwi->dwExStyle = Wnd->ExStyle;
698 pwi->dwWindowStatus = (UserGetForegroundWindow() == Window->hSelf); /* WS_ACTIVECAPTION */
699 IntGetWindowBorderMeasures(Window, &pwi->cxWindowBorders, &pwi->cyWindowBorders);
700 pwi->atomWindowType = (Wnd->pcls ? Wnd->pcls->atomClassName : 0);
701 pwi->wCreatorVersion = 0x400; /* FIXME - return a real version number */
702 return TRUE;
703 }
704
705 static BOOL FASTCALL
706 IntSetMenu(
707 PWINDOW_OBJECT Window,
708 HMENU Menu,
709 BOOL *Changed)
710 {
711 PMENU_OBJECT OldMenu, NewMenu = NULL;
712 PWND Wnd = Window->Wnd;
713
714 if ((Wnd->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
715 {
716 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
717 return FALSE;
718 }
719
720 *Changed = (Wnd->IDMenu != (UINT) Menu);
721 if (! *Changed)
722 {
723 return TRUE;
724 }
725
726 if (Wnd->IDMenu)
727 {
728 OldMenu = IntGetMenuObject((HMENU) Wnd->IDMenu);
729 ASSERT(NULL == OldMenu || OldMenu->MenuInfo.Wnd == Window->hSelf);
730 }
731 else
732 {
733 OldMenu = NULL;
734 }
735
736 if (NULL != Menu)
737 {
738 NewMenu = IntGetMenuObject(Menu);
739 if (NULL == NewMenu)
740 {
741 if (NULL != OldMenu)
742 {
743 IntReleaseMenuObject(OldMenu);
744 }
745 SetLastWin32Error(ERROR_INVALID_MENU_HANDLE);
746 return FALSE;
747 }
748 if (NULL != NewMenu->MenuInfo.Wnd)
749 {
750 /* Can't use the same menu for two windows */
751 if (NULL != OldMenu)
752 {
753 IntReleaseMenuObject(OldMenu);
754 }
755 SetLastWin32Error(ERROR_INVALID_MENU_HANDLE);
756 return FALSE;
757 }
758
759 }
760
761 Wnd->IDMenu = (UINT) Menu;
762 if (NULL != NewMenu)
763 {
764 NewMenu->MenuInfo.Wnd = Window->hSelf;
765 IntReleaseMenuObject(NewMenu);
766 }
767 if (NULL != OldMenu)
768 {
769 OldMenu->MenuInfo.Wnd = NULL;
770 IntReleaseMenuObject(OldMenu);
771 }
772
773 return TRUE;
774 }
775
776
777 /* INTERNAL ******************************************************************/
778
779
780 VOID FASTCALL
781 co_DestroyThreadWindows(struct _ETHREAD *Thread)
782 {
783 PTHREADINFO WThread;
784 PLIST_ENTRY Current;
785 PWINDOW_OBJECT Wnd;
786 USER_REFERENCE_ENTRY Ref;
787 WThread = (PTHREADINFO)Thread->Tcb.Win32Thread;
788
789 while (!IsListEmpty(&WThread->WindowListHead))
790 {
791 Current = WThread->WindowListHead.Flink;
792 Wnd = CONTAINING_RECORD(Current, WINDOW_OBJECT, ThreadListEntry);
793
794 DPRINT("thread cleanup: while destroy wnds, wnd=0x%x\n",Wnd);
795
796 /* window removes itself from the list */
797
798 /*
799 fixme: it is critical that the window removes itself! if now, we will loop
800 here forever...
801 */
802
803 //ASSERT(co_UserDestroyWindow(Wnd));
804
805 UserRefObjectCo(Wnd, &Ref);//faxme: temp hack??
806 if (!co_UserDestroyWindow(Wnd))
807 {
808 DPRINT1("Unable to destroy window 0x%x at thread cleanup... This is _VERY_ bad!\n", Wnd);
809 }
810 UserDerefObjectCo(Wnd);//faxme: temp hack??
811 }
812 }
813
814
815
816 /*!
817 * Internal function.
818 * Returns client window rectangle relative to the upper-left corner of client area.
819 *
820 * \note Does not check the validity of the parameters
821 */
822 VOID FASTCALL
823 IntGetClientRect(PWINDOW_OBJECT Window, RECTL *Rect)
824 {
825 ASSERT( Window );
826 ASSERT( Rect );
827
828 Rect->left = Rect->top = 0;
829 Rect->right = Window->Wnd->rcClient.right - Window->Wnd->rcClient.left;
830 Rect->bottom = Window->Wnd->rcClient.bottom - Window->Wnd->rcClient.top;
831 }
832
833
834 #if 0
835 HWND FASTCALL
836 IntGetFocusWindow(VOID)
837 {
838 PUSER_MESSAGE_QUEUE Queue;
839 PDESKTOP pdo = IntGetActiveDesktop();
840
841 if( !pdo )
842 return NULL;
843
844 Queue = (PUSER_MESSAGE_QUEUE)pdo->ActiveMessageQueue;
845
846 if (Queue == NULL)
847 return(NULL);
848 else
849 return(Queue->FocusWindow);
850 }
851 #endif
852
853 PMENU_OBJECT FASTCALL
854 IntGetSystemMenu(PWINDOW_OBJECT Window, BOOL bRevert, BOOL RetMenu)
855 {
856 PMENU_OBJECT Menu, NewMenu = NULL, SysMenu = NULL, ret = NULL;
857 PTHREADINFO W32Thread;
858 HMENU hNewMenu, hSysMenu;
859 ROSMENUITEMINFO ItemInfo;
860
861 if(bRevert)
862 {
863 W32Thread = PsGetCurrentThreadWin32Thread();
864
865 if(!W32Thread->rpdesk)
866 return NULL;
867
868 if(Window->SystemMenu)
869 {
870 Menu = UserGetMenuObject(Window->SystemMenu);
871 if(Menu)
872 {
873 IntDestroyMenuObject(Menu, TRUE, TRUE);
874 Window->SystemMenu = (HMENU)0;
875 }
876 }
877
878 if(W32Thread->rpdesk->rpwinstaParent->SystemMenuTemplate)
879 {
880 /* clone system menu */
881 Menu = UserGetMenuObject(W32Thread->rpdesk->rpwinstaParent->SystemMenuTemplate);
882 if(!Menu)
883 return NULL;
884
885 NewMenu = IntCloneMenu(Menu);
886 if(NewMenu)
887 {
888 Window->SystemMenu = NewMenu->MenuInfo.Self;
889 NewMenu->MenuInfo.Flags |= MF_SYSMENU;
890 NewMenu->MenuInfo.Wnd = Window->hSelf;
891 ret = NewMenu;
892 //IntReleaseMenuObject(NewMenu);
893 }
894 }
895 else
896 {
897 hSysMenu = UserCreateMenu(FALSE);
898 if (NULL == hSysMenu)
899 {
900 return NULL;
901 }
902 SysMenu = IntGetMenuObject(hSysMenu);
903 if (NULL == SysMenu)
904 {
905 UserDestroyMenu(hSysMenu);
906 return NULL;
907 }
908 SysMenu->MenuInfo.Flags |= MF_SYSMENU;
909 SysMenu->MenuInfo.Wnd = Window->hSelf;
910 hNewMenu = co_IntLoadSysMenuTemplate();
911 if(!hNewMenu)
912 {
913 IntReleaseMenuObject(SysMenu);
914 UserDestroyMenu(hSysMenu);
915 return NULL;
916 }
917 Menu = IntGetMenuObject(hNewMenu);
918 if(!Menu)
919 {
920 IntReleaseMenuObject(SysMenu);
921 UserDestroyMenu(hSysMenu);
922 return NULL;
923 }
924
925 NewMenu = IntCloneMenu(Menu);
926 if(NewMenu)
927 {
928 NewMenu->MenuInfo.Flags |= MF_SYSMENU | MF_POPUP;
929 IntReleaseMenuObject(NewMenu);
930 UserSetMenuDefaultItem(NewMenu, SC_CLOSE, FALSE);
931
932 ItemInfo.cbSize = sizeof(MENUITEMINFOW);
933 ItemInfo.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_STATE | MIIM_SUBMENU;
934 ItemInfo.fType = MF_POPUP;
935 ItemInfo.fState = MFS_ENABLED;
936 ItemInfo.dwTypeData = NULL;
937 ItemInfo.cch = 0;
938 ItemInfo.hSubMenu = NewMenu->MenuInfo.Self;
939 IntInsertMenuItem(SysMenu, (UINT) -1, TRUE, &ItemInfo);
940
941 Window->SystemMenu = SysMenu->MenuInfo.Self;
942
943 ret = SysMenu;
944 }
945 IntDestroyMenuObject(Menu, FALSE, TRUE);
946 }
947 if(RetMenu)
948 return ret;
949 else
950 return NULL;
951 }
952 else
953 {
954 if(Window->SystemMenu)
955 return IntGetMenuObject((HMENU)Window->SystemMenu);
956 else
957 return NULL;
958 }
959 }
960
961
962 BOOL FASTCALL
963 IntIsChildWindow(PWINDOW_OBJECT Parent, PWINDOW_OBJECT BaseWindow)
964 {
965 PWINDOW_OBJECT Window;
966 PWND Wnd;
967
968 Window = BaseWindow;
969 while (Window)
970 {
971 Wnd = Window->Wnd;
972 if (Window == Parent)
973 {
974 return(TRUE);
975 }
976 if(!(Wnd->style & WS_CHILD))
977 {
978 break;
979 }
980
981 Window = Window->spwndParent;
982 }
983
984 return(FALSE);
985 }
986
987 BOOL FASTCALL
988 IntIsWindowVisible(PWINDOW_OBJECT BaseWindow)
989 {
990 PWINDOW_OBJECT Window;
991 PWND Wnd;
992
993 Window = BaseWindow;
994 while(Window)
995 {
996 Wnd = Window->Wnd;
997 if(!(Wnd->style & WS_CHILD))
998 {
999 break;
1000 }
1001 if(!(Wnd->style & WS_VISIBLE))
1002 {
1003 return FALSE;
1004 }
1005
1006 Window = Window->spwndParent;
1007 }
1008
1009 if(Window && Wnd->style & WS_VISIBLE)
1010 {
1011 return TRUE;
1012 }
1013
1014 return FALSE;
1015 }
1016
1017 VOID FASTCALL
1018 IntLinkWnd(
1019 PWND Wnd,
1020 PWND WndParent,
1021 PWND WndPrevSibling) /* set to NULL if top sibling */
1022 {
1023 Wnd->spwndParent = WndParent;
1024 if ((Wnd->spwndPrev = WndPrevSibling))
1025 {
1026 /* link after WndPrevSibling */
1027 if ((Wnd->spwndNext = WndPrevSibling->spwndNext))
1028 Wnd->spwndNext->spwndPrev = Wnd;
1029
1030 Wnd->spwndPrev->spwndNext = Wnd;
1031 }
1032 else
1033 {
1034 /* link at top */
1035 if ((Wnd->spwndNext = WndParent->spwndChild))
1036 Wnd->spwndNext->spwndPrev = Wnd;
1037
1038 WndParent->spwndChild = Wnd;
1039 }
1040
1041 }
1042
1043 /* link the window into siblings and parent. children are kept in place. */
1044 VOID FASTCALL
1045 IntLinkWindow(
1046 PWINDOW_OBJECT Wnd,
1047 PWINDOW_OBJECT WndParent,
1048 PWINDOW_OBJECT WndPrevSibling /* set to NULL if top sibling */
1049 )
1050 {
1051 PWINDOW_OBJECT Parent;
1052
1053 IntLinkWnd(Wnd->Wnd,
1054 WndParent->Wnd,
1055 WndPrevSibling ? WndPrevSibling->Wnd : NULL);
1056
1057 Wnd->spwndParent = WndParent;
1058 if ((Wnd->spwndPrev = WndPrevSibling))
1059 {
1060 /* link after WndPrevSibling */
1061 if ((Wnd->spwndNext = WndPrevSibling->spwndNext))
1062 Wnd->spwndNext->spwndPrev = Wnd;
1063 Wnd->spwndPrev->spwndNext = Wnd;
1064 }
1065 else
1066 {
1067 /* link at top */
1068 Parent = Wnd->spwndParent;
1069 if ((Wnd->spwndNext = WndParent->spwndChild))
1070 Wnd->spwndNext->spwndPrev = Wnd;
1071 else if (Parent)
1072 {
1073 Parent->spwndChild = Wnd;
1074 return;
1075 }
1076 if(Parent)
1077 {
1078 Parent->spwndChild = Wnd;
1079 }
1080 }
1081
1082 }
1083
1084 HWND FASTCALL
1085 IntSetOwner(HWND hWnd, HWND hWndNewOwner)
1086 {
1087 PWINDOW_OBJECT Wnd, WndOldOwner, WndNewOwner;
1088 HWND ret;
1089
1090 Wnd = IntGetWindowObject(hWnd);
1091 if(!Wnd)
1092 return NULL;
1093
1094 WndOldOwner = IntGetWindowObject(Wnd->hOwner);
1095 if (WndOldOwner)
1096 {
1097 ret = WndOldOwner->hSelf;
1098 UserDereferenceObject(WndOldOwner);
1099 }
1100 else
1101 {
1102 ret = 0;
1103 }
1104
1105 if((WndNewOwner = UserGetWindowObject(hWndNewOwner)))
1106 {
1107 Wnd->hOwner = hWndNewOwner;
1108 Wnd->Wnd->spwndOwner = WndNewOwner->Wnd;
1109 }
1110 else
1111 {
1112 Wnd->hOwner = NULL;
1113 Wnd->Wnd->spwndOwner = NULL;
1114 }
1115
1116 UserDereferenceObject(Wnd);
1117 return ret;
1118 }
1119
1120 PWINDOW_OBJECT FASTCALL
1121 co_IntSetParent(PWINDOW_OBJECT Wnd, PWINDOW_OBJECT WndNewParent)
1122 {
1123 PWINDOW_OBJECT WndOldParent, Sibling, InsertAfter;
1124 // HWND hWnd, hWndNewParent;
1125 BOOL WasVisible;
1126
1127 ASSERT(Wnd);
1128 ASSERT(WndNewParent);
1129 ASSERT_REFS_CO(Wnd);
1130 ASSERT_REFS_CO(WndNewParent);
1131
1132 // hWnd = Wnd->hSelf;
1133 // hWndNewParent = WndNewParent->hSelf;
1134
1135 /* Some applications try to set a child as a parent */
1136 if (IntIsChildWindow(Wnd, WndNewParent))
1137 {
1138 SetLastWin32Error( ERROR_INVALID_PARAMETER );
1139 return NULL;
1140 }
1141
1142 /*
1143 * Windows hides the window first, then shows it again
1144 * including the WM_SHOWWINDOW messages and all
1145 */
1146 WasVisible = co_WinPosShowWindow(Wnd, SW_HIDE);
1147
1148 // /* Validate that window and parent still exist */
1149 // if (!IntIsWindow(hWnd) || !IntIsWindow(hWndNewParent))
1150 // return NULL;
1151
1152 /* Window must belong to current process */
1153 if (Wnd->pti->pEThread->ThreadsProcess != PsGetCurrentProcess())
1154 return NULL;
1155
1156 WndOldParent = Wnd->spwndParent;
1157
1158 if (WndOldParent) UserReferenceObject(WndOldParent); /* caller must deref */
1159
1160 if (WndNewParent != WndOldParent)
1161 {
1162 IntUnlinkWindow(Wnd);
1163 InsertAfter = NULL;
1164 if (0 == (Wnd->Wnd->ExStyle & WS_EX_TOPMOST))
1165 {
1166 /* Not a TOPMOST window, put after TOPMOSTs of new parent */
1167 Sibling = WndNewParent->spwndChild;
1168 while (NULL != Sibling && 0 != (Sibling->Wnd->ExStyle & WS_EX_TOPMOST))
1169 {
1170 InsertAfter = Sibling;
1171 Sibling = Sibling->spwndNext;
1172 }
1173 }
1174 if (NULL == InsertAfter)
1175 {
1176 IntLinkWindow(Wnd, WndNewParent, InsertAfter /*prev sibling*/);
1177 }
1178 else
1179 {
1180 // UserReferenceObject(InsertAfter);
1181 IntLinkWindow(Wnd, WndNewParent, InsertAfter /*prev sibling*/);
1182 // UserDereferenceObject(InsertAfter);
1183 }
1184 }
1185
1186 /*
1187 * SetParent additionally needs to make hwnd the top window
1188 * in the z-order and send the expected WM_WINDOWPOSCHANGING and
1189 * WM_WINDOWPOSCHANGED notification messages.
1190 */
1191 co_WinPosSetWindowPos(Wnd, (0 == (Wnd->Wnd->ExStyle & WS_EX_TOPMOST) ? HWND_TOP : HWND_TOPMOST),
1192 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE
1193 | (WasVisible ? SWP_SHOWWINDOW : 0));
1194
1195 /*
1196 * FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
1197 * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE
1198 */
1199
1200 /*
1201 * Validate that the old parent still exist, since it migth have been
1202 * destroyed during the last callbacks to user-mode
1203 */
1204 // if(WndOldParent)
1205 // {
1206 // if(!IntIsWindow(WndOldParent->hSelf))
1207 // {
1208 // UserDereferenceObject(WndOldParent);
1209 // return NULL;
1210 // }
1211
1212 /* don't dereference the window object here, it must be done by the caller
1213 of IntSetParent() */
1214 // return WndOldParent;
1215 // }
1216
1217 return WndOldParent;//NULL;
1218 }
1219
1220 BOOL FASTCALL
1221 IntSetSystemMenu(PWINDOW_OBJECT Window, PMENU_OBJECT Menu)
1222 {
1223 PMENU_OBJECT OldMenu;
1224 if(Window->SystemMenu)
1225 {
1226 OldMenu = IntGetMenuObject(Window->SystemMenu);
1227 if(OldMenu)
1228 {
1229 OldMenu->MenuInfo.Flags &= ~ MF_SYSMENU;
1230 IntReleaseMenuObject(OldMenu);
1231 }
1232 }
1233
1234 if(Menu)
1235 {
1236 /* FIXME check window style, propably return FALSE ? */
1237 Window->SystemMenu = Menu->MenuInfo.Self;
1238 Menu->MenuInfo.Flags |= MF_SYSMENU;
1239 }
1240 else
1241 Window->SystemMenu = (HMENU)0;
1242
1243 return TRUE;
1244 }
1245
1246 /* unlink the window from siblings and parent. children are kept in place. */
1247 VOID FASTCALL
1248 IntUnlinkWnd(PWND Wnd)
1249 {
1250 if (Wnd->spwndNext)
1251 Wnd->spwndNext->spwndPrev = Wnd->spwndPrev;
1252
1253 if (Wnd->spwndPrev)
1254 Wnd->spwndPrev->spwndNext = Wnd->spwndNext;
1255
1256 if (Wnd->spwndParent && Wnd->spwndParent->spwndChild == Wnd)
1257 Wnd->spwndParent->spwndChild = Wnd->spwndNext;
1258
1259 Wnd->spwndPrev = Wnd->spwndNext = Wnd->spwndParent = NULL;
1260 }
1261
1262
1263 /* unlink the window from siblings and parent. children are kept in place. */
1264 VOID FASTCALL
1265 IntUnlinkWindow(PWINDOW_OBJECT Wnd)
1266 {
1267 PWINDOW_OBJECT WndParent = Wnd->spwndParent;
1268
1269 IntUnlinkWnd(Wnd->Wnd);
1270
1271 if (Wnd->spwndNext)
1272 Wnd->spwndNext->spwndPrev = Wnd->spwndPrev;
1273
1274 if (Wnd->spwndPrev)
1275 Wnd->spwndPrev->spwndNext = Wnd->spwndNext;
1276 else if (WndParent && WndParent->spwndChild == Wnd)
1277 WndParent->spwndChild = Wnd->spwndNext;
1278
1279 Wnd->spwndPrev = Wnd->spwndNext = Wnd->spwndParent = NULL;
1280 }
1281
1282 BOOL FASTCALL
1283 IntAnyPopup(VOID)
1284 {
1285 PWINDOW_OBJECT Window, Child;
1286
1287 if(!(Window = UserGetWindowObject(IntGetDesktopWindow())))
1288 {
1289 return FALSE;
1290 }
1291
1292 for(Child = Window->spwndChild; Child; Child = Child->spwndNext)
1293 {
1294 if(Child->hOwner && Child->Wnd->style & WS_VISIBLE)
1295 {
1296 /*
1297 * The desktop has a popup window if one of them has
1298 * an owner window and is visible
1299 */
1300 return TRUE;
1301 }
1302 }
1303
1304 return FALSE;
1305 }
1306
1307 BOOL FASTCALL
1308 IntIsWindowInDestroy(PWINDOW_OBJECT Window)
1309 {
1310 return ((Window->state & WINDOWSTATUS_DESTROYING) == WINDOWSTATUS_DESTROYING);
1311 }
1312
1313
1314 BOOL
1315 FASTCALL
1316 IntGetWindowPlacement(PWINDOW_OBJECT Window, WINDOWPLACEMENT *lpwndpl)
1317 {
1318 PWND Wnd;
1319 POINT Size;
1320
1321 Wnd = Window->Wnd;
1322 if (!Wnd) return FALSE;
1323
1324 if(lpwndpl->length != sizeof(WINDOWPLACEMENT))
1325 {
1326 return FALSE;
1327 }
1328
1329 lpwndpl->flags = 0;
1330 if (0 == (Wnd->style & WS_VISIBLE))
1331 {
1332 lpwndpl->showCmd = SW_HIDE;
1333 }
1334 else if (0 != (Window->state & WINDOWOBJECT_RESTOREMAX) ||
1335 0 != (Wnd->style & WS_MAXIMIZE))
1336 {
1337 lpwndpl->showCmd = SW_MAXIMIZE;
1338 }
1339 else if (0 != (Wnd->style & WS_MINIMIZE))
1340 {
1341 lpwndpl->showCmd = SW_MINIMIZE;
1342 }
1343 else if (0 != (Wnd->style & WS_VISIBLE))
1344 {
1345 lpwndpl->showCmd = SW_SHOWNORMAL;
1346 }
1347
1348 Size.x = Wnd->rcWindow.left;
1349 Size.y = Wnd->rcWindow.top;
1350 WinPosInitInternalPos(Window, &Size,
1351 &Wnd->rcWindow);
1352
1353 lpwndpl->rcNormalPosition = Wnd->InternalPos.NormalRect;
1354 lpwndpl->ptMinPosition = Wnd->InternalPos.IconPos;
1355 lpwndpl->ptMaxPosition = Wnd->InternalPos.MaxPos;
1356
1357 return TRUE;
1358 }
1359
1360
1361 /* FUNCTIONS *****************************************************************/
1362
1363 /*
1364 * @unimplemented
1365 */
1366 DWORD APIENTRY
1367 NtUserAlterWindowStyle(DWORD Unknown0,
1368 DWORD Unknown1,
1369 DWORD Unknown2)
1370 {
1371 UNIMPLEMENTED
1372
1373 return(0);
1374 }
1375
1376 /*
1377 * As best as I can figure, this function is used by EnumWindows,
1378 * EnumChildWindows, EnumDesktopWindows, & EnumThreadWindows.
1379 *
1380 * It's supposed to build a list of HWNDs to return to the caller.
1381 * We can figure out what kind of list by what parameters are
1382 * passed to us.
1383 */
1384 /*
1385 * @implemented
1386 */
1387 NTSTATUS
1388 APIENTRY
1389 NtUserBuildHwndList(
1390 HDESK hDesktop,
1391 HWND hwndParent,
1392 BOOLEAN bChildren,
1393 ULONG dwThreadId,
1394 ULONG lParam,
1395 HWND* pWnd,
1396 ULONG* pBufSize)
1397 {
1398 NTSTATUS Status;
1399 ULONG dwCount = 0;
1400
1401 if (pBufSize == 0)
1402 return ERROR_INVALID_PARAMETER;
1403
1404 if (hwndParent || !dwThreadId)
1405 {
1406 PDESKTOP Desktop;
1407 PWINDOW_OBJECT Parent, Window;
1408
1409 if(!hwndParent)
1410 {
1411 if(hDesktop == NULL && !(Desktop = IntGetActiveDesktop()))
1412 {
1413 return ERROR_INVALID_HANDLE;
1414 }
1415
1416 if(hDesktop)
1417 {
1418 Status = IntValidateDesktopHandle(hDesktop,
1419 UserMode,
1420 0,
1421 &Desktop);
1422 if(!NT_SUCCESS(Status))
1423 {
1424 return ERROR_INVALID_HANDLE;
1425 }
1426 }
1427 hwndParent = Desktop->DesktopWindow;
1428 }
1429 else
1430 {
1431 hDesktop = 0;
1432 }
1433
1434 if((Parent = UserGetWindowObject(hwndParent)) &&
1435 (Window = Parent->spwndChild))
1436 {
1437 BOOL bGoDown = TRUE;
1438
1439 Status = STATUS_SUCCESS;
1440 while(TRUE)
1441 {
1442 if (bGoDown)
1443 {
1444 if(dwCount++ < *pBufSize && pWnd)
1445 {
1446 _SEH2_TRY
1447 {
1448 ProbeForWrite(pWnd, sizeof(HWND), 1);
1449 *pWnd = Window->hSelf;
1450 pWnd++;
1451 }
1452 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1453 {
1454 Status = _SEH2_GetExceptionCode();
1455 }
1456 _SEH2_END
1457 if(!NT_SUCCESS(Status))
1458 {
1459 SetLastNtError(Status);
1460 break;
1461 }
1462 }
1463 if (Window->spwndChild && bChildren)
1464 {
1465 Window = Window->spwndChild;
1466 continue;
1467 }
1468 bGoDown = FALSE;
1469 }
1470 if (Window->spwndNext)
1471 {
1472 Window = Window->spwndNext;
1473 bGoDown = TRUE;
1474 continue;
1475 }
1476 Window = Window->spwndParent;
1477 if (Window == Parent)
1478 {
1479 break;
1480 }
1481 }
1482 }
1483
1484 if(hDesktop)
1485 {
1486 ObDereferenceObject(Desktop);
1487 }
1488 }
1489 else
1490 {
1491 PETHREAD Thread;
1492 PTHREADINFO W32Thread;
1493 PLIST_ENTRY Current;
1494 PWINDOW_OBJECT Window;
1495
1496 Status = PsLookupThreadByThreadId((HANDLE)dwThreadId, &Thread);
1497 if(!NT_SUCCESS(Status))
1498 {
1499 return ERROR_INVALID_PARAMETER;
1500 }
1501 if(!(W32Thread = (PTHREADINFO)Thread->Tcb.Win32Thread))
1502 {
1503 ObDereferenceObject(Thread);
1504 DPRINT("Thread is not a GUI Thread!\n");
1505 return ERROR_INVALID_PARAMETER;
1506 }
1507
1508 Current = W32Thread->WindowListHead.Flink;
1509 while(Current != &(W32Thread->WindowListHead))
1510 {
1511 Window = CONTAINING_RECORD(Current, WINDOW_OBJECT, ThreadListEntry);
1512 ASSERT(Window);
1513
1514 if(bChildren || Window->hOwner != NULL)
1515 {
1516 if(dwCount < *pBufSize && pWnd)
1517 {
1518 Status = MmCopyToCaller(pWnd++, &Window->hSelf, sizeof(HWND));
1519 if(!NT_SUCCESS(Status))
1520 {
1521 SetLastNtError(Status);
1522 break;
1523 }
1524 }
1525 dwCount++;
1526 }
1527 Current = Current->Flink;
1528 }
1529
1530 ObDereferenceObject(Thread);
1531 }
1532
1533 *pBufSize = dwCount;
1534 return STATUS_SUCCESS;
1535 }
1536
1537
1538 /*
1539 * @implemented
1540 */
1541 HWND APIENTRY
1542 NtUserChildWindowFromPointEx(HWND hwndParent,
1543 LONG x,
1544 LONG y,
1545 UINT uiFlags)
1546 {
1547 PWINDOW_OBJECT Parent;
1548 POINTL Pt;
1549 HWND Ret;
1550 HWND *List, *phWnd;
1551
1552 if(!(Parent = UserGetWindowObject(hwndParent)))
1553 {
1554 return NULL;
1555 }
1556
1557 Pt.x = x;
1558 Pt.y = y;
1559
1560 if(Parent->hSelf != IntGetDesktopWindow())
1561 {
1562 Pt.x += Parent->Wnd->rcClient.left;
1563 Pt.y += Parent->Wnd->rcClient.top;
1564 }
1565
1566 if(!IntPtInWindow(Parent, Pt.x, Pt.y))
1567 {
1568 return NULL;
1569 }
1570
1571 Ret = Parent->hSelf;
1572 if((List = IntWinListChildren(Parent)))
1573 {
1574 for(phWnd = List; *phWnd; phWnd++)
1575 {
1576 PWINDOW_OBJECT Child;
1577 PWND ChildWnd;
1578 if((Child = UserGetWindowObject(*phWnd)))
1579 {
1580 ChildWnd = Child->Wnd;
1581 if(!(ChildWnd->style & WS_VISIBLE) && (uiFlags & CWP_SKIPINVISIBLE))
1582 {
1583 continue;
1584 }
1585 if((ChildWnd->style & WS_DISABLED) && (uiFlags & CWP_SKIPDISABLED))
1586 {
1587 continue;
1588 }
1589 if((ChildWnd->ExStyle & WS_EX_TRANSPARENT) && (uiFlags & CWP_SKIPTRANSPARENT))
1590 {
1591 continue;
1592 }
1593 if(IntPtInWindow(Child, Pt.x, Pt.y))
1594 {
1595 Ret = Child->hSelf;
1596 break;
1597 }
1598 }
1599 }
1600 ExFreePool(List);
1601 }
1602
1603 return Ret;
1604 }
1605
1606 void FASTCALL
1607 IntFixWindowCoordinates(CREATESTRUCTW* Cs, PWINDOW_OBJECT ParentWindow, DWORD* dwShowMode)
1608 {
1609 #define IS_DEFAULT(x) ((x) == CW_USEDEFAULT || (x) == (SHORT)0x8000)
1610
1611 /* default positioning for overlapped windows */
1612 if(!(Cs->style & (WS_POPUP | WS_CHILD)))
1613 {
1614 RECTL rc, WorkArea;
1615 PRTL_USER_PROCESS_PARAMETERS ProcessParams;
1616
1617 UserSystemParametersInfo(SPI_GETWORKAREA, 0, &WorkArea, 0);
1618
1619 rc = WorkArea;
1620 ProcessParams = PsGetCurrentProcess()->Peb->ProcessParameters;
1621
1622 if (IS_DEFAULT(Cs->x))
1623 {
1624 if (!IS_DEFAULT(Cs->y)) *dwShowMode = Cs->y;
1625
1626 if(ProcessParams->WindowFlags & STARTF_USEPOSITION)
1627 {
1628 Cs->x = ProcessParams->StartingX;
1629 Cs->y = ProcessParams->StartingY;
1630 }
1631 else
1632 {
1633 Cs->x = WorkArea.left;
1634 Cs->y = WorkArea.top;
1635 }
1636 }
1637
1638 if (IS_DEFAULT(Cs->cx))
1639 {
1640 if (ProcessParams->WindowFlags & STARTF_USEPOSITION)
1641 {
1642 Cs->cx = ProcessParams->CountX;
1643 Cs->cy = ProcessParams->CountY;
1644 }
1645 else
1646 {
1647 Cs->cx = (WorkArea.right - WorkArea.left) * 3 / 4 - Cs->x;
1648 Cs->cy = (WorkArea.bottom - WorkArea.top) * 3 / 4 - Cs->y;
1649 }
1650 }
1651 /* neither x nor cx are default. Check the y values .
1652 * In the trace we see Outlook and Outlook Express using
1653 * cy set to CW_USEDEFAULT when opening the address book.
1654 */
1655 else if (IS_DEFAULT(Cs->cy))
1656 {
1657 DPRINT("Strange use of CW_USEDEFAULT in nHeight\n");
1658 Cs->cy = (WorkArea.bottom - WorkArea.top) * 3 / 4 - Cs->y;
1659 }
1660 }
1661 else
1662 {
1663 /* if CW_USEDEFAULT is set for non-overlapped windows, both values are set to zero */
1664 if(IS_DEFAULT(Cs->x))
1665 {
1666 Cs->x = 0;
1667 Cs->y = 0;
1668 }
1669 if(IS_DEFAULT(Cs->cx))
1670 {
1671 Cs->cx = 0;
1672 Cs->cy = 0;
1673 }
1674 }
1675
1676 #undef IS_DEFAULT
1677 }
1678
1679 /* Allocates and initializes a window*/
1680 PWINDOW_OBJECT FASTCALL IntCreateWindow(CREATESTRUCTW* Cs,
1681 PLARGE_STRING WindowName,
1682 PCLS Class,
1683 PWINDOW_OBJECT ParentWindow,
1684 PWINDOW_OBJECT OwnerWindow)
1685 {
1686 PWND Wnd = NULL;
1687 PWINDOW_OBJECT Window;
1688 HWND hWnd;
1689 PTHREADINFO pti = NULL;
1690 PMENU_OBJECT SystemMenu;
1691 BOOL MenuChanged;
1692 BOOL bUnicodeWindow;
1693
1694 pti = PsGetCurrentThreadWin32Thread();
1695
1696 /* Automatically add WS_EX_WINDOWEDGE */
1697 if ((Cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
1698 ((!(Cs->dwExStyle & WS_EX_STATICEDGE)) &&
1699 (Cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
1700 Cs->dwExStyle |= WS_EX_WINDOWEDGE;
1701 else
1702 Cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
1703
1704 /* Is it a unicode window? */
1705 bUnicodeWindow =!(Cs->dwExStyle & WS_EX_SETANSICREATOR);
1706 Cs->dwExStyle &= ~WS_EX_SETANSICREATOR;
1707
1708 /* Allocate the new window */
1709 Window = (PWINDOW_OBJECT) UserCreateObject( gHandleTable,
1710 pti->rpdesk,
1711 (PHANDLE)&hWnd,
1712 otWindow,
1713 sizeof(WINDOW_OBJECT));
1714
1715 Wnd = DesktopHeapAlloc(pti->rpdesk, sizeof(WND) + Class->cbwndExtra);
1716
1717 if(!Window || !Wnd)
1718 {
1719 goto AllocError;
1720 }
1721
1722 RtlZeroMemory(Wnd, sizeof(WND) + Class->cbwndExtra);
1723
1724 DPRINT("Created object with handle %X\n", hWnd);
1725
1726 if (NULL == pti->rpdesk->DesktopWindow)
1727 {
1728 /* If there is no desktop window yet, we must be creating it */
1729 pti->rpdesk->DesktopWindow = hWnd;
1730 pti->rpdesk->pDeskInfo->spwnd = Wnd;
1731 }
1732
1733 /*
1734 * Fill out the structure describing it.
1735 */
1736 Window->Wnd = Wnd;
1737 Window->pti = pti;
1738 Window->hSelf = hWnd;
1739 Window->spwndParent = ParentWindow;
1740 Window->hOwner = OwnerWindow ? OwnerWindow->hSelf : NULL;
1741
1742 Wnd->head.h = hWnd;
1743 Wnd->head.pti = pti;
1744 Wnd->head.rpdesk = pti->rpdesk;
1745 Wnd->fnid = 0;
1746 Wnd->hWndLastActive = hWnd;
1747 Wnd->state2 |= WNDS2_WIN40COMPAT;
1748 Wnd->pcls = Class;
1749 Wnd->hModule = Cs->hInstance;
1750 Wnd->style = Cs->style & ~WS_VISIBLE;
1751 Wnd->ExStyle = Cs->dwExStyle;
1752 Wnd->rcWindow.left = Cs->x;
1753 Wnd->rcWindow.top = Cs->y;
1754 Wnd->rcWindow.right = Cs->x + Cs->cx;
1755 Wnd->rcWindow.bottom = Cs->y + Cs->cy;
1756 Wnd->cbwndExtra = Wnd->pcls->cbwndExtra;
1757 Wnd->spwndOwner = OwnerWindow ? OwnerWindow->Wnd : NULL;
1758 Wnd->spwndParent = ParentWindow ? ParentWindow->Wnd : NULL;
1759
1760 if (Wnd->style & WS_CHILD && ParentWindow)
1761 {
1762 RECTL_vOffsetRect(&(Wnd->rcWindow), ParentWindow->Wnd->rcClient.left,
1763 ParentWindow->Wnd->rcClient.top);
1764 }
1765 Wnd->rcClient = Wnd->rcWindow;
1766
1767 IntReferenceMessageQueue(Window->pti->MessageQueue);
1768 if (Wnd->spwndParent != NULL && Cs->hwndParent != 0)
1769 {
1770 Wnd->HideFocus = Wnd->spwndParent->HideFocus;
1771 Wnd->HideAccel = Wnd->spwndParent->HideAccel;
1772 }
1773
1774 if (Wnd->pcls->CSF_flags & CSF_SERVERSIDEPROC)
1775 Wnd->state |= WNDS_SERVERSIDEWINDOWPROC;
1776
1777 /* BugBoy Comments: Comment below say that System classes are always created
1778 as UNICODE. In windows, creating a window with the ANSI version of CreateWindow
1779 sets the window to ansi as verified by testing with IsUnicodeWindow API.
1780
1781 No where can I see in code or through testing does the window change back
1782 to ANSI after being created as UNICODE in ROS. I didnt do more testing to
1783 see what problems this would cause.*/
1784
1785 // Set WndProc from Class.
1786 Wnd->lpfnWndProc = Wnd->pcls->lpfnWndProc;
1787
1788 // GetWindowProc, test for non server side default classes and set WndProc.
1789 if ( Wnd->pcls->fnid <= FNID_GHOST && Wnd->pcls->fnid >= FNID_BUTTON )
1790 {
1791 if (bUnicodeWindow)
1792 {
1793 if (GETPFNCLIENTA(Wnd->pcls->fnid) == Wnd->lpfnWndProc)
1794 Wnd->lpfnWndProc = GETPFNCLIENTW(Wnd->pcls->fnid);
1795 }
1796 else
1797 {
1798 if (GETPFNCLIENTW(Wnd->pcls->fnid) == Wnd->lpfnWndProc)
1799 Wnd->lpfnWndProc = GETPFNCLIENTA(Wnd->pcls->fnid);
1800 }
1801 }
1802
1803 // If not an Unicode caller, set Ansi creator bit.
1804 if (!bUnicodeWindow) Wnd->state |= WNDS_ANSICREATOR;
1805
1806 // Clone Class Ansi/Unicode proc type.
1807 if (Wnd->pcls->CSF_flags & CSF_ANSIPROC)
1808 {
1809 Wnd->state |= WNDS_ANSIWINDOWPROC;
1810 Wnd->Unicode = FALSE;
1811 }
1812 else
1813 { /*
1814 It seems there can be both an Ansi creator and Unicode Class Window
1815 WndProc, unless the following overriding conditions occur:
1816 */
1817 if ( !bUnicodeWindow &&
1818 ( Class->atomClassName == gpsi->atomSysClass[ICLS_BUTTON] ||
1819 Class->atomClassName == gpsi->atomSysClass[ICLS_COMBOBOX] ||
1820 Class->atomClassName == gpsi->atomSysClass[ICLS_COMBOLBOX] ||
1821 Class->atomClassName == gpsi->atomSysClass[ICLS_DIALOG] ||
1822 Class->atomClassName == gpsi->atomSysClass[ICLS_EDIT] ||
1823 Class->atomClassName == gpsi->atomSysClass[ICLS_IME] ||
1824 Class->atomClassName == gpsi->atomSysClass[ICLS_LISTBOX] ||
1825 Class->atomClassName == gpsi->atomSysClass[ICLS_MDICLIENT] ||
1826 Class->atomClassName == gpsi->atomSysClass[ICLS_STATIC] ) )
1827 { // Override Class and set the window Ansi WndProc.
1828 Wnd->state |= WNDS_ANSIWINDOWPROC;
1829 Wnd->Unicode = FALSE;
1830 }
1831 else
1832 { // Set the window Unicode WndProc.
1833 Wnd->state &= ~WNDS_ANSIWINDOWPROC;
1834 Wnd->Unicode = TRUE;
1835 }
1836 }
1837
1838 /* BugBoy Comments: if the window being created is a edit control, ATOM 0xCxxx,
1839 then my testing shows that windows (2k and XP) creates a CallProc for it immediately
1840 Dont understand why it does this. */
1841 if (Class->atomClassName == gpsi->atomSysClass[ICLS_EDIT])
1842 {
1843 PCALLPROCDATA CallProc;
1844 //CallProc = CreateCallProc(NULL, Wnd->lpfnWndProc, bUnicodeWindow, Wnd->ti->ppi);
1845 CallProc = CreateCallProc(NULL, Wnd->lpfnWndProc, Wnd->Unicode , Wnd->head.pti->ppi);
1846
1847 if (!CallProc)
1848 {
1849 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
1850 DPRINT1("Warning: Unable to create CallProc for edit control. Control may not operate correctly! hwnd %x\n",hWnd);
1851 }
1852 else
1853 {
1854 UserAddCallProcToClass(Wnd->pcls, CallProc);
1855 }
1856 }
1857
1858 InitializeListHead(&Wnd->PropListHead);
1859
1860 if ( WindowName->Buffer != NULL && WindowName->Length > 0 )
1861 {
1862 Wnd->strName.Buffer = DesktopHeapAlloc(Wnd->head.rpdesk,
1863 WindowName->Length + sizeof(UNICODE_NULL));
1864 if (Wnd->strName.Buffer == NULL)
1865 {
1866 goto AllocError;
1867 }
1868
1869 RtlCopyMemory(Wnd->strName.Buffer, WindowName->Buffer, WindowName->Length);
1870 Wnd->strName.Buffer[WindowName->Length / sizeof(WCHAR)] = L'\0';
1871 Wnd->strName.Length = WindowName->Length;
1872 }
1873
1874 /* Correct the window style. */
1875 if ((Wnd->style & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1876 {
1877 Wnd->style |= WS_CLIPSIBLINGS;
1878 if (!(Wnd->style & WS_POPUP))
1879 {
1880 Wnd->style |= WS_CAPTION;
1881 Window->state |= WINDOWOBJECT_NEED_SIZE;
1882 }
1883 }
1884
1885 if ((Wnd->ExStyle & WS_EX_DLGMODALFRAME) ||
1886 (Wnd->style & (WS_DLGFRAME | WS_THICKFRAME)))
1887 Wnd->ExStyle |= WS_EX_WINDOWEDGE;
1888 else
1889 Wnd->ExStyle &= ~WS_EX_WINDOWEDGE;
1890
1891 /* create system menu */
1892 if((Cs->style & WS_SYSMENU) )//&& (dwStyle & WS_CAPTION) == WS_CAPTION)
1893 {
1894 SystemMenu = IntGetSystemMenu(Window, TRUE, TRUE);
1895 if(SystemMenu)
1896 {
1897 Window->SystemMenu = SystemMenu->MenuInfo.Self;
1898 IntReleaseMenuObject(SystemMenu);
1899 }
1900 }
1901
1902 /* Set the window menu */
1903 if ((Cs->style & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1904 {
1905 if (Cs->hMenu)
1906 IntSetMenu(Window, Cs->hMenu, &MenuChanged);
1907 else if (Wnd->pcls->lpszMenuName) // Take it from the parent.
1908 {
1909 UNICODE_STRING MenuName;
1910 HMENU hMenu;
1911
1912 if (IS_INTRESOURCE(Wnd->pcls->lpszMenuName))
1913 {
1914 MenuName.Length = 0;
1915 MenuName.MaximumLength = 0;
1916 MenuName.Buffer = Wnd->pcls->lpszMenuName;
1917 }
1918 else
1919 {
1920 RtlInitUnicodeString( &MenuName, Wnd->pcls->lpszMenuName);
1921 }
1922 hMenu = co_IntCallLoadMenu( Wnd->pcls->hModule, &MenuName);
1923 if (hMenu) IntSetMenu(Window, hMenu, &MenuChanged);
1924 }
1925 }
1926 else // Not a child
1927 Wnd->IDMenu = (UINT) Cs->hMenu;
1928
1929 /* Insert the window into the thread's window list. */
1930 InsertTailList (&pti->WindowListHead, &Window->ThreadListEntry);
1931
1932 /* Handle "CS_CLASSDC", it is tested first. */
1933 if ( (Wnd->pcls->style & CS_CLASSDC) && !(Wnd->pcls->pdce) )
1934 { /* One DCE per class to have CLASS. */
1935 Wnd->pcls->pdce = DceAllocDCE( Window, DCE_CLASS_DC );
1936 }
1937 else if ( Wnd->pcls->style & CS_OWNDC)
1938 { /* Allocate a DCE for this window. */
1939 DceAllocDCE(Window, DCE_WINDOW_DC);
1940 }
1941
1942 return Window;
1943
1944 AllocError:
1945
1946 if(Window)
1947 UserDereferenceObject(Window);
1948
1949 if(Wnd)
1950 DesktopHeapFree(Wnd->head.rpdesk, Wnd);
1951
1952 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
1953 return NULL;
1954 }
1955
1956 /*
1957 * @implemented
1958 */
1959 PWND FASTCALL
1960 co_UserCreateWindowEx(CREATESTRUCTW* Cs,
1961 PUNICODE_STRING ClassName,
1962 PLARGE_STRING WindowName)
1963 {
1964 PWINDOW_OBJECT Window = NULL, ParentWindow = NULL, OwnerWindow;
1965 HWND hWnd, hWndParent, hWndOwner;
1966 DWORD dwStyle;
1967 PWINSTATION_OBJECT WinSta;
1968 PWND Wnd = NULL;
1969 PCLS Class = NULL;
1970 SIZE Size;
1971 POINT MaxPos;
1972 CBT_CREATEWNDW CbtCreate;
1973 LRESULT Result;
1974 USER_REFERENCE_ENTRY ParentRef, Ref;
1975 PTHREADINFO pti;
1976 DWORD dwShowMode = SW_SHOW;
1977 DECLARE_RETURN(PWND);
1978
1979 /* Get the current window station and reference it */
1980 pti = GetW32ThreadInfo();
1981 if (pti == NULL || pti->rpdesk == NULL)
1982 {
1983 DPRINT1("Thread is not attached to a desktop! Cannot create window!\n");
1984 return NULL; //There is nothing to cleanup
1985 }
1986 WinSta = pti->rpdesk->rpwinstaParent;
1987 ObReferenceObjectByPointer(WinSta, KernelMode, ExWindowStationObjectType, 0);
1988
1989 /* Get the class and reference it*/
1990 Class = IntGetAndReferenceClass(ClassName, Cs->hInstance);
1991 if(!Class)
1992 {
1993 DPRINT1("Failed to find class %wZ\n", ClassName);
1994 RETURN(NULL);
1995 }
1996
1997 /* Now find the parent and the owner window */
1998 hWndParent = IntGetDesktopWindow();
1999 hWndOwner = NULL;
2000
2001 if (Cs->hwndParent == HWND_MESSAGE)
2002 {
2003 Cs->hwndParent = hWndParent = IntGetMessageWindow();
2004 }
2005 else if (Cs->hwndParent)
2006 {
2007 if ((Cs->style & (WS_CHILD|WS_POPUP)) != WS_CHILD)
2008 hWndOwner = Cs->hwndParent;
2009 else
2010 hWndParent = Cs->hwndParent;
2011 }
2012 else if ((Cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
2013 {
2014 DPRINT1("Cannot create a child window without a parrent!\n");
2015 SetLastWin32Error(ERROR_TLW_WITH_WSCHILD);
2016 RETURN(NULL); /* WS_CHILD needs a parent, but WS_POPUP doesn't */
2017 }
2018
2019 ParentWindow = hWndParent ? UserGetWindowObject(hWndParent): NULL;
2020 OwnerWindow = hWndOwner ? UserGetWindowObject(hWndOwner): NULL;
2021
2022 /* FIXME: is this correct?*/
2023 if(OwnerWindow)
2024 OwnerWindow = UserGetAncestor(OwnerWindow, GA_ROOT);
2025
2026 /* Fix the position and the size of the window */
2027 if (ParentWindow)
2028 {
2029 UserRefObjectCo(ParentWindow, &ParentRef);
2030 IntFixWindowCoordinates(Cs, ParentWindow, &dwShowMode);
2031 }
2032
2033 /* Allocate and initialize the new window */
2034 Window = IntCreateWindow(Cs,
2035 WindowName,
2036 Class,
2037 ParentWindow,
2038 OwnerWindow);
2039 if(!Window)
2040 {
2041 DPRINT1("IntCreateWindow failed!\n");
2042 RETURN(0);
2043 }
2044
2045 Wnd = Window->Wnd;
2046 hWnd = Window->hSelf;
2047
2048 UserRefObjectCo(Window, &Ref);
2049 ObDereferenceObject(WinSta);
2050
2051 /* Call the WH_CBT hook */
2052 dwStyle = Cs->style;
2053 Cs->style = Wnd->style; /* HCBT_CREATEWND needs the real window style */
2054 CbtCreate.lpcs = Cs;
2055 CbtCreate.hwndInsertAfter = HWND_TOP;
2056 if (ISITHOOKED(WH_CBT))
2057 {
2058 if (co_HOOK_CallHooks(WH_CBT, HCBT_CREATEWND, (WPARAM) hWnd, (LPARAM) &CbtCreate))
2059 {
2060 DPRINT1("HCBT_CREATEWND hook failed!\n");
2061 RETURN( (PWND) NULL);
2062 }
2063 }
2064 Cs->style = dwStyle; /* NCCREATE and WM_NCCALCSIZE need the original values*/
2065
2066 /* Send the WM_GETMINMAXINFO message*/
2067 Size.cx = Cs->cx;
2068 Size.cy = Cs->cy;
2069
2070 if ((dwStyle & WS_THICKFRAME) || !(dwStyle & (WS_POPUP | WS_CHILD)))
2071 {
2072 POINT MaxSize, MaxPos, MinTrack, MaxTrack;
2073
2074 co_WinPosGetMinMaxInfo(Window, &MaxSize, &MaxPos, &MinTrack, &MaxTrack);
2075 if (Size.cx > MaxTrack.x) Size.cx = MaxTrack.x;
2076 if (Size.cy > MaxTrack.y) Size.cy = MaxTrack.y;
2077 if (Size.cx < MinTrack.x) Size.cx = MinTrack.x;
2078 if (Size.cy < MinTrack.y) Size.cy = MinTrack.y;
2079 }
2080
2081 Wnd->rcWindow.left = Cs->x;
2082 Wnd->rcWindow.top = Cs->y;
2083 Wnd->rcWindow.right = Cs->x + Size.cx;
2084 Wnd->rcWindow.bottom = Cs->y + Size.cy;
2085 if (0 != (Wnd->style & WS_CHILD) && ParentWindow)
2086 {
2087 RECTL_vOffsetRect(&Wnd->rcWindow,
2088 ParentWindow->Wnd->rcClient.left,
2089 ParentWindow->Wnd->rcClient.top);
2090 }
2091 Wnd->rcClient = Wnd->rcWindow;
2092
2093
2094 /* Link the window*/
2095 if (NULL != ParentWindow)
2096 {
2097 /* link the window into the parent's child list */
2098 if ((dwStyle & (WS_CHILD|WS_MAXIMIZE)) == WS_CHILD)
2099 {
2100 PWINDOW_OBJECT PrevSibling;
2101
2102 PrevSibling = ParentWindow->spwndChild;
2103
2104 if(PrevSibling)
2105 {
2106 while (PrevSibling->spwndNext)
2107 PrevSibling = PrevSibling->spwndNext;
2108 }
2109
2110 /* link window as bottom sibling */
2111 IntLinkWindow(Window, ParentWindow, PrevSibling /*prev sibling*/);
2112 }
2113 else
2114 {
2115 /* link window as top sibling (but after topmost siblings) */
2116 PWINDOW_OBJECT InsertAfter, Sibling;
2117 if (!(Cs->dwExStyle & WS_EX_TOPMOST))
2118 {
2119 InsertAfter = NULL;
2120 Sibling = ParentWindow->spwndChild;
2121 while (Sibling && (Sibling->Wnd->ExStyle & WS_EX_TOPMOST))
2122 {
2123 InsertAfter = Sibling;
2124 Sibling = Sibling->spwndNext;
2125 }
2126 }
2127 else
2128 {
2129 InsertAfter = NULL;
2130 }
2131
2132 IntLinkWindow(Window, ParentWindow, InsertAfter /* prev sibling */);
2133 }
2134 }
2135
2136 /* Send the NCCREATE message */
2137 Result = co_IntSendMessage(Window->hSelf, WM_NCCREATE, 0, (LPARAM) Cs);
2138 if (!Result)
2139 {
2140 DPRINT1("co_UserCreateWindowEx(): NCCREATE message failed\n");
2141 RETURN((PWND)0);
2142 }
2143
2144 /* Send the WM_NCCALCSIZE message */
2145 MaxPos.x = Window->Wnd->rcWindow.left;
2146 MaxPos.y = Window->Wnd->rcWindow.top;
2147
2148 Result = co_WinPosGetNonClientSize(Window, &Wnd->rcWindow, &Wnd->rcClient);
2149
2150 RECTL_vOffsetRect(&Wnd->rcWindow, MaxPos.x - Wnd->rcWindow.left,
2151 MaxPos.y - Wnd->rcWindow.top);
2152
2153
2154 /* Send the WM_CREATE message. */
2155 Result = co_IntSendMessage(Window->hSelf, WM_CREATE, 0, (LPARAM) Cs);
2156 if (Result == (LRESULT)-1)
2157 {
2158 DPRINT1("co_UserCreateWindowEx(): WM_CREATE message failed\n");
2159 IntUnlinkWindow(Window);
2160 RETURN((PWND)0);
2161 }
2162
2163 /* Send the EVENT_OBJECT_CREATE event*/
2164 IntNotifyWinEvent(EVENT_OBJECT_CREATE, Window->Wnd, OBJID_WINDOW, 0);
2165
2166 /* By setting the flag below it can be examined to determine if the window
2167 was created successfully and a valid pwnd was passed back to caller since
2168 from here the function has to succeed. */
2169 Window->Wnd->state2 |= WNDS2_WMCREATEMSGPROCESSED;
2170
2171 /* Send the WM_SIZE and WM_MOVE messages. */
2172 if (!(Window->state & WINDOWOBJECT_NEED_SIZE))
2173 {
2174 co_WinPosSendSizeMove(Window);
2175 }
2176
2177 /* Show or maybe minimize or maximize the window. */
2178 if (Wnd->style & (WS_MINIMIZE | WS_MAXIMIZE))
2179 {
2180 RECTL NewPos;
2181 UINT16 SwFlag;
2182
2183 SwFlag = (Wnd->style & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;
2184
2185 co_WinPosMinMaximize(Window, SwFlag, &NewPos);
2186
2187 SwFlag = ((Wnd->style & WS_CHILD) || UserGetActiveWindow()) ?
2188 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED :
2189 SWP_NOZORDER | SWP_FRAMECHANGED;
2190
2191 co_WinPosSetWindowPos(Window, 0, NewPos.left, NewPos.top,
2192 NewPos.right, NewPos.bottom, SwFlag);
2193 }
2194
2195 /* Send the WM_PARENTNOTIFY message */
2196 if ((Wnd->style & WS_CHILD) &&
2197 (!(Wnd->ExStyle & WS_EX_NOPARENTNOTIFY)) && ParentWindow)
2198 {
2199 co_IntSendMessage(ParentWindow->hSelf,
2200 WM_PARENTNOTIFY,
2201 MAKEWPARAM(WM_CREATE, Wnd->IDMenu),
2202 (LPARAM)Window->hSelf);
2203 }
2204
2205 /* Notify the shell that a new window was created */
2206 if ((!hWndParent) && (!hWndOwner))
2207 {
2208 co_IntShellHookNotify(HSHELL_WINDOWCREATED, (LPARAM)hWnd);
2209 }
2210
2211 /* Initialize and show the window's scrollbars */
2212 if (Wnd->style & WS_VSCROLL)
2213 {
2214 co_UserShowScrollBar(Window, SB_VERT, TRUE);
2215 }
2216 if (Wnd->style & WS_HSCROLL)
2217 {
2218 co_UserShowScrollBar(Window, SB_HORZ, TRUE);
2219 }
2220
2221 /* Show the new window */
2222 if (Cs->style & WS_VISIBLE)
2223 {
2224 if (Wnd->style & WS_MAXIMIZE)
2225 dwShowMode = SW_SHOW;
2226 else if (Wnd->style & WS_MINIMIZE)
2227 dwShowMode = SW_SHOWMINIMIZED;
2228
2229 co_WinPosShowWindow(Window, dwShowMode);
2230
2231 if (Wnd->ExStyle & WS_EX_MDICHILD)
2232 {
2233 co_IntSendMessage(ParentWindow->hSelf, WM_MDIREFRESHMENU, 0, 0);
2234 /* ShowWindow won't activate child windows */
2235 co_WinPosSetWindowPos(Window, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
2236 }
2237 }
2238
2239 DPRINT("co_UserCreateWindowEx(): Created window %X\n", hWnd);
2240 RETURN( Wnd);
2241
2242 CLEANUP:
2243 if (!_ret_)
2244 {
2245 /* If the window was created, the class will be dereferenced by co_UserDestroyWindow */
2246 if (Window)
2247 co_UserDestroyWindow(Window);
2248 else
2249 IntDereferenceClass(Class, pti->pDeskInfo, pti->ppi);
2250 }
2251
2252 if (Window)
2253 {
2254 UserDerefObjectCo(Window);
2255 UserDereferenceObject(Window);
2256 }
2257 if (ParentWindow) UserDerefObjectCo(ParentWindow);
2258
2259 END_CLEANUP;
2260 }
2261
2262 NTSTATUS
2263 NTAPI
2264 ProbeAndCaptureLargeString(
2265 OUT PLARGE_STRING plstrSafe,
2266 IN PLARGE_STRING plstrUnsafe)
2267 {
2268 LARGE_STRING lstrTemp;
2269 PVOID pvBuffer = NULL;
2270
2271 _SEH2_TRY
2272 {
2273 /* Probe and copy the string */
2274 ProbeForRead(plstrUnsafe, sizeof(LARGE_STRING), sizeof(ULONG));
2275 lstrTemp = *plstrUnsafe;
2276 }
2277 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2278 {
2279 /* Fail */
2280 _SEH2_YIELD(return _SEH2_GetExceptionCode();)
2281 }
2282 _SEH2_END
2283
2284 if (lstrTemp.Length != 0)
2285 {
2286 /* Allocate a buffer from paged pool */
2287 pvBuffer = ExAllocatePoolWithTag(PagedPool, lstrTemp.Length, TAG_STRING);
2288 if (!pvBuffer)
2289 {
2290 return STATUS_NO_MEMORY;
2291 }
2292
2293 _SEH2_TRY
2294 {
2295 /* Probe and copy the buffer */
2296 ProbeForRead(lstrTemp.Buffer, lstrTemp.Length, sizeof(WCHAR));
2297 RtlCopyMemory(pvBuffer, lstrTemp.Buffer, lstrTemp.Length);
2298 }
2299 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2300 {
2301 /* Cleanup and fail */
2302 ExFreePool(pvBuffer);
2303 _SEH2_YIELD(return _SEH2_GetExceptionCode();)
2304 }
2305 _SEH2_END
2306 }
2307
2308 /* Set the output string */
2309 plstrSafe->Buffer = pvBuffer;
2310 plstrSafe->Length = lstrTemp.Length;
2311 plstrSafe->MaximumLength = lstrTemp.Length;
2312
2313 return STATUS_SUCCESS;
2314 }
2315
2316 /**
2317 * \todo Allow passing plstrClassName as ANSI.
2318 */
2319 HWND
2320 NTAPI
2321 NtUserCreateWindowEx(
2322 DWORD dwExStyle,
2323 PLARGE_STRING plstrClassName,
2324 PLARGE_STRING plstrClsVersion,
2325 PLARGE_STRING plstrWindowName,
2326 DWORD dwStyle,
2327 int x,
2328 int y,
2329 int nWidth,
2330 int nHeight,
2331 HWND hWndParent,
2332 HMENU hMenu,
2333 HINSTANCE hInstance,
2334 LPVOID lpParam,
2335 DWORD dwFlags,
2336 PVOID acbiBuffer)
2337 {
2338 NTSTATUS Status;
2339 LARGE_STRING lstrWindowName;
2340 LARGE_STRING lstrClassName;
2341 UNICODE_STRING ustrClassName;
2342 CREATESTRUCTW Cs;
2343 HWND hwnd = NULL;
2344 PWND pwnd;
2345
2346 lstrWindowName.Buffer = NULL;
2347 lstrClassName.Buffer = NULL;
2348
2349 /* Check if we got a Window name */
2350 if (plstrWindowName)
2351 {
2352 /* Copy the string to kernel mode */
2353 Status = ProbeAndCaptureLargeString(&lstrWindowName, plstrWindowName);
2354 if (!NT_SUCCESS(Status))
2355 {
2356 DPRINT1("NtUserCreateWindowEx: failed to capture plstrWindowName\n");
2357 SetLastNtError(Status);
2358 return NULL;
2359 }
2360 plstrWindowName = &lstrWindowName;
2361 }
2362
2363 /* Check if the class is an atom */
2364 if (IS_ATOM(plstrClassName))
2365 {
2366 /* It is, pass the atom in the UNICODE_STRING */
2367 ustrClassName.Buffer = (PVOID)plstrClassName;
2368 ustrClassName.Length = 0;
2369 ustrClassName.MaximumLength = 0;
2370 }
2371 else
2372 {
2373 /* It's not, capture the class name */
2374 Status = ProbeAndCaptureLargeString(&lstrClassName, plstrClassName);
2375 if (!NT_SUCCESS(Status))
2376 {
2377 DPRINT1("NtUserCreateWindowEx: failed to capture plstrClassName\n");
2378 /* Set last error, cleanup and return */
2379 SetLastNtError(Status);
2380 goto cleanup;
2381 }
2382
2383 /* We pass it on as a UNICODE_STRING */
2384 ustrClassName.Buffer = lstrClassName.Buffer;
2385 ustrClassName.Length = lstrClassName.Length;
2386 ustrClassName.MaximumLength = lstrClassName.MaximumLength;
2387 }
2388
2389 /* Fill the CREATESTRUCTW */
2390 /* we will keep here the original parameters */
2391 Cs.style = dwStyle;
2392 Cs.lpCreateParams = lpParam;
2393 Cs.hInstance = hInstance;
2394 Cs.hMenu = hMenu;
2395 Cs.hwndParent = hWndParent;
2396 Cs.cx = nWidth;
2397 Cs.cy = nHeight;
2398 Cs.x = x;
2399 Cs.y = y;
2400 // Cs.lpszName = (LPCWSTR) WindowName->Buffer;
2401 // Cs.lpszClass = (LPCWSTR) ClassName->Buffer;
2402 Cs.lpszName = (LPCWSTR) plstrWindowName;
2403 Cs.lpszClass = (LPCWSTR) &ustrClassName;
2404 Cs.dwExStyle = dwExStyle;
2405
2406 UserEnterExclusive();
2407
2408 /* Call the internal function */
2409 pwnd = co_UserCreateWindowEx(&Cs, &ustrClassName, plstrWindowName);
2410
2411 if(!pwnd)
2412 {
2413 DPRINT1("co_UserCreateWindowEx failed!\n");
2414 }
2415 hwnd = pwnd ? UserHMGetHandle(pwnd) : NULL;
2416
2417 UserLeave();
2418
2419 cleanup:
2420 if (lstrWindowName.Buffer)
2421 {
2422 ExFreePoolWithTag(lstrWindowName.Buffer, TAG_STRING);
2423 }
2424 if (lstrClassName.Buffer)
2425 {
2426 ExFreePoolWithTag(lstrClassName.Buffer, TAG_STRING);
2427 }
2428
2429 return hwnd;
2430 }
2431
2432 /*
2433 * @unimplemented
2434 */
2435 HDWP APIENTRY
2436 NtUserDeferWindowPos(HDWP WinPosInfo,
2437 HWND Wnd,
2438 HWND WndInsertAfter,
2439 int x,
2440 int y,
2441 int cx,
2442 int cy,
2443 UINT Flags)
2444 {
2445 UNIMPLEMENTED
2446
2447 return 0;
2448 }
2449
2450
2451 BOOLEAN FASTCALL co_UserDestroyWindow(PWINDOW_OBJECT Window)
2452 {
2453 BOOLEAN isChild;
2454 PWND Wnd;
2455 HWND hWnd;
2456 PTHREADINFO ti;
2457 MSG msg;
2458
2459 ASSERT_REFS_CO(Window); // FIXME: temp hack?
2460
2461 hWnd = Window->hSelf;
2462
2463 Wnd = Window->Wnd;
2464
2465 if (!Wnd) return TRUE; // FIXME: Need to finish object rewrite or lock the thread when killing the window!
2466
2467 DPRINT("co_UserDestroyWindow \n");
2468
2469 /* Check for owner thread */
2470 if ( (Window->pti->pEThread != PsGetCurrentThread()) ||
2471 Wnd->head.pti != PsGetCurrentThreadWin32Thread() )
2472 {
2473 SetLastWin32Error(ERROR_ACCESS_DENIED);
2474 return FALSE;
2475 }
2476
2477 /* If window was created successfully and it is hooked */
2478 if ((Wnd->state2 & WNDS2_WMCREATEMSGPROCESSED) && (ISITHOOKED(WH_CBT)))
2479 {
2480 if (co_HOOK_CallHooks(WH_CBT, HCBT_DESTROYWND, (WPARAM) hWnd, 0)) return FALSE;
2481 }
2482
2483 /* Look whether the focus is within the tree of windows we will
2484 * be destroying.
2485 */
2486 if (!co_WinPosShowWindow(Window, SW_HIDE))
2487 {
2488 if (UserGetActiveWindow() == Window->hSelf)
2489 {
2490 co_WinPosActivateOtherWindow(Window);
2491 }
2492 }
2493
2494 if (Window->pti->MessageQueue->ActiveWindow == Window->hSelf)
2495 Window->pti->MessageQueue->ActiveWindow = NULL;
2496 if (Window->pti->MessageQueue->FocusWindow == Window->hSelf)
2497 Window->pti->MessageQueue->FocusWindow = NULL;
2498 if (Window->pti->MessageQueue->CaptureWindow == Window->hSelf)
2499 Window->pti->MessageQueue->CaptureWindow = NULL;
2500
2501 /*
2502 * Check if this window is the Shell's Desktop Window. If so set hShellWindow to NULL
2503 */
2504
2505 ti = PsGetCurrentThreadWin32Thread();
2506
2507 if ((ti != NULL) & (ti->pDeskInfo != NULL))
2508 {
2509 if (ti->pDeskInfo->hShellWindow == hWnd)
2510 {
2511 DPRINT1("Destroying the ShellWindow!\n");
2512 ti->pDeskInfo->hShellWindow = NULL;
2513 }
2514 }
2515
2516 IntDereferenceMessageQueue(Window->pti->MessageQueue);
2517
2518 IntEngWindowChanged(Window, WOC_DELETE);
2519 isChild = (0 != (Wnd->style & WS_CHILD));
2520
2521 #if 0 /* FIXME */
2522
2523 if (isChild)
2524 {
2525 if (! USER_IsExitingThread(GetCurrentThreadId()))
2526 {
2527 send_parent_notify(hwnd, WM_DESTROY);
2528 }
2529 }
2530 else if (NULL != GetWindow(Wnd, GW_OWNER))
2531 {
2532 co_HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
2533 /* FIXME: clean up palette - see "Internals" p.352 */
2534 }
2535 #endif
2536
2537 if (!IntIsWindow(Window->hSelf))
2538 {
2539 return TRUE;
2540 }
2541
2542 /* Recursively destroy owned windows */
2543 if (! isChild)
2544 {
2545 for (;;)
2546 {
2547 BOOL GotOne = FALSE;
2548 HWND *Children;
2549 HWND *ChildHandle;
2550 PWINDOW_OBJECT Child, Desktop;
2551
2552 Desktop = IntIsDesktopWindow(Window) ? Window :
2553 UserGetWindowObject(IntGetDesktopWindow());
2554 Children = IntWinListChildren(Desktop);
2555
2556 if (Children)
2557 {
2558 for (ChildHandle = Children; *ChildHandle; ++ChildHandle)
2559 {
2560 Child = UserGetWindowObject(*ChildHandle);
2561 if (Child == NULL)
2562 continue;
2563 if (Child->hOwner != Window->hSelf)
2564 {
2565 continue;
2566 }
2567
2568 if (IntWndBelongsToThread(Child, PsGetCurrentThreadWin32Thread()))
2569 {
2570 USER_REFERENCE_ENTRY ChildRef;
2571 UserRefObjectCo(Child, &ChildRef);//temp hack?
2572 co_UserDestroyWindow(Child);
2573 UserDerefObjectCo(Child);//temp hack?
2574
2575 GotOne = TRUE;
2576 continue;
2577 }
2578
2579 if (Child->hOwner != NULL)
2580 {
2581 Child->hOwner = NULL;
2582 Child->Wnd->spwndOwner = NULL;
2583 }
2584
2585 }
2586 ExFreePool(Children);
2587 }
2588 if (! GotOne)
2589 {
2590 break;
2591 }
2592 }
2593 }
2594
2595 /* Generate mouse move message for the next window */
2596 msg.message = WM_MOUSEMOVE;
2597 msg.wParam = IntGetSysCursorInfo()->ButtonsDown;
2598 msg.lParam = MAKELPARAM(gpsi->ptCursor.x, gpsi->ptCursor.y);
2599 msg.pt = gpsi->ptCursor;
2600 MsqInsertSystemMessage(&msg);
2601
2602 if (!IntIsWindow(Window->hSelf))
2603 {
2604 return TRUE;
2605 }
2606
2607 /* Destroy the window storage */
2608 co_UserFreeWindow(Window, PsGetCurrentProcessWin32Process(), PsGetCurrentThreadWin32Thread(), TRUE);
2609
2610 return TRUE;
2611 }
2612
2613
2614 /*
2615 * @implemented
2616 */
2617 BOOLEAN APIENTRY
2618 NtUserDestroyWindow(HWND Wnd)
2619 {
2620 PWINDOW_OBJECT Window;
2621 DECLARE_RETURN(BOOLEAN);
2622 BOOLEAN ret;
2623 USER_REFERENCE_ENTRY Ref;
2624
2625 DPRINT("Enter NtUserDestroyWindow\n");
2626 UserEnterExclusive();
2627
2628 if (!(Window = UserGetWindowObject(Wnd)))
2629 {
2630 RETURN(FALSE);
2631 }
2632
2633 UserRefObjectCo(Window, &Ref);//faxme: dunno if win should be reffed during destroy..
2634 ret = co_UserDestroyWindow(Window);
2635 UserDerefObjectCo(Window);//faxme: dunno if win should be reffed during destroy..
2636
2637 RETURN(ret);
2638
2639 CLEANUP:
2640 DPRINT("Leave NtUserDestroyWindow, ret=%i\n",_ret_);
2641 UserLeave();
2642 END_CLEANUP;
2643 }
2644
2645
2646
2647 /*
2648 * @unimplemented
2649 */
2650 DWORD
2651 APIENTRY
2652 NtUserDrawMenuBarTemp(
2653 HWND hWnd,
2654 HDC hDC,
2655 PRECT hRect,
2656 HMENU hMenu,
2657 HFONT hFont)
2658 {
2659 /* we'll use this function just for caching the menu bar */
2660 UNIMPLEMENTED
2661 return 0;
2662 }
2663
2664
2665 /*
2666 * @unimplemented
2667 */
2668 DWORD APIENTRY
2669 NtUserEndDeferWindowPosEx(DWORD Unknown0,
2670 DWORD Unknown1)
2671 {
2672 UNIMPLEMENTED
2673
2674 return 0;
2675 }
2676
2677
2678 /*
2679 * FillWindow: Called from User; Dialog, Edit and ListBox procs during a WM_ERASEBKGND.
2680 */
2681 /*
2682 * @unimplemented
2683 */
2684 BOOL APIENTRY
2685 NtUserFillWindow(HWND hWndPaint,
2686 HWND hWndPaint1,
2687 HDC hDC,
2688 HBRUSH hBrush)
2689 {
2690 UNIMPLEMENTED
2691
2692 return 0;
2693 }
2694
2695
2696 static HWND FASTCALL
2697 IntFindWindow(PWINDOW_OBJECT Parent,
2698 PWINDOW_OBJECT ChildAfter,
2699 RTL_ATOM ClassAtom,
2700 PUNICODE_STRING WindowName)
2701 {
2702 BOOL CheckWindowName;
2703 HWND *List, *phWnd;
2704 HWND Ret = NULL;
2705 UNICODE_STRING CurrentWindowName;
2706
2707 ASSERT(Parent);
2708
2709 CheckWindowName = WindowName->Length != 0;
2710
2711 if((List = IntWinListChildren(Parent)))
2712 {
2713 phWnd = List;
2714 if(ChildAfter)
2715 {
2716 /* skip handles before and including ChildAfter */
2717 while(*phWnd && (*(phWnd++) != ChildAfter->hSelf))
2718 ;
2719 }
2720
2721 /* search children */
2722 while(*phWnd)
2723 {
2724 PWINDOW_OBJECT Child;
2725 if(!(Child = UserGetWindowObject(*(phWnd++))))
2726 {
2727 continue;
2728 }
2729
2730 /* Do not send WM_GETTEXT messages in the kernel mode version!
2731 The user mode version however calls GetWindowText() which will
2732 send WM_GETTEXT messages to windows belonging to its processes */
2733 if (!ClassAtom || Child->Wnd->pcls->atomClassName == ClassAtom)
2734 {
2735 // HACK: use UNICODE_STRING instead of LARGE_STRING
2736 CurrentWindowName.Buffer = Child->Wnd->strName.Buffer;
2737 CurrentWindowName.Length = Child->Wnd->strName.Length;
2738 CurrentWindowName.MaximumLength = Child->Wnd->strName.MaximumLength;
2739 if(!CheckWindowName ||
2740 (Child->Wnd->strName.Length < 0xFFFF &&
2741 !RtlCompareUnicodeString(WindowName, &CurrentWindowName, TRUE)))
2742 {
2743 Ret = Child->hSelf;
2744 break;
2745 }
2746 }
2747 }
2748 ExFreePool(List);
2749 }
2750
2751 return Ret;
2752 }
2753
2754 /*
2755 * FUNCTION:
2756 * Searches a window's children for a window with the specified
2757 * class and name
2758 * ARGUMENTS:
2759 * hwndParent = The window whose childs are to be searched.
2760 * NULL = desktop
2761 * HWND_MESSAGE = message-only windows
2762 *
2763 * hwndChildAfter = Search starts after this child window.
2764 * NULL = start from beginning
2765 *
2766 * ucClassName = Class name to search for
2767 * Reguired parameter.
2768 *
2769 * ucWindowName = Window name
2770 * ->Buffer == NULL = don't care
2771 *
2772 * RETURNS:
2773 * The HWND of the window if it was found, otherwise NULL
2774 */
2775 /*
2776 * @implemented
2777 */
2778 HWND APIENTRY
2779 NtUserFindWindowEx(HWND hwndParent,
2780 HWND hwndChildAfter,
2781 PUNICODE_STRING ucClassName,
2782 PUNICODE_STRING ucWindowName,
2783 DWORD dwUnknown)
2784 {
2785 PWINDOW_OBJECT Parent, ChildAfter;
2786 UNICODE_STRING ClassName = {0}, WindowName = {0};
2787 HWND Desktop, Ret = NULL;
2788 RTL_ATOM ClassAtom = (RTL_ATOM)0;
2789 DECLARE_RETURN(HWND);
2790
2791 DPRINT("Enter NtUserFindWindowEx\n");
2792 UserEnterShared();
2793
2794 if (ucClassName != NULL || ucWindowName != NULL)
2795 {
2796 _SEH2_TRY
2797 {
2798 if (ucClassName != NULL)
2799 {
2800 ClassName = ProbeForReadUnicodeString(ucClassName);
2801 if (ClassName.Length != 0)
2802 {
2803 ProbeForRead(ClassName.Buffer,
2804 ClassName.Length,
2805 sizeof(WCHAR));
2806 }
2807 else if (!IS_ATOM(ClassName.Buffer))
2808 {
2809 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2810 _SEH2_LEAVE;
2811 }
2812
2813 if (!IntGetAtomFromStringOrAtom(&ClassName,
2814 &ClassAtom))
2815 {
2816 _SEH2_LEAVE;
2817 }
2818 }
2819
2820 if (ucWindowName != NULL)
2821 {
2822 WindowName = ProbeForReadUnicodeString(ucWindowName);
2823 if (WindowName.Length != 0)
2824 {
2825 ProbeForRead(WindowName.Buffer,
2826 WindowName.Length,
2827 sizeof(WCHAR));
2828 }
2829 }
2830 }
2831 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2832 {
2833 SetLastNtError(_SEH2_GetExceptionCode());
2834 _SEH2_YIELD(RETURN(NULL));
2835 }
2836 _SEH2_END;
2837
2838 if (ucClassName != NULL)
2839 {
2840 if (ClassName.Length == 0 && ClassName.Buffer != NULL &&
2841 !IS_ATOM(ClassName.Buffer))
2842 {
2843 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2844 RETURN(NULL);
2845 }
2846 else if (ClassAtom == (RTL_ATOM)0)
2847 {
2848 /* LastError code was set by IntGetAtomFromStringOrAtom */
2849 RETURN(NULL);
2850 }
2851 }
2852 }
2853
2854 Desktop = IntGetCurrentThreadDesktopWindow();
2855
2856 if(hwndParent == NULL)
2857 hwndParent = Desktop;
2858 else if(hwndParent == HWND_MESSAGE)
2859 {
2860 hwndParent = IntGetMessageWindow();
2861 }
2862
2863 if(!(Parent = UserGetWindowObject(hwndParent)))
2864 {
2865 RETURN( NULL);
2866 }
2867
2868 ChildAfter = NULL;
2869 if(hwndChildAfter && !(ChildAfter = UserGetWindowObject(hwndChildAfter)))
2870 {
2871 RETURN( NULL);
2872 }
2873
2874 _SEH2_TRY
2875 {
2876 if(Parent->hSelf == Desktop)
2877 {
2878 HWND *List, *phWnd;
2879 PWINDOW_OBJECT TopLevelWindow;
2880 BOOLEAN CheckWindowName;
2881 BOOLEAN WindowMatches;
2882 BOOLEAN ClassMatches;
2883
2884 /* windows searches through all top-level windows if the parent is the desktop
2885 window */
2886
2887 if((List = IntWinListChildren(Parent)))
2888 {
2889 phWnd = List;
2890
2891 if(ChildAfter)
2892 {
2893 /* skip handles before and including ChildAfter */
2894 while(*phWnd && (*(phWnd++) != ChildAfter->hSelf))
2895 ;
2896 }
2897
2898 CheckWindowName = WindowName.Length != 0;
2899
2900 /* search children */
2901 while(*phWnd)
2902 {
2903 UNICODE_STRING ustr;
2904
2905 if(!(TopLevelWindow = UserGetWindowObject(*(phWnd++))))
2906 {
2907 continue;
2908 }
2909
2910 /* Do not send WM_GETTEXT messages in the kernel mode version!
2911 The user mode version however calls GetWindowText() which will
2912 send WM_GETTEXT messages to windows belonging to its processes */
2913 ustr.Buffer = TopLevelWindow->Wnd->strName.Buffer;
2914 ustr.Length = TopLevelWindow->Wnd->strName.Length;
2915 ustr.MaximumLength = TopLevelWindow->Wnd->strName.MaximumLength;
2916 WindowMatches = !CheckWindowName ||
2917 (TopLevelWindow->Wnd->strName.Length < 0xFFFF &&
2918 !RtlCompareUnicodeString(&WindowName, &ustr, TRUE));
2919 ClassMatches = (ClassAtom == (RTL_ATOM)0) ||
2920 ClassAtom == TopLevelWindow->Wnd->pcls->atomClassName;
2921
2922 if (WindowMatches && ClassMatches)
2923 {
2924 Ret = TopLevelWindow->hSelf;
2925 break;
2926 }
2927
2928 if (IntFindWindow(TopLevelWindow, NULL, ClassAtom, &WindowName))
2929 {
2930 /* window returns the handle of the top-level window, in case it found
2931 the child window */
2932 Ret = TopLevelWindow->hSelf;
2933 break;
2934 }
2935
2936 }
2937 ExFreePool(List);
2938 }
2939 }
2940 else
2941 Ret = IntFindWindow(Parent, ChildAfter, ClassAtom, &WindowName);
2942
2943 #if 0
2944
2945 if(Ret == NULL && hwndParent == NULL && hwndChildAfter == NULL)
2946 {
2947 /* FIXME - if both hwndParent and hwndChildAfter are NULL, we also should
2948 search the message-only windows. Should this also be done if
2949 Parent is the desktop window??? */
2950 PWINDOW_OBJECT MsgWindows;
2951
2952 if((MsgWindows = UserGetWindowObject(IntGetMessageWindow())))
2953 {
2954 Ret = IntFindWindow(MsgWindows, ChildAfter, ClassAtom, &WindowName);
2955 }
2956 }
2957 #endif
2958 }
2959 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2960 {
2961 SetLastNtError(_SEH2_GetExceptionCode());
2962 Ret = NULL;
2963 }
2964 _SEH2_END;
2965
2966 RETURN( Ret);
2967
2968 CLEANUP:
2969 DPRINT("Leave NtUserFindWindowEx, ret %i\n",_ret_);
2970 UserLeave();
2971 END_CLEANUP;
2972 }
2973
2974
2975 /*
2976 * @unimplemented
2977 */
2978 BOOL APIENTRY
2979 NtUserFlashWindowEx(IN PFLASHWINFO pfwi)
2980 {
2981 UNIMPLEMENTED
2982
2983 return 0;
2984 }
2985
2986
2987 /*
2988 * @implemented
2989 */
2990 PWINDOW_OBJECT FASTCALL UserGetAncestor(PWINDOW_OBJECT Wnd, UINT Type)
2991 {
2992 PWINDOW_OBJECT WndAncestor, Parent;
2993
2994 if (Wnd->hSelf == IntGetDesktopWindow())
2995 {
2996 return NULL;
2997 }
2998
2999 switch (Type)
3000 {
3001 case GA_PARENT:
3002 {
3003 WndAncestor = Wnd->spwndParent;
3004 break;
3005 }
3006
3007 case GA_ROOT:
3008 {
3009 WndAncestor = Wnd;
3010 Parent = NULL;
3011
3012 for(;;)
3013 {
3014 if(!(Parent = WndAncestor->spwndParent))
3015 {
3016 break;
3017 }
3018 if(IntIsDesktopWindow(Parent))
3019 {
3020 break;
3021 }
3022
3023 WndAncestor = Parent;
3024 }
3025 break;
3026 }
3027
3028 case GA_ROOTOWNER:
3029 {
3030 WndAncestor = Wnd;
3031
3032 for (;;)
3033 {
3034 PWINDOW_OBJECT Parent, Old;
3035
3036 Old = WndAncestor;
3037 Parent = IntGetParent(WndAncestor);
3038
3039 if (!Parent)
3040 {
3041 break;
3042 }
3043
3044 //temp hack
3045 // UserDereferenceObject(Parent);
3046
3047 WndAncestor = Parent;
3048 }
3049 break;
3050 }
3051
3052 default:
3053 {
3054 return NULL;
3055 }
3056 }
3057
3058 return WndAncestor;
3059 }
3060
3061 /*
3062 * @implemented
3063 */
3064 HWND APIENTRY
3065 NtUserGetAncestor(HWND hWnd, UINT Type)
3066 {
3067 PWINDOW_OBJECT Window, Ancestor;
3068 DECLARE_RETURN(HWND);
3069
3070 DPRINT("Enter NtUserGetAncestor\n");
3071 UserEnterExclusive();
3072
3073 if (!(Window = UserGetWindowObject(hWnd)))
3074 {
3075 RETURN(NULL);
3076 }
3077
3078 Ancestor = UserGetAncestor(Window, Type);
3079 /* faxme: can UserGetAncestor ever return NULL for a valid window? */
3080
3081 RETURN(Ancestor ? Ancestor->hSelf : NULL);
3082
3083 CLEANUP:
3084 DPRINT("Leave NtUserGetAncestor, ret=%i\n",_ret_);
3085 UserLeave();
3086 END_CLEANUP;
3087 }
3088
3089
3090 BOOL
3091 APIENTRY
3092 NtUserGetComboBoxInfo(
3093 HWND hWnd,
3094 PCOMBOBOXINFO pcbi)
3095 {
3096 PWINDOW_OBJECT Wnd;
3097 DECLARE_RETURN(BOOL);
3098
3099 DPRINT("Enter NtUserGetComboBoxInfo\n");
3100 UserEnterShared();
3101
3102 if (!(Wnd = UserGetWindowObject(hWnd)))
3103 {
3104 RETURN( FALSE );
3105 }
3106 _SEH2_TRY
3107 {
3108 if(pcbi)
3109 {
3110 ProbeForWrite(pcbi,
3111 sizeof(COMBOBOXINFO),
3112 1);
3113 }
3114 }
3115 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3116 {
3117 SetLastNtError(_SEH2_GetExceptionCode());
3118 _SEH2_YIELD(RETURN(FALSE));
3119 }
3120 _SEH2_END;
3121
3122 // Pass the user pointer, it was already probed.
3123 RETURN( (BOOL) co_IntSendMessage( Wnd->hSelf, CB_GETCOMBOBOXINFO, 0, (LPARAM)pcbi));
3124
3125 CLEANUP:
3126 DPRINT("Leave NtUserGetComboBoxInfo, ret=%i\n",_ret_);
3127 UserLeave();
3128 END_CLEANUP;
3129 }
3130
3131
3132 /*
3133 * @implemented
3134 */
3135 DWORD APIENTRY
3136 NtUserGetInternalWindowPos( HWND hWnd,
3137 LPRECT rectWnd,
3138 LPPOINT ptIcon)
3139 {
3140 PWINDOW_OBJECT Window;
3141 PWND Wnd;
3142 DWORD Ret = 0;
3143 BOOL Hit = FALSE;
3144 WINDOWPLACEMENT wndpl;
3145
3146 UserEnterShared();
3147
3148 if (!(Window = UserGetWindowObject(hWnd)) || !Window->Wnd)
3149 {
3150 Hit = FALSE;
3151 goto Exit;
3152 }
3153 Wnd = Window->Wnd;
3154
3155 _SEH2_TRY
3156 {
3157 if(rectWnd)
3158 {
3159 ProbeForWrite(rectWnd,
3160 sizeof(RECT),
3161 1);
3162 }
3163 if(ptIcon)
3164 {
3165 ProbeForWrite(ptIcon,
3166 sizeof(POINT),
3167 1);
3168 }
3169
3170 }
3171 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3172 {
3173 SetLastNtError(_SEH2_GetExceptionCode());
3174 Hit = TRUE;
3175 }
3176 _SEH2_END;
3177
3178 wndpl.length = sizeof(WINDOWPLACEMENT);
3179
3180 if (IntGetWindowPlacement(Window, &wndpl) && !Hit)
3181 {
3182 _SEH2_TRY
3183 {
3184 if (rectWnd)
3185 {
3186 RtlCopyMemory(rectWnd, &wndpl.rcNormalPosition , sizeof(RECT));
3187 }
3188 if (ptIcon)
3189 {
3190 RtlCopyMemory(ptIcon, &wndpl.ptMinPosition, sizeof(POINT));
3191 }
3192
3193 }
3194 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3195 {
3196 SetLastNtError(_SEH2_GetExceptionCode());
3197 Hit = TRUE;
3198 }
3199 _SEH2_END;
3200
3201 if (!Hit) Ret = wndpl.showCmd;
3202 }
3203 Exit:
3204 UserLeave();
3205 return Ret;
3206 }
3207
3208 DWORD
3209 APIENTRY
3210 NtUserGetListBoxInfo(
3211 HWND hWnd)
3212 {
3213 PWINDOW_OBJECT Wnd;
3214 DECLARE_RETURN(DWORD);
3215
3216 DPRINT("Enter NtUserGetListBoxInfo\n");
3217 UserEnterShared();
3218
3219 if (!(Wnd = UserGetWindowObject(hWnd)))
3220 {
3221 RETURN( 0 );
3222 }
3223
3224 RETURN( (DWORD) co_IntSendMessage( Wnd->hSelf, LB_GETLISTBOXINFO, 0, 0 ));
3225
3226 CLEANUP:
3227 DPRINT("Leave NtUserGetListBoxInfo, ret=%i\n",_ret_);
3228 UserLeave();
3229 END_CLEANUP;
3230 }
3231
3232
3233 HWND FASTCALL
3234 co_UserSetParent(HWND hWndChild, HWND hWndNewParent)
3235 {
3236 PWINDOW_OBJECT Wnd = NULL, WndParent = NULL, WndOldParent;
3237 HWND hWndOldParent = NULL;
3238 USER_REFERENCE_ENTRY Ref, ParentRef;
3239
3240 if (IntIsBroadcastHwnd(hWndChild) || IntIsBroadcastHwnd(hWndNewParent))
3241 {
3242 SetLastWin32Error(ERROR_INVALID_PARAMETER);
3243 return( NULL);
3244 }
3245
3246 if (hWndChild == IntGetDesktopWindow())
3247 {
3248 SetLastWin32Error(ERROR_ACCESS_DENIED);
3249 return( NULL);
3250 }
3251
3252 if (hWndNewParent)
3253 {
3254 if (!(WndParent = UserGetWindowObject(hWndNewParent)))
3255 {
3256 return( NULL);
3257 }
3258 }
3259 else
3260 {
3261 if (!(WndParent = UserGetWindowObject(IntGetDesktopWindow())))
3262 {
3263 return( NULL);
3264 }
3265 }
3266
3267 if (!(Wnd = UserGetWindowObject(hWndChild)))
3268 {
3269 return( NULL);
3270 }
3271
3272 UserRefObjectCo(Wnd, &Ref);
3273 UserRefObjectCo(WndParent, &ParentRef);
3274
3275 WndOldParent = co_IntSetParent(Wnd, WndParent);
3276
3277 UserDerefObjectCo(WndParent);
3278 UserDerefObjectCo(Wnd);
3279
3280 if (WndOldParent)
3281 {
3282 hWndOldParent = WndOldParent->hSelf;
3283 UserDereferenceObject(WndOldParent);
3284 }
3285
3286 return( hWndOldParent);
3287 }
3288
3289 /*
3290 * NtUserSetParent
3291 *
3292 * The NtUserSetParent function changes the parent window of the specified
3293 * child window.
3294 *
3295 * Remarks
3296 * The new parent window and the child window must belong to the same
3297 * application. If the window identified by the hWndChild parameter is
3298 * visible, the system performs the appropriate redrawing and repainting.
3299 * For compatibility reasons, NtUserSetParent does not modify the WS_CHILD
3300 * or WS_POPUP window styles of the window whose parent is being changed.
3301 *
3302 * Status
3303 * @implemented
3304 */
3305
3306 HWND APIENTRY
3307 NtUserSetParent(HWND hWndChild, HWND hWndNewParent)
3308 {
3309 DECLARE_RETURN(HWND);
3310
3311 DPRINT("Enter NtUserSetParent\n");
3312 UserEnterExclusive();
3313
3314 /*
3315 Check Parent first from user space, set it here.
3316 */
3317 if (!hWndNewParent)
3318 {
3319 hWndNewParent = IntGetDesktopWindow();
3320 }
3321 else if (hWndNewParent == HWND_MESSAGE)
3322 {
3323 hWndNewParent = IntGetMessageWindow();
3324 }
3325
3326 RETURN( co_UserSetParent(hWndChild, hWndNewParent));
3327
3328 CLEANUP:
3329 DPRINT("Leave NtUserSetParent, ret=%i\n",_ret_);
3330 UserLeave();
3331 END_CLEANUP;
3332 }
3333
3334 /*
3335 * UserGetShellWindow
3336 *
3337 * Returns a handle to shell window that was set by NtUserSetShellWindowEx.
3338 *
3339 * Status
3340 * @implemented
3341 */
3342 HWND FASTCALL UserGetShellWindow(VOID)
3343 {
3344 PWINSTATION_OBJECT WinStaObject;
3345 HWND Ret;
3346
3347 NTSTATUS Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
3348 KernelMode,
3349 0,
3350 &WinStaObject);
3351
3352 if (!NT_SUCCESS(Status))
3353 {
3354 SetLastNtError(Status);
3355 return( (HWND)0);
3356 }
3357
3358 Ret = (HWND)WinStaObject->ShellWindow;
3359
3360 ObDereferenceObject(WinStaObject);
3361 return( Ret);
3362 }
3363
3364 /*
3365 * NtUserSetShellWindowEx
3366 *
3367 * This is undocumented function to set global shell window. The global
3368 * shell window has special handling of window position.
3369 *
3370 * Status
3371 * @implemented
3372 */
3373 BOOL APIENTRY
3374 NtUserSetShellWindowEx(HWND hwndShell, HWND hwndListView)
3375 {
3376 PWINSTATION_OBJECT WinStaObject;
3377 PWINDOW_OBJECT WndShell;
3378 DECLARE_RETURN(BOOL);
3379 USER_REFERENCE_ENTRY Ref;
3380 NTSTATUS Status;
3381 PTHREADINFO ti;
3382
3383 DPRINT("Enter NtUserSetShellWindowEx\n");
3384 UserEnterExclusive();
3385
3386 if (!(WndShell = UserGetWindowObject(hwndShell)))
3387 {
3388 RETURN(FALSE);
3389 }
3390
3391 Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
3392 KernelMode,
3393 0,
3394 &WinStaObject);
3395
3396 if (!NT_SUCCESS(Status))
3397 {
3398 SetLastNtError(Status);
3399 RETURN( FALSE);
3400 }
3401
3402 /*
3403 * Test if we are permitted to change the shell window.
3404 */
3405 if (WinStaObject->ShellWindow)
3406 {
3407 ObDereferenceObject(WinStaObject);
3408 RETURN( FALSE);
3409 }
3410
3411 /*
3412 * Move shell window into background.
3413 */
3414 if (hwndListView && hwndListView != hwndShell)
3415 {
3416 /*
3417 * Disabled for now to get Explorer working.
3418 * -- Filip, 01/nov/2003
3419 */
3420 #if 0
3421 co_WinPosSetWindowPos(hwndListView, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
3422 #endif
3423
3424 if (UserGetWindowLong(hwndListView, GWL_EXSTYLE, FALSE) & WS_EX_TOPMOST)
3425 {
3426 ObDereferenceObject(WinStaObject);
3427 RETURN( FALSE);
3428 }
3429 }
3430
3431 if (UserGetWindowLong(hwndShell, GWL_EXSTYLE, FALSE) & WS_EX_TOPMOST)
3432 {
3433 ObDereferenceObject(WinStaObject);
3434 RETURN( FALSE);
3435 }
3436
3437 UserRefObjectCo(WndShell, &Ref);
3438 co_WinPosSetWindowPos(WndShell, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
3439
3440 WinStaObject->ShellWindow = hwndShell;
3441 WinStaObject->ShellListView = hwndListView;
3442
3443 ti = GetW32ThreadInfo();
3444 if (ti->pDeskInfo) ti->pDeskInfo->hShellWindow = hwndShell;
3445
3446 UserDerefObjectCo(WndShell);
3447
3448 ObDereferenceObject(WinStaObject);
3449 RETURN( TRUE);
3450
3451 CLEANUP:
3452 DPRINT("Leave NtUserSetShellWindowEx, ret=%i\n",_ret_);
3453 UserLeave();
3454 END_CLEANUP;
3455 }
3456
3457 /*
3458 * NtUserGetSystemMenu
3459 *
3460 * The NtUserGetSystemMenu function allows the application to access the
3461 * window menu (also known as the system menu or the control menu) for
3462 * copying and modifying.
3463 *
3464 * Parameters
3465 * hWnd
3466 * Handle to the window that will own a copy of the window menu.
3467 * bRevert
3468 * Specifies the action to be taken. If this parameter is FALSE,
3469 * NtUserGetSystemMenu returns a handle to the copy of the window menu
3470 * currently in use. The copy is initially identical to the window menu
3471 * but it can be modified.
3472 * If this parameter is TRUE, GetSystemMenu resets the window menu back
3473 * to the default state. The previous window menu, if any, is destroyed.
3474 *
3475 * Return Value
3476 * If the bRevert parameter is FALSE, the return value is a handle to a
3477 * copy of the window menu. If the bRevert parameter is TRUE, the return
3478 * value is NULL.
3479 *
3480 * Status
3481 * @implemented
3482 */
3483
3484 HMENU APIENTRY
3485 NtUserGetSystemMenu(HWND hWnd, BOOL bRevert)
3486 {
3487 PWINDOW_OBJECT Window;
3488 PMENU_OBJECT Menu;
3489 DECLARE_RETURN(HMENU);
3490
3491 DPRINT("Enter NtUserGetSystemMenu\n");
3492 UserEnterShared();
3493
3494 if (!(Window = UserGetWindowObject(hWnd)))
3495 {
3496 RETURN(NULL);
3497 }
3498
3499 if (!(Menu = IntGetSystemMenu(Window, bRevert, FALSE)))
3500 {
3501 RETURN(NULL);
3502 }
3503
3504 RETURN(Menu->MenuInfo.Self);
3505
3506 CLEANUP:
3507 DPRINT("Leave NtUserGetSystemMenu, ret=%i\n",_ret_);
3508 UserLeave();
3509 END_CLEANUP;
3510 }
3511
3512 /*
3513 * NtUserSetSystemMenu
3514 *
3515 * Status
3516 * @implemented
3517 */
3518
3519 BOOL APIENTRY
3520 NtUserSetSystemMenu(HWND hWnd, HMENU hMenu)
3521 {
3522 BOOL Result = FALSE;
3523 PWINDOW_OBJECT Window;
3524 PMENU_OBJECT Menu;
3525 DECLARE_RETURN(BOOL);
3526
3527 DPRINT("Enter NtUserSetSystemMenu\n");
3528 UserEnterExclusive();
3529
3530 if (!(Window = UserGetWindowObject(hWnd)))
3531 {
3532 RETURN( FALSE);
3533 }
3534
3535 if (hMenu)
3536 {
3537 /*
3538 * Assign new menu handle.
3539 */
3540 if (!(Menu = UserGetMenuObject(hMenu)))
3541 {
3542 RETURN( FALSE);
3543 }
3544
3545 Result = IntSetSystemMenu(Window, Menu);
3546 }
3547
3548 RETURN( Result);
3549
3550 CLEANUP:
3551 DPRINT("Leave NtUserSetSystemMenu, ret=%i\n",_ret_);
3552 UserLeave();
3553 END_CLEANUP;
3554 }
3555
3556 HWND FASTCALL
3557 UserGetWindow(HWND hWnd, UINT Relationship)
3558 {
3559 PWINDOW_OBJECT Parent, Window;
3560 HWND hWndResult = NULL;
3561
3562 if (!(Window = UserGetWindowObject(hWnd)))
3563 return NULL;
3564
3565 switch (Relationship)
3566 {
3567 case GW_HWNDFIRST:
3568 if((Parent = Window->spwndParent))
3569 {
3570 if (Parent->spwndChild)
3571 hWndResult = Parent->spwndChild->hSelf;
3572 }
3573 break;
3574
3575 case GW_HWNDLAST:
3576 if((Parent = Window->spwndParent))
3577 {
3578 if (Parent->spwndChild)
3579 {
3580 Window = Parent->spwndChild;
3581 if(Window)
3582 {
3583 while(Window->spwndNext)
3584 Window = Window->spwndNext;
3585 }
3586 hWndResult = Window->hSelf;
3587 }
3588 }
3589 break;
3590
3591 case GW_HWNDNEXT:
3592 if (Window->spwndNext)
3593 hWndResult = Window->spwndNext->hSelf;
3594 break;
3595
3596 case GW_HWNDPREV:
3597 if (Window->spwndPrev)
3598 hWndResult = Window->spwndPrev->hSelf;
3599 break;
3600
3601 case GW_OWNER:
3602 if((Parent = UserGetWindowObject(Window->hOwner)))
3603 {
3604 hWndResult = Parent->hSelf;
3605 }
3606 break;
3607 case GW_CHILD:
3608 if (Window->spwndChild)
3609 hWndResult = Window->spwndChild->hSelf;
3610 break;
3611 }
3612
3613 return hWndResult;
3614 }
3615
3616 /*
3617 * NtUserGetWindowLong
3618 *
3619 * The NtUserGetWindowLong function retrieves information about the specified
3620 * window. The function also retrieves the 32-bit (long) value at the
3621 * specified offset into the extra window memory.
3622 *
3623 * Status
3624 * @implemented
3625 */
3626
3627 LONG FASTCALL
3628 UserGetWindowLong(HWND hWnd, DWORD Index, BOOL Ansi)
3629 {
3630 PWINDOW_OBJECT Window, Parent;
3631 PWND Wnd;
3632 LONG Result = 0;
3633
3634 DPRINT("NtUserGetWindowLong(%x,%d,%d)\n", hWnd, (INT)Index, Ansi);
3635
3636 if (!(Window = UserGetWindowObject(hWnd)) || !Window->Wnd)
3637 {
3638 return 0;
3639 }
3640
3641 Wnd = Window->Wnd;
3642
3643 /*
3644 * WndProc is only available to the owner process
3645 */
3646 if (GWL_WNDPROC == Index
3647 && Window->pti->pEThread->ThreadsProcess != PsGetCurrentProcess())
3648 {
3649 SetLastWin32Error(ERROR_ACCESS_DENIED);
3650 return 0;
3651 }
3652
3653 if ((INT)Index >= 0)
3654 {
3655 if ((Index + sizeof(LONG)) > Window->Wnd->cbwndExtra)
3656 {
3657 SetLastWin32Error(ERROR_INVALID_PARAMETER);
3658 return 0;
3659 }
3660 Result = *((LONG *)((PCHAR)(Window->Wnd + 1) + Index));
3661 }
3662 else
3663 {
3664 switch (Index)
3665 {
3666 case GWL_EXSTYLE:
3667 Result = Wnd->ExStyle;
3668 break;
3669
3670 case GWL_STYLE:
3671 Result = Wnd->style;
3672 break;
3673
3674 case GWL_WNDPROC:
3675 Result = (LONG)IntGetWindowProc(Wnd, Ansi);
3676 break;
3677
3678 case GWL_HINSTANCE:
3679 Result = (LONG) Wnd->hModule;
3680 break;
3681
3682 case GWL_HWNDPARENT:
3683 Parent = Window->spwndParent;
3684 if(Parent)
3685 {
3686 if (Parent && Parent->hSelf == IntGetDesktopWindow())
3687 Result = (LONG) UserGetWindow(Window->hSelf, GW_OWNER);
3688 else
3689 Result = (LONG) Parent->hSelf;
3690 }
3691 break;
3692
3693 case GWL_ID:
3694 Result = (LONG) Wnd->IDMenu;
3695 break;
3696
3697 case GWL_USERDATA:
3698 Result = Wnd->dwUserData;
3699 break;
3700
3701 default:
3702 DPRINT1("NtUserGetWindowLong(): Unsupported index %d\n", Index);
3703 SetLastWin32Error(ERROR_INVALID_PARAMETER);
3704 Result = 0;
3705 break;
3706 }
3707 }
3708
3709 return Result;
3710 }
3711
3712 LONG FASTCALL
3713 co_UserSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi)
3714 {
3715 PWINDOW_OBJECT Window, Parent;
3716 PWND Wnd;
3717 PWINSTATION_OBJECT WindowStation;
3718 LONG OldValue;
3719 STYLESTRUCT Style;
3720
3721 if (hWnd == IntGetDesktopWindow())
3722 {
3723 SetLastWin32Error(STATUS_ACCESS_DENIED);
3724 return( 0);
3725 }
3726
3727 if (!(Window = UserGetWindowObject(hWnd)))
3728 {
3729 return( 0);
3730 }
3731
3732 Wnd = Window->Wnd;
3733
3734 if (!Wnd) return 0; // No go on zero.
3735
3736 if ((INT)Index >= 0)
3737 {
3738 if ((Index + sizeof(LONG)) > Wnd->cbwndExtra)
3739 {
3740 SetLastWin32Error(ERROR_INVALID_INDEX);
3741 return( 0);
3742 }
3743
3744 OldValue = *((LONG *)((PCHAR)(Wnd + 1) + Index));
3745 /*
3746 if ( Index == DWLP_DLGPROC && Wnd->state & WNDS_DIALOGWINDOW)
3747 {
3748 OldValue = (LONG)IntSetWindowProc( Wnd,
3749 (WNDPROC)NewValue,
3750 Ansi);
3751 if (!OldValue) return 0;
3752 }
3753 */
3754 *((LONG *)((PCHAR)(Wnd + 1) + Index)) = NewValue;
3755 }
3756 else
3757 {
3758 switch (Index)
3759 {
3760 case GWL_EXSTYLE:
3761 OldValue = (LONG) Wnd->ExStyle;
3762 Style.styleOld = OldValue;
3763 Style.styleNew = NewValue;
3764
3765 /*
3766 * Remove extended window style bit WS_EX_TOPMOST for shell windows.
3767 */
3768 WindowStation = Window->pti->rpdesk->rpwinstaParent;
3769 if(WindowStation)
3770 {
3771 if (hWnd == WindowStation->ShellWindow || hWnd == WindowStation->ShellListView)
3772 Style.styleNew &= ~WS_EX_TOPMOST;
3773 }
3774
3775 co_IntSendMessage(hWnd, WM_STYLECHANGING, GWL_EXSTYLE, (LPARAM) &Style);
3776 Wnd->ExStyle = (DWORD)Style.styleNew;
3777 co_IntSendMessage(hWnd, WM_STYLECHANGED, GWL_EXSTYLE, (LPARAM) &Style);
3778 break;
3779
3780 case GWL_STYLE:
3781 OldValue = (LONG) Wnd->style;
3782 Style.styleOld = OldValue;
3783 Style.styleNew = NewValue;
3784 co_IntSendMessage(hWnd, WM_STYLECHANGING, GWL_STYLE, (LPARAM) &Style);
3785 Wnd->style = (DWORD)Style.styleNew;
3786 co_IntSendMessage(hWnd, WM_STYLECHANGED, GWL_STYLE, (LPARAM) &Style);
3787 break;
3788
3789 case GWL_WNDPROC:
3790 {
3791 if ( Wnd->head.pti->ppi != PsGetCurrentProcessWin32Process() ||
3792 Wnd->fnid & FNID_FREED)
3793 {
3794 SetLastWin32Error(ERROR_ACCESS_DENIED);
3795 return( 0);
3796 }
3797 OldValue = (LONG)IntSetWindowProc(Wnd,
3798 (WNDPROC)NewValue,
3799 Ansi);
3800 break;
3801 }
3802
3803 case GWL_HINSTANCE:
3804 OldValue = (LONG) Wnd->hModule;
3805 Wnd->hModule = (HINSTANCE) NewValue;
3806 break;
3807
3808 case GWL_HWNDPARENT:
3809 Parent = Window->spwndParent;
3810 if (Parent && (Parent->hSelf == IntGetDesktopWindow()))
3811 OldValue = (LONG) IntSetOwner(Window->hSelf, (HWND) NewValue);
3812 else
3813 OldValue = (LONG) co_UserSetParent(Window->hSelf, (HWND) NewValue);
3814 break;
3815
3816 case GWL_ID:
3817 OldValue = (LONG) Wnd->IDMenu;
3818 Wnd->IDMenu = (UINT) NewValue;
3819 break;
3820
3821 case GWL_USERDATA:
3822 OldValue = Wnd->dwUserData;
3823 Wnd->dwUserData = NewValue;
3824 break;
3825
3826 default:
3827 DPRINT1("NtUserSetWindowLong(): Unsupported index %d\n", Index);
3828 SetLastWin32Error(ERROR_INVALID_INDEX);
3829 OldValue = 0;
3830 break;
3831 }
3832 }
3833
3834 return( OldValue);
3835 }
3836
3837 /*
3838 * NtUserSetWindowLong
3839 *
3840 * The NtUserSetWindowLong function changes an attribute of the specified
3841 * window. The function also sets the 32-bit (long) value at the specified
3842 * offset into the extra window memory.
3843 *
3844 * Status
3845 * @implemented
3846 */
3847
3848 LONG APIENTRY
3849 NtUserSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi)
3850 {
3851 DECLARE_RETURN(LONG);
3852
3853 DPRINT("Enter NtUserSetWindowLong\n");
3854 UserEnterExclusive();
3855
3856 RETURN( co_UserSetWindowLong(hWnd, Index, NewValue, Ansi));
3857
3858 CLEANUP:
3859 DPRINT("Leave NtUserSetWindowLong, ret=%i\n",_ret_);
3860 UserLeave();
3861 END_CLEANUP;
3862 }
3863
3864 /*
3865 * NtUserSetWindowWord
3866 *
3867 * Legacy function similar to NtUserSetWindowLong.
3868 *
3869 * Status
3870 * @implemented
3871 */
3872
3873 WORD APIENTRY
3874 NtUserSetWindowWord(HWND hWnd, INT Index, WORD NewValue)
3875 {
3876 PWINDOW_OBJECT Window;
3877 WORD OldValue;
3878 DECLARE_RETURN(WORD);
3879
3880 DPRINT("Enter NtUserSetWindowWord\n");
3881 UserEnterExclusive();
3882
3883 if (!(Window = UserGetWindowObject(hWnd)))
3884 {
3885 RETURN( 0);
3886 }
3887
3888 switch (Index)
3889 {
3890 case GWL_ID:
3891 case GWL_HINSTANCE:
3892 case GWL_HWNDPARENT:
3893 RETURN( co_UserSetWindowLong(Window->hSelf, Index, (UINT)NewValue, TRUE));
3894 default:
3895 if (Index < 0)
3896 {
3897 SetLastWin32Error(ERROR_INVALID_INDEX);
3898 RETURN( 0);
3899 }
3900 }
3901
3902 if (Index > Window->Wnd->cbwndExtra - sizeof(WORD))
3903 {
3904 SetLastWin32Error(ERROR_INVALID_PARAMETER);
3905 RETURN( 0);
3906 }
3907
3908 OldValue = *((WORD *)((PCHAR)(Window->Wnd + 1) + Index));
3909 *((WORD *)((PCHAR)(Window->Wnd + 1) + Index)) = NewValue;
3910
3911 RETURN( OldValue);
3912
3913 CLEANUP:
3914 DPRINT("Leave NtUserSetWindowWord, ret=%i\n",_ret_);
3915 UserLeave();
3916 END_CLEANUP;
3917 }
3918
3919 /*
3920 * @implemented
3921 */
3922 BOOL APIENTRY
3923 NtUserGetWindowPlacement(HWND hWnd,
3924 WINDOWPLACEMENT *lpwndpl)
3925 {
3926 PWINDOW_OBJECT Window;
3927 PWND Wnd;
3928 POINT Size;
3929 WINDOWPLACEMENT Safepl;
3930 NTSTATUS Status;
3931 DECLARE_RETURN(BOOL);
3932
3933 DPRINT("Enter NtUserGetWindowPlacement\n");
3934 UserEnterShared();
3935
3936 if (!(Window = UserGetWindowObject(hWnd)))
3937 {
3938 RETURN( FALSE);
3939 }
3940 Wnd = Window->Wnd;
3941
3942 Status = MmCopyFromCaller(&Safepl, lpwndpl, sizeof(WINDOWPLACEMENT));
3943 if(!NT_SUCCESS(Status))
3944 {
3945 SetLastNtError(Status);
3946 RETURN( FALSE);
3947 }
3948 if(Safepl.length != sizeof(WINDOWPLACEMENT))
3949 {
3950 RETURN( FALSE);
3951 }
3952
3953 Safepl.flags = 0;
3954 if (0 == (Wnd->style & WS_VISIBLE))
3955 {
3956 Safepl.showCmd = SW_HIDE;
3957 }
3958 else if ((0 != (Window->state & WINDOWOBJECT_RESTOREMAX) ||
3959 0 != (Wnd->style & WS_MAXIMIZE)) &&
3960 0 == (Wnd->style & WS_MINIMIZE))
3961 {
3962 Safepl.showCmd = SW_SHOWMAXIMIZED;
3963 }
3964 else if (0 != (Wnd->style & WS_MINIMIZE))
3965 {
3966 Safepl.showCmd = SW_SHOWMINIMIZED;
3967 }
3968 else if (0 != (Wnd->style & WS_VISIBLE))
3969 {
3970 Safepl.showCmd = SW_SHOWNORMAL;
3971 }
3972
3973 Size.x = Wnd->rcWindow.left;
3974 Size.y = Wnd->rcWindow.top;
3975 WinPosInitInternalPos(Window, &Size,
3976 &Wnd->rcWindow);
3977
3978 Safepl.rcNormalPosition = Wnd->InternalPos.NormalRect;
3979 Safepl.ptMinPosition = Wnd->InternalPos.IconPos;
3980 Safepl.ptMaxPosition = Wnd->InternalPos.MaxPos;
3981
3982 Status = MmCopyToCaller(lpwndpl, &Safepl, sizeof(WINDOWPLACEMENT));
3983 if(!NT_SUCCESS(Status))
3984 {
3985 SetLastNtError(Status);
3986 RETURN( FALSE);
3987 }
3988
3989 RETURN( TRUE);
3990
3991 CLEANUP:
3992 DPRINT("Leave NtUserGetWindowPlacement, ret=%i\n",_ret_);
3993 UserLeave();
3994 END_CLEANUP;
3995 }
3996
3997
3998 /*
3999 * @unimplemented
4000 */
4001 BOOL APIENTRY
4002 NtUserLockWindowUpdate(HWND hWnd)
4003 {
4004 UNIMPLEMENTED
4005
4006 return 0;
4007 }
4008
4009
4010 /*
4011 * @implemented
4012 */
4013 BOOL APIENTRY
4014 NtUserMoveWindow(
4015 HWND hWnd,
4016 int X,
4017 int Y,
4018 int nWidth,
4019 int nHeight,
4020 BOOL bRepaint)
4021 {
4022 return NtUserSetWindowPos(hWnd, 0, X, Y, nWidth, nHeight,
4023 (bRepaint ? SWP_NOZORDER | SWP_NOACTIVATE :
4024 SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW));
4025 }
4026
4027 /*
4028 QueryWindow based on KJK::Hyperion and James Tabor.
4029
4030 0 = QWUniqueProcessId
4031 1 = QWUniqueThreadId
4032 2 = QWActiveWindow
4033 3 = QWFocusWindow
4034 4 = QWIsHung Implements IsHungAppWindow found
4035 by KJK::Hyperion.
4036
4037 9 = QWKillWindow When I called this with hWnd ==
4038 DesktopWindow, it shutdown the system
4039 and rebooted.
4040 */
4041 /*
4042 * @implemented
4043 */
4044 DWORD APIENTRY
4045 NtUserQueryWindow(HWND hWnd, DWORD Index)
4046 {
4047 PWINDOW_OBJECT Window;
4048 PWND pWnd;
4049 DWORD Result;
4050 DECLARE_RETURN(UINT);
4051
4052 DPRINT("Enter NtUserQueryWindow\n");
4053 UserEnterShared();
4054
4055 if (!(Window = UserGetWindowObject(hWnd)) || !Window->Wnd)
4056 {
4057 RETURN( 0);
4058 }
4059
4060 pWnd = Window->Wnd;
4061
4062 switch(Index)
4063 {
4064 case QUERY_WINDOW_UNIQUE_PROCESS_ID:
4065 Result = (DWORD)IntGetWndProcessId(Window);
4066 break;
4067
4068 case QUERY_WINDOW_UNIQUE_THREAD_ID:
4069 Result = (DWORD)IntGetWndThreadId(Window);
4070 break;
4071
4072 case QUERY_WINDOW_ACTIVE:
4073 Result = (DWORD)UserGetActiveWindow();
4074 break;
4075
4076 case QUERY_WINDOW_FOCUS:
4077 Result = (DWORD)IntGetFocusWindow();
4078 break;
4079
4080 case QUERY_WINDOW_ISHUNG:
4081 Result = (DWORD)MsqIsHung(Window->pti->MessageQueue);
4082 break;
4083
4084 case QUERY_WINDOW_REAL_ID:
4085 Result = (DWORD)pWnd->head.pti->pEThread->Cid.UniqueProcess;
4086
4087 default:
4088 Result = (DWORD)NULL;
4089 break;
4090 }
4091
4092 RETURN( Result);
4093
4094 CLEANUP:
4095 DPRINT("Leave NtUserQueryWindow, ret=%i\n",_ret_);
4096 UserLeave();
4097 END_CLEANUP;
4098 }
4099
4100
4101 /*
4102 * @unimplemented
4103 */
4104 DWORD APIENTRY
4105 NtUserRealChildWindowFromPoint(DWORD Unknown0,
4106 DWORD Unknown1,
4107 DWORD Unknown2)
4108 {
4109 UNIMPLEMENTED
4110
4111 return 0;
4112 }
4113
4114
4115 /*
4116 * @implemented
4117 */
4118 UINT APIENTRY
4119 NtUserRegisterWindowMessage(PUNICODE_STRING MessageNameUnsafe)
4120 {
4121 UNICODE_STRING SafeMessageName;
4122 NTSTATUS Status;
4123 UINT Ret;
4124 DECLARE_RETURN(UINT);
4125
4126 DPRINT("Enter NtUserRegisterWindowMessage\n");
4127 UserEnterExclusive();
4128
4129 if(MessageNameUnsafe == NULL)
4130 {
4131 SetLastWin32Error(ERROR_INVALID_PARAMETER);
4132 RETURN( 0);
4133 }
4134
4135 Status = IntSafeCopyUnicodeStringTerminateNULL(&SafeMessageName, MessageNameUnsafe);
4136 if(!NT_SUCCESS(Status))
4137 {
4138 SetLastNtError(Status);
4139 RETURN( 0);
4140 }
4141
4142 Ret = (UINT)IntAddAtom(SafeMessageName.Buffer);
4143 if (SafeMessageName.Buffer)
4144 ExFreePoolWithTag(SafeMessageName.Buffer, TAG_STRING);
4145 RETURN( Ret);
4146
4147 CLEANUP:
4148 DPRINT("Leave NtUserRegisterWindowMessage, ret=%i\n",_ret_);
4149 UserLeave();
4150 END_CLEANUP;
4151 }
4152
4153
4154 /*
4155 * @unimplemented
4156 */
4157 DWORD APIENTRY
4158 NtUserSetImeOwnerWindow(DWORD Unknown0,
4159 DWORD Unknown1)
4160 {
4161 UNIMPLEMENTED
4162
4163 return 0;
4164 }
4165
4166
4167 /*
4168 * @unimplemented
4169 */
4170 DWORD APIENTRY
4171 NtUserSetInternalWindowPos(
4172 HWND hwnd,
4173 UINT showCmd,
4174 LPRECT rect,
4175 LPPOINT pt)
4176 {
4177 UNIMPLEMENTED
4178
4179 return 0;
4180
4181 }
4182
4183
4184 /*
4185 * @unimplemented
4186 */
4187 BOOL APIENTRY
4188 NtUserSetLayeredWindowAttributes(HWND hwnd,
4189 COLORREF crKey,
4190 BYTE bAlpha,
4191 DWORD dwFlags)
4192 {
4193 UNIMPLEMENTED;
4194 return FALSE;
4195 }
4196
4197
4198 /*
4199 * @unimplemented
4200 */
4201 BOOL APIENTRY
4202 NtUserSetLogonNotifyWindow(HWND hWnd)
4203 {
4204 UNIMPLEMENTED
4205
4206 return 0;
4207 }
4208
4209
4210 /*
4211 * @implemented
4212 */
4213 BOOL APIENTRY
4214 NtUserSetMenu(
4215 HWND hWnd,
4216 HMENU Menu,
4217 BOOL Repaint)
4218 {
4219 PWINDOW_OBJECT Window;
4220 BOOL Changed;
4221 DECLARE_RETURN(BOOL);
4222
4223 DPRINT("Enter NtUserSetMenu\n");
4224 UserEnterExclusive();
4225
4226 if (!(Window = UserGetWindowObject(hWnd)))
4227 {
4228 RETURN( FALSE);
4229 }
4230
4231 if (! IntSetMenu(Window, Menu, &Changed))
4232 {
4233 RETURN( FALSE);
4234 }
4235
4236 if (Changed && Repaint)
4237 {
4238 USER_REFERENCE_ENTRY Ref;
4239
4240 UserRefObjectCo(Window, &Ref);
4241 co_WinPosSetWindowPos(Window, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
4242 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED);
4243
4244 UserDerefObjectCo(Window);
4245 }
4246
4247 RETURN( TRUE);
4248
4249 CLEANUP:
4250 DPRINT("Leave NtUserSetMenu, ret=%i\n",_ret_);
4251 UserLeave();
4252 END_CLEANUP;
4253 }
4254
4255
4256 /*
4257 * @implemented
4258 */
4259 BOOL APIENTRY
4260 NtUserSetWindowFNID(HWND hWnd,
4261 WORD fnID)
4262 {
4263 PWINDOW_OBJECT Window;
4264 PWND Wnd;
4265 DECLARE_RETURN(BOOL);
4266
4267 DPRINT("Enter NtUserSetWindowFNID\n");
4268 UserEnterExclusive();
4269
4270 if (!(Window = UserGetWindowObject(hWnd)))
4271 {
4272 RETURN( FALSE);
4273 }
4274 Wnd = Window->Wnd;
4275
4276 if (Wnd->pcls)
4277 { // From user land we only set these.
4278 if ((fnID != FNID_DESTROY) || ((fnID < FNID_BUTTON) && (fnID > FNID_IME)) )
4279 {
4280 RETURN( FALSE);
4281 }
4282 else
4283 Wnd->pcls->fnid |= fnID;
4284 }
4285 RETURN( TRUE);
4286
4287 CLEANUP:
4288 DPRINT("Leave NtUserSetWindowFNID\n");
4289 UserLeave();
4290 END_CLEANUP;
4291 }
4292
4293
4294 /*
4295 * @implemented
4296 */
4297 BOOL APIENTRY
4298 NtUserSetWindowPlacement(HWND hWnd,
4299 WINDOWPLACEMENT *lpwndpl)
4300 {
4301 PWINDOW_OBJECT Window;
4302 PWND Wnd;
4303 WINDOWPLACEMENT Safepl;
4304 NTSTATUS Status;
4305 DECLARE_RETURN(BOOL);
4306 USER_REFERENCE_ENTRY Ref;
4307
4308 DPRINT("Enter NtUserSetWindowPlacement\n");
4309 UserEnterExclusive();
4310
4311 if (!(Window = UserGetWindowObject(hWnd)))
4312 {
4313 RETURN( FALSE);
4314 }
4315 Wnd = Window->Wnd;
4316
4317 Status = MmCopyFromCaller(&Safepl, lpwndpl, sizeof(WINDOWPLACEMENT));
4318 if(!NT_SUCCESS(Status))
4319 {
4320 SetLastNtError(Status);
4321 RETURN( FALSE);
4322 }
4323 if(Safepl.length != sizeof(WINDOWPLACEMENT))
4324 {
4325 RETURN( FALSE);
4326 }
4327
4328 UserRefObjectCo(Window, &Ref);
4329
4330 if ((Wnd->style & (WS_MAXIMIZE | WS_MINIMIZE)) == 0)
4331 {
4332 co_WinPosSetWindowPos(Window, NULL,
4333 Safepl.rcNormalPosition.left, Safepl.rcNormalPosition.top,
4334 Safepl.rcNormalPosition.right - Safepl.rcNormalPosition.left,
4335 Safepl.rcNormalPosition.bottom - Safepl.rcNormalPosition.top,
4336 SWP_NOZORDER | SWP_NOACTIVATE);
4337 }
4338
4339 /* FIXME - change window status */
4340 co_WinPosShowWindow(Window, Safepl.showCmd);
4341
4342 Wnd->InternalPosInitialized = TRUE;
4343 Wnd->InternalPos.NormalRect = Safepl.rcNormalPosition;
4344 Wnd->InternalPos.IconPos = Safepl.ptMinPosition;
4345 Wnd->InternalPos.MaxPos = Safepl.ptMaxPosition;
4346
4347 UserDerefObjectCo(Window);
4348 RETURN(TRUE);
4349
4350 CLEANUP:
4351 DPRINT("Leave NtUserSetWindowPlacement, ret=%i\n",_ret_);
4352 UserLeave();
4353 END_CLEANUP;
4354 }
4355
4356
4357 /*
4358 * @implemented
4359 */
4360 BOOL APIENTRY
4361 NtUserSetWindowPos(
4362 HWND hWnd,
4363 HWND hWndInsertAfter,
4364 int X,
4365 int Y,
4366 int cx,
4367 int cy,
4368 UINT uFlags)
4369 {
4370 DECLARE_RETURN(BOOL);
4371 PWINDOW_OBJECT Window;
4372 BOOL ret;
4373 USER_REFERENCE_ENTRY Ref;
4374
4375 DPRINT("Enter NtUserSetWindowPos\n");
4376 UserEnterExclusive();
4377
4378 if (!(Window = UserGetWindowObject(hWnd)))
4379 {
4380 RETURN(FALSE);
4381 }
4382
4383 /* First make sure that coordinates are valid for WM_WINDOWPOSCHANGING */
4384 if (!(uFlags & SWP_NOMOVE))
4385 {
4386 if (X < -32768) X = -32768;
4387 else if (X > 32767) X = 32767;
4388 if (Y < -32768) Y = -32768;
4389 else if (Y > 32767) Y = 32767;
4390 }
4391 if (!(uFlags & SWP_NOSIZE))
4392 {
4393 if (cx < 0) cx = 0;
4394 else if (cx > 32767) cx = 32767;
4395 if (cy < 0) cy = 0;
4396 else if (cy > 32767) cy = 32767;
4397 }
4398
4399 UserRefObjectCo(Window, &Ref);
4400 ret = co_WinPosSetWindowPos(Window, hWndInsertAfter, X, Y, cx, cy, uFlags);
4401 UserDerefObjectCo(Window);
4402
4403 RETURN(ret);
4404
4405 CLEANUP:
4406 DPRINT("Leave NtUserSetWindowPos, ret=%i\n",_ret_);
4407 UserLeave();
4408 END_CLEANUP;
4409 }
4410
4411
4412 INT FASTCALL
4413 IntGetWindowRgn(PWINDOW_OBJECT Window, HRGN hRgn)
4414 {
4415 INT Ret;
4416 HRGN VisRgn;
4417 ROSRGNDATA *pRgn;
4418 PWND Wnd;
4419
4420 if(!Window)
4421 {
4422 return ERROR;
4423 }
4424 if(!hRgn)
4425 {
4426 return ERROR;
4427 }
4428
4429 Wnd = Window->Wnd;
4430
4431 /* Create a new window region using the window rectangle */
4432 VisRgn = IntSysCreateRectRgnIndirect(&Window->Wnd->rcWindow);
4433 NtGdiOffsetRgn(VisRgn, -Window->Wnd->rcWindow.left, -Window->Wnd->rcWindow.top);
4434 /* if there's a region assigned to the window, combine them both */
4435 if(Window->hrgnClip && !(Wnd->style & WS_MINIMIZE))
4436 NtGdiCombineRgn(VisRgn, VisRgn, Window->hrgnClip, RGN_AND);
4437 /* Copy the region into hRgn */
4438 NtGdiCombineRgn(hRgn, VisRgn, NULL, RGN_COPY);
4439
4440 if((pRgn = RGNOBJAPI_Lock(hRgn, NULL)))
4441 {
4442 Ret = pRgn->rdh.iType;
4443 RGNOBJAPI_Unlock(pRgn);
4444 }
4445 else
4446 Ret = ERROR;
4447
4448 REGION_FreeRgnByHandle(VisRgn);
4449
4450 return Ret;
4451 }
4452
4453 INT FASTCALL
4454 IntGetWindowRgnBox(PWINDOW_OBJECT Window, RECTL *Rect)
4455 {
4456 INT Ret;
4457 HRGN VisRgn;
4458 ROSRGNDATA *pRgn;
4459 PWND Wnd;
4460
4461 if(!Window)
4462 {
4463 return ERROR;
4464 }
4465 if(!Rect)
4466 {
4467 return ERROR;
4468 }
4469
4470 Wnd = Window->Wnd;
4471
4472 /* Create a new window region using the window rectangle */
4473 VisRgn = IntSysCreateRectRgnIndirect(&Window->Wnd->rcWindow);
4474 NtGdiOffsetRgn(VisRgn, -Window->Wnd->rcWindow.left, -Window->Wnd->rcWindow.top);
4475 /* if there's a region assigned to the window, combine them both */
4476 if(Window->hrgnClip && !(Wnd->style & WS_MINIMIZE))
4477 NtGdiCombineRgn(VisRgn, VisRgn, Window->hrgnClip, RGN_AND);
4478
4479 if((pRgn = RGNOBJAPI_Lock(VisRgn, NULL)))
4480 {
4481 Ret = pRgn->rdh.iType;
4482 *Rect = pRgn->rdh.rcBound;
4483 RGNOBJAPI_Unlock(pRgn);
4484 }
4485 else
4486 Ret = ERROR;
4487
4488 REGION_FreeRgnByHandle(VisRgn);
4489
4490 return Ret;
4491 }
4492
4493
4494 /*
4495 * @implemented
4496 */
4497 INT APIENTRY
4498 NtUserSetWindowRgn(
4499 HWND hWnd,
4500 HRGN hRgn,
4501 BOOL bRedraw)
4502 {
4503 HRGN hrgnCopy;
4504 PWINDOW_OBJECT Window;
4505 DECLARE_RETURN(INT);
4506
4507 DPRINT("Enter NtUserSetWindowRgn\n");
4508 UserEnterExclusive();
4509
4510 if (!(Window = UserGetWindowObject(hWnd)))
4511 {
4512 RETURN( 0);
4513 }
4514
4515 if (hRgn) // The region will be deleted in user32.
4516 {
4517 if (GDIOBJ_ValidateHandle(hRgn, GDI_OBJECT_TYPE_REGION))
4518 {
4519 hrgnCopy = IntSysCreateRectRgn(0, 0, 0, 0);
4520 NtGdiCombineRgn(hrgnCopy, hRgn, 0, RGN_COPY);
4521 }
4522 else
4523 RETURN( 0);
4524 }
4525 else
4526 hrgnCopy = (HRGN) 1;
4527
4528 if (Window->hrgnClip)
4529 {
4530 /* Delete no longer needed region handle */
4531 GreDeleteObject(Window->hrgnClip);
4532 }
4533 Window->hrgnClip = hrgnCopy;
4534
4535 /* FIXME - send WM_WINDOWPOSCHANGING and WM_WINDOWPOSCHANGED messages to the window */
4536
4537 if(bRedraw)
4538 {
4539 USER_REFERENCE_ENTRY Ref;
4540 UserRefObjectCo(Window, &Ref);
4541 co_UserRedrawWindow(Window, NULL, NULL, RDW_INVALIDATE);
4542 UserDerefObjectCo(Window);
4543 }
4544
4545 RETURN( (INT)hRgn);
4546
4547 CLEANUP:
4548 DPRINT("Leave NtUserSetWindowRgn, ret=%i\n",_ret_);
4549 UserLeave();
4550 END_CLEANUP;
4551 }
4552
4553
4554 /*
4555 * @implemented
4556 */
4557 BOOL APIENTRY
4558 NtUserShowWindow(HWND hWnd, LONG nCmdShow)
4559 {
4560 PWINDOW_OBJECT Window;
4561 BOOL ret;
4562 DECLARE_RETURN(BOOL);
4563 USER_REFERENCE_ENTRY Ref;
4564
4565 DPRINT("Enter NtUserShowWindow\n");
4566 UserEnterExclusive();
4567
4568 if (!(Window = UserGetWindowObject(hWnd)))
4569 {
4570 RETURN(FALSE);
4571 }
4572
4573 UserRefObjectCo(Window, &Ref);
4574 ret = co_WinPosShowWindow(Window, nCmdShow);
4575 UserDerefObjectCo(Window);
4576
4577 RETURN(ret);
4578
4579 CLEANUP:
4580 DPRINT("Leave NtUserShowWindow, ret=%i\n",_ret_);
4581 UserLeave();
4582 END_CLEANUP;
4583 }
4584
4585
4586 /*
4587 * @unimplemented
4588 */
4589 BOOL APIENTRY
4590 NtUserShowWindowAsync(HWND hWnd, LONG nCmdShow)
4591 {
4592 #if 0
4593 UNIMPLEMENTED
4594 return 0;
4595 #else
4596 return NtUserShowWindow(hWnd, nCmdShow);
4597 #endif
4598 }
4599
4600
4601 /*
4602 * @unimplemented
4603 */
4604 BOOL
4605 APIENTRY
4606 NtUserUpdateLayeredWindow(
4607 HWND hwnd,
4608 HDC hdcDst,
4609 POINT *pptDst,
4610 SIZE *psize,
4611 HDC hdcSrc,
4612 POINT *pptSrc,
4613 COLORREF crKey,
4614 BLENDFUNCTION *pblend,
4615 DWORD dwFlags,
4616 RECT *prcDirty)
4617 {
4618 UNIMPLEMENTED
4619
4620 return 0;
4621 }
4622
4623 /*
4624 * @unimplemented
4625 */
4626 HWND APIENTRY
4627 NtUserWindowFromPhysicalPoint(POINT Point)
4628 {
4629 UNIMPLEMENTED
4630
4631 return NULL;
4632 }
4633
4634 /*
4635 * @implemented
4636 */
4637 HWND APIENTRY
4638 NtUserWindowFromPoint(LONG X, LONG Y)
4639 {
4640 POINT pt;
4641 HWND Ret;
4642 PWINDOW_OBJECT DesktopWindow = NULL, Window = NULL;
4643 DECLARE_RETURN(HWND);
4644 USER_REFERENCE_ENTRY Ref;
4645
4646 DPRINT("Enter NtUserWindowFromPoint\n");
4647 UserEnterExclusive();
4648
4649 if ((DesktopWindow = UserGetWindowObject(IntGetDesktopWindow())))
4650 {
4651 PTHREADINFO pti;
4652 USHORT Hit;
4653
4654 pt.x = X;
4655 pt.y = Y;
4656
4657 //hmm... threads live on desktops thus we have a reference on the desktop and indirectly the desktop window
4658 //its possible this referencing is useless, thou it shouldnt hurt...
4659 UserRefObjectCo(DesktopWindow, &Ref);
4660
4661 pti = PsGetCurrentThreadWin32Thread();
4662 Hit = co_WinPosWindowFromPoint(DesktopWindow, pti->MessageQueue, &pt, &Window);
4663
4664 if(Window)
4665 {
4666 Ret = Window->hSelf;
4667
4668 RETURN( Ret);
4669 }
4670 }
4671
4672 RETURN( NULL);
4673
4674 CLEANUP:
4675 if (Window) UserDereferenceObject(Window);
4676 if (DesktopWindow) UserDerefObjectCo(DesktopWindow);
4677
4678 DPRINT("Leave NtUserWindowFromPoint, ret=%i\n",_ret_);
4679 UserLeave();
4680 END_CLEANUP;
4681
4682 }
4683
4684
4685 /*
4686 * NtUserDefSetText
4687 *
4688 * Undocumented function that is called from DefWindowProc to set
4689 * window text.
4690 *
4691 * Status
4692 * @implemented
4693 */
4694 BOOL APIENTRY
4695 NtUserDefSetText(HWND hWnd, PLARGE_STRING WindowText)
4696 {
4697 PWINDOW_OBJECT Window;
4698 PWND Wnd;
4699 LARGE_STRING SafeText;
4700 UNICODE_STRING UnicodeString;
4701 BOOL Ret = TRUE;
4702
4703 DPRINT("Enter NtUserDefSetText\n");
4704
4705 if (WindowText != NULL)
4706 {
4707 _SEH2_TRY
4708 {
4709 SafeText = ProbeForReadLargeString(WindowText);
4710 }
4711 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4712 {
4713 Ret = FALSE;
4714 SetLastNtError(_SEH2_GetExceptionCode());
4715 }
4716 _SEH2_END;
4717
4718 if (!Ret)
4719 return FALSE;
4720 }
4721 else
4722 return TRUE;
4723
4724 UserEnterExclusive();
4725
4726 if(!(Window = UserGetWindowObject(hWnd)) || !Window->Wnd)
4727 {
4728 UserLeave();
4729 return FALSE;
4730 }
4731 Wnd = Window->Wnd;
4732
4733 // ReactOS uses Unicode and not mixed. Up/Down converting will take time.
4734 // Brought to you by: The Wine Project! Dysfunctional Thought Processes!
4735 // Now we know what the bAnsi is for.
4736 RtlInitUnicodeString(&UnicodeString, NULL);
4737 if (SafeText.Buffer)
4738 {
4739 _SEH2_TRY
4740 {
4741 if (SafeText.bAnsi)
4742 ProbeForRead(SafeText.Buffer, SafeText.Length, sizeof(CHAR));
4743 else
4744 ProbeForRead(SafeText.Buffer, SafeText.Length, sizeof(WCHAR));
4745 Ret = RtlLargeStringToUnicodeString(&UnicodeString, &SafeText);
4746 }
4747 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4748 {
4749 Ret = FALSE;
4750 SetLastNtError(_SEH2_GetExceptionCode());
4751 }
4752 _SEH2_END;
4753 if (!Ret) goto Exit;
4754 }
4755
4756 if (UnicodeString.Length != 0)
4757 {
4758 if (Wnd->strName.MaximumLength > 0 &&
4759 UnicodeString.Length <= Wnd->strName.MaximumLength - sizeof(UNICODE_NULL))
4760 {
4761 ASSERT(Wnd->strName.Buffer != NULL);
4762
4763 Wnd->strName.Length = UnicodeString.Length;
4764 Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0';
4765 RtlCopyMemory(Wnd->strName.Buffer,
4766 UnicodeString.Buffer,
4767 UnicodeString.Length);
4768 }
4769 else
4770 {
4771 PWCHAR buf;
4772 Wnd->strName.MaximumLength = Wnd->strName.Length = 0;
4773 buf = Wnd->strName.Buffer;
4774 Wnd->strName.Buffer = NULL;
4775 if (buf != NULL)
4776 {
4777 DesktopHeapFree(Wnd->head.rpdesk, buf);
4778 }
4779
4780 Wnd->strName.Buffer = DesktopHeapAlloc(Wnd->head.rpdesk,
4781 UnicodeString.Length + sizeof(UNICODE_NULL));
4782 if (Wnd->strName.Buffer != NULL)
4783 {
4784 Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0';
4785 RtlCopyMemory(Wnd->strName.Buffer,
4786 UnicodeString.Buffer,
4787 UnicodeString.Length);
4788 Wnd->strName.MaximumLength = UnicodeString.Length + sizeof(UNICODE_NULL);
4789 Wnd->strName.Length = UnicodeString.Length;
4790 }
4791 else
4792 {
4793 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
4794 Ret = FALSE;
4795 goto Exit;
4796 }
4797 }
4798 }
4799 else
4800 {
4801 Wnd->strName.Length = 0;
4802 if (Wnd->strName.Buffer != NULL)
4803 Wnd->strName.Buffer[0] = L'\0';
4804 }
4805
4806 // HAX! FIXME! Windows does not do this in here!
4807 // In User32, these are called after: NotifyWinEvent EVENT_OBJECT_NAMECHANGE than
4808 // RepaintButton, StaticRepaint, NtUserCallHwndLock HWNDLOCK_ROUTINE_REDRAWFRAMEANDHOOK, etc.
4809 /* Send shell notifications */
4810 if (!IntGetOwner(Window) && !IntGetParent(Window))
4811 {
4812 co_IntShellHookNotify(HSHELL_REDRAW, (LPARAM) hWnd);
4813 }
4814
4815 Ret = TRUE;
4816 Exit:
4817 if (UnicodeString.Buffer) RtlFreeUnicodeString(&UnicodeString);
4818 DPRINT("Leave NtUserDefSetText, ret=%i\n", Ret);
4819 UserLeave();
4820 return Ret;
4821 }
4822
4823 /*
4824 * NtUserInternalGetWindowText
4825 *
4826 * Status
4827 * @implemented
4828 */
4829
4830 INT APIENTRY
4831 NtUserInternalGetWindowText(HWND hWnd, LPWSTR lpString, INT nMaxCount)
4832 {
4833 PWINDOW_OBJECT Window;
4834 PWND Wnd;
4835 NTSTATUS Status;
4836 INT Result;
4837 DECLARE_RETURN(INT);
4838
4839 DPRINT("Enter NtUserInternalGetWindowText\n");
4840 UserEnterShared();
4841
4842 if(lpString && (nMaxCount <= 1))
4843 {
4844 SetLastWin32Error(ERROR_INVALID_PARAMETER);
4845 RETURN( 0);
4846 }
4847
4848 if(!(Window = UserGetWindowObject(hWnd)))
4849 {
4850 RETURN( 0);
4851 }
4852 Wnd = Window->Wnd;
4853
4854 Result = Wnd->strName.Length / sizeof(WCHAR);
4855 if(lpString)
4856 {
4857 const WCHAR Terminator = L'\0';
4858 INT Copy;
4859 WCHAR *Buffer = (WCHAR*)lpString;
4860
4861 Copy = min(nMaxCount - 1, Result);
4862 if(Copy > 0)
4863 {
4864 Status = MmCopyToCaller(Buffer, Wnd->strName.Buffer, Copy * sizeof(WCHAR));
4865 if(!NT_SUCCESS(Status))
4866 {
4867 SetLastNtError(Status);
4868 RETURN( 0);
4869 }
4870 Buffer += Copy;
4871 }
4872
4873 Status = MmCopyToCaller(Buffer, &Terminator, sizeof(WCHAR));
4874 if(!NT_SUCCESS(Status))
4875 {
4876 SetLastNtError(Status);
4877 RETURN( 0);
4878 }
4879
4880 Result = Copy;
4881 }
4882
4883 RETURN( Result);
4884
4885 CLEANUP:
4886 DPRINT("Leave NtUserInternalGetWindowText, ret=%i\n",_ret_);
4887 UserLeave();
4888 END_CLEANUP;
4889 }
4890
4891
4892 BOOL
4893 FASTCALL
4894 IntShowOwnedPopups(PWINDOW_OBJECT OwnerWnd, BOOL fShow )
4895 {
4896 int count = 0;
4897 PWINDOW_OBJECT pWnd;
4898 HWND *win_array;
4899
4900 // ASSERT(OwnerWnd);
4901
4902 win_array = IntWinListChildren(UserGetWindowObject(IntGetDesktopWindow()));
4903
4904 if (!win_array)
4905 return TRUE;
4906
4907 while (win_array[count])
4908 count++;
4909 while (--count >= 0)
4910 {
4911 if (UserGetWindow( win_array[count], GW_OWNER ) != OwnerWnd->hSelf)
4912 continue;
4913 if (!(pWnd = UserGetWindowObject( win_array[count] )))
4914 continue;
4915 // if (pWnd == WND_OTHER_PROCESS) continue;
4916
4917 if (fShow)
4918 {
4919 if (pWnd->Wnd->state & WNDS_HIDDENPOPUP)
4920 {
4921 /* In Windows, ShowOwnedPopups(TRUE) generates
4922 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
4923 * regardless of the state of the owner
4924 */
4925 co_IntSendMessage(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
4926 continue;
4927 }
4928 }
4929 else
4930 {
4931 if (pWnd->Wnd->style & WS_VISIBLE)
4932 {
4933 /* In Windows, ShowOwnedPopups(FALSE) generates
4934 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
4935 * regardless of the state of the owner
4936 */
4937 co_IntSendMessage(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
4938 continue;
4939 }
4940 }
4941
4942 }
4943 ExFreePool( win_array );
4944 return TRUE;
4945 }
4946
4947 /*
4948 * NtUserValidateHandleSecure
4949 *
4950 * Status
4951 * @implemented
4952 */
4953
4954 BOOL
4955 APIENTRY
4956 NtUserValidateHandleSecure(
4957 HANDLE handle,
4958 BOOL Restricted)
4959 {
4960 if(!Restricted)
4961 {
4962 UINT uType;
4963 {
4964 PUSER_HANDLE_ENTRY entry;
4965 if (!(entry = handle_to_entry(gHandleTable, handle )))
4966 {
4967 SetLastWin32Error(ERROR_INVALID_HANDLE);
4968 return FALSE;
4969 }
4970 uType = entry->type;
4971 }
4972 switch (uType)
4973 {
4974 case otWindow:
4975 {
4976 PWINDOW_OBJECT Window;
4977 if ((Window = UserGetWindowObject((HWND) handle))) return TRUE;
4978 return FALSE;
4979 }
4980 case otMenu:
4981 {
4982 PMENU_OBJECT Menu;
4983 if ((Menu = UserGetMenuObject((HMENU) handle))) return TRUE;
4984 return FALSE;
4985 }
4986 case otAccel:
4987 {
4988 PACCELERATOR_TABLE Accel;
4989 if ((Accel = UserGetAccelObject((HACCEL) handle))) return TRUE;
4990 return FALSE;
4991 }
4992 case otCursorIcon:
4993 {
4994 PCURICON_OBJECT Cursor;
4995 if ((Cursor = UserGetCurIconObject((HCURSOR) handle))) return TRUE;
4996 return FALSE;
4997 }
4998 case otHook:
4999 {
5000 PHOOK Hook;
5001 if ((Hook = IntGetHookObject((HHOOK) handle))) return TRUE;
5002 return FALSE;
5003 }
5004 case otMonitor:
5005 {
5006 PMONITOR Monitor;
5007 if ((Monitor = UserGetMonitorObject((HMONITOR) handle))) return TRUE;
5008 return FALSE;
5009 }
5010 case otCallProc:
5011 {
5012 WNDPROC_INFO Proc;
5013 return UserGetCallProcInfo( handle, &Proc );
5014 }
5015 default:
5016 SetLastWin32Error(ERROR_INVALID_HANDLE);
5017 }
5018 }
5019 else
5020 { /* Is handle entry restricted? */
5021 UNIMPLEMENTED
5022 }
5023 return FALSE;
5024 }
5025
5026
5027 /* EOF */