- Create another branch for networking fixes
[reactos.git] / 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 <w32k.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(USER_BODY_TO_HEADER(Window)->RefCount >= 0);
97
98 USER_BODY_TO_HEADER(Window)->RefCount++;
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->Status & WINDOWSTATUS_DESTROYED))
127 {
128 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
129 return NULL;
130 }
131
132 ASSERT(USER_BODY_TO_HEADER(Window)->RefCount >= 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->Parent;
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->FirstChild; Child; Child = Child->NextSibling)
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->FirstChild, Index = 0;
234 Child != NULL;
235 Child = Child->NextSibling, ++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->Status & WINDOWSTATUS_DESTROYING)
369 {
370 DPRINT("Tried to call IntDestroyWindow() twice\n");
371 return 0;
372 }
373 Window->Status |= 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 MsqRemoveTimersWindow(ThreadData->MessageQueue, Window->hSelf);
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->Status |= 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->Desktop)
442 {
443 if (Window->hSelf == ThreadData->Desktop->WindowStation->ShellWindow)
444 ThreadData->Desktop->WindowStation->ShellWindow = NULL;
445
446 if (Window->hSelf == ThreadData->Desktop->WindowStation->ShellListView)
447 ThreadData->Desktop->WindowStation->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->ti->pDeskInfo,
498 Window->ti->ppi);
499 Wnd->pcls = NULL;
500
501 if(Window->WindowRegion)
502 {
503 GreDeleteObject(Window->WindowRegion);
504 }
505
506 ASSERT(Window->Wnd != NULL);
507 UserFreeWindowInfo(Window->ti, 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 (Class->fnid <= FNID_GHOST && Class->fnid >= FNID_BUTTON)
667 {
668 if (Ansi)
669 {
670 if (GETPFNCLIENTW(Class->fnid) == NewWndProc)
671 chWndProc = GETPFNCLIENTA(Class->fnid);
672 }
673 else
674 {
675 if (GETPFNCLIENTA(Class->fnid) == NewWndProc)
676 chWndProc = GETPFNCLIENTW(Class->fnid);
677 }
678 }
679 // Now set the new window proc.
680 pWnd->lpfnWndProc = (chWndProc ? chWndProc : NewWndProc);
681 }
682 return Ret;
683 }
684
685 // Move this to user space!
686 BOOL FASTCALL
687 IntGetWindowInfo(PWINDOW_OBJECT Window, PWINDOWINFO pwi)
688 {
689 PWND Wnd = Window->Wnd;
690
691 pwi->cbSize = sizeof(WINDOWINFO);
692 pwi->rcWindow = Window->Wnd->rcWindow;
693 pwi->rcClient = Window->Wnd->rcClient;
694 pwi->dwStyle = Wnd->style;
695 pwi->dwExStyle = Wnd->ExStyle;
696 pwi->dwWindowStatus = (UserGetForegroundWindow() == Window->hSelf); /* WS_ACTIVECAPTION */
697 IntGetWindowBorderMeasures(Window, &pwi->cxWindowBorders, &pwi->cyWindowBorders);
698 pwi->atomWindowType = (Wnd->pcls ? Wnd->pcls->atomClassName : 0);
699 pwi->wCreatorVersion = 0x400; /* FIXME - return a real version number */
700 return TRUE;
701 }
702
703 static BOOL FASTCALL
704 IntSetMenu(
705 PWINDOW_OBJECT Window,
706 HMENU Menu,
707 BOOL *Changed)
708 {
709 PMENU_OBJECT OldMenu, NewMenu = NULL;
710 PWND Wnd = Window->Wnd;
711
712 if ((Wnd->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
713 {
714 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
715 return FALSE;
716 }
717
718 *Changed = (Wnd->IDMenu != (UINT) Menu);
719 if (! *Changed)
720 {
721 return TRUE;
722 }
723
724 if (Wnd->IDMenu)
725 {
726 OldMenu = IntGetMenuObject((HMENU) Wnd->IDMenu);
727 ASSERT(NULL == OldMenu || OldMenu->MenuInfo.Wnd == Window->hSelf);
728 }
729 else
730 {
731 OldMenu = NULL;
732 }
733
734 if (NULL != Menu)
735 {
736 NewMenu = IntGetMenuObject(Menu);
737 if (NULL == NewMenu)
738 {
739 if (NULL != OldMenu)
740 {
741 IntReleaseMenuObject(OldMenu);
742 }
743 SetLastWin32Error(ERROR_INVALID_MENU_HANDLE);
744 return FALSE;
745 }
746 if (NULL != NewMenu->MenuInfo.Wnd)
747 {
748 /* Can't use the same menu for two windows */
749 if (NULL != OldMenu)
750 {
751 IntReleaseMenuObject(OldMenu);
752 }
753 SetLastWin32Error(ERROR_INVALID_MENU_HANDLE);
754 return FALSE;
755 }
756
757 }
758
759 Wnd->IDMenu = (UINT) Menu;
760 if (NULL != NewMenu)
761 {
762 NewMenu->MenuInfo.Wnd = Window->hSelf;
763 IntReleaseMenuObject(NewMenu);
764 }
765 if (NULL != OldMenu)
766 {
767 OldMenu->MenuInfo.Wnd = NULL;
768 IntReleaseMenuObject(OldMenu);
769 }
770
771 return TRUE;
772 }
773
774
775 /* INTERNAL ******************************************************************/
776
777
778 VOID FASTCALL
779 co_DestroyThreadWindows(struct _ETHREAD *Thread)
780 {
781 PTHREADINFO WThread;
782 PLIST_ENTRY Current;
783 PWINDOW_OBJECT Wnd;
784 USER_REFERENCE_ENTRY Ref;
785 WThread = (PTHREADINFO)Thread->Tcb.Win32Thread;
786
787 while (!IsListEmpty(&WThread->WindowListHead))
788 {
789 Current = WThread->WindowListHead.Flink;
790 Wnd = CONTAINING_RECORD(Current, WINDOW_OBJECT, ThreadListEntry);
791
792 DPRINT("thread cleanup: while destroy wnds, wnd=0x%x\n",Wnd);
793
794 /* window removes itself from the list */
795
796 /*
797 fixme: it is critical that the window removes itself! if now, we will loop
798 here forever...
799 */
800
801 //ASSERT(co_UserDestroyWindow(Wnd));
802
803 UserRefObjectCo(Wnd, &Ref);//faxme: temp hack??
804 if (!co_UserDestroyWindow(Wnd))
805 {
806 DPRINT1("Unable to destroy window 0x%x at thread cleanup... This is _VERY_ bad!\n", Wnd);
807 }
808 UserDerefObjectCo(Wnd);//faxme: temp hack??
809 }
810 }
811
812
813
814 /*!
815 * Internal function.
816 * Returns client window rectangle relative to the upper-left corner of client area.
817 *
818 * \note Does not check the validity of the parameters
819 */
820 VOID FASTCALL
821 IntGetClientRect(PWINDOW_OBJECT Window, RECTL *Rect)
822 {
823 ASSERT( Window );
824 ASSERT( Rect );
825
826 Rect->left = Rect->top = 0;
827 Rect->right = Window->Wnd->rcClient.right - Window->Wnd->rcClient.left;
828 Rect->bottom = Window->Wnd->rcClient.bottom - Window->Wnd->rcClient.top;
829 }
830
831
832 #if 0
833 HWND FASTCALL
834 IntGetFocusWindow(VOID)
835 {
836 PUSER_MESSAGE_QUEUE Queue;
837 PDESKTOP pdo = IntGetActiveDesktop();
838
839 if( !pdo )
840 return NULL;
841
842 Queue = (PUSER_MESSAGE_QUEUE)pdo->ActiveMessageQueue;
843
844 if (Queue == NULL)
845 return(NULL);
846 else
847 return(Queue->FocusWindow);
848 }
849 #endif
850
851 PMENU_OBJECT FASTCALL
852 IntGetSystemMenu(PWINDOW_OBJECT Window, BOOL bRevert, BOOL RetMenu)
853 {
854 PMENU_OBJECT Menu, NewMenu = NULL, SysMenu = NULL, ret = NULL;
855 PTHREADINFO W32Thread;
856 HMENU hNewMenu, hSysMenu;
857 ROSMENUITEMINFO ItemInfo;
858
859 if(bRevert)
860 {
861 W32Thread = PsGetCurrentThreadWin32Thread();
862
863 if(!W32Thread->Desktop)
864 return NULL;
865
866 if(Window->SystemMenu)
867 {
868 Menu = UserGetMenuObject(Window->SystemMenu);
869 if(Menu)
870 {
871 IntDestroyMenuObject(Menu, TRUE, TRUE);
872 Window->SystemMenu = (HMENU)0;
873 }
874 }
875
876 if(W32Thread->Desktop->WindowStation->SystemMenuTemplate)
877 {
878 /* clone system menu */
879 Menu = UserGetMenuObject(W32Thread->Desktop->WindowStation->SystemMenuTemplate);
880 if(!Menu)
881 return NULL;
882
883 NewMenu = IntCloneMenu(Menu);
884 if(NewMenu)
885 {
886 Window->SystemMenu = NewMenu->MenuInfo.Self;
887 NewMenu->MenuInfo.Flags |= MF_SYSMENU;
888 NewMenu->MenuInfo.Wnd = Window->hSelf;
889 ret = NewMenu;
890 //IntReleaseMenuObject(NewMenu);
891 }
892 }
893 else
894 {
895 hSysMenu = UserCreateMenu(FALSE);
896 if (NULL == hSysMenu)
897 {
898 return NULL;
899 }
900 SysMenu = IntGetMenuObject(hSysMenu);
901 if (NULL == SysMenu)
902 {
903 UserDestroyMenu(hSysMenu);
904 return NULL;
905 }
906 SysMenu->MenuInfo.Flags |= MF_SYSMENU;
907 SysMenu->MenuInfo.Wnd = Window->hSelf;
908 hNewMenu = co_IntLoadSysMenuTemplate();
909 if(!hNewMenu)
910 {
911 IntReleaseMenuObject(SysMenu);
912 UserDestroyMenu(hSysMenu);
913 return NULL;
914 }
915 Menu = IntGetMenuObject(hNewMenu);
916 if(!Menu)
917 {
918 IntReleaseMenuObject(SysMenu);
919 UserDestroyMenu(hSysMenu);
920 return NULL;
921 }
922
923 NewMenu = IntCloneMenu(Menu);
924 if(NewMenu)
925 {
926 NewMenu->MenuInfo.Flags |= MF_SYSMENU | MF_POPUP;
927 IntReleaseMenuObject(NewMenu);
928 UserSetMenuDefaultItem(NewMenu, SC_CLOSE, FALSE);
929
930 ItemInfo.cbSize = sizeof(MENUITEMINFOW);
931 ItemInfo.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_STATE | MIIM_SUBMENU;
932 ItemInfo.fType = MF_POPUP;
933 ItemInfo.fState = MFS_ENABLED;
934 ItemInfo.dwTypeData = NULL;
935 ItemInfo.cch = 0;
936 ItemInfo.hSubMenu = NewMenu->MenuInfo.Self;
937 IntInsertMenuItem(SysMenu, (UINT) -1, TRUE, &ItemInfo);
938
939 Window->SystemMenu = SysMenu->MenuInfo.Self;
940
941 ret = SysMenu;
942 }
943 IntDestroyMenuObject(Menu, FALSE, TRUE);
944 }
945 if(RetMenu)
946 return ret;
947 else
948 return NULL;
949 }
950 else
951 {
952 if(Window->SystemMenu)
953 return IntGetMenuObject((HMENU)Window->SystemMenu);
954 else
955 return NULL;
956 }
957 }
958
959
960 BOOL FASTCALL
961 IntIsChildWindow(PWINDOW_OBJECT Parent, PWINDOW_OBJECT BaseWindow)
962 {
963 PWINDOW_OBJECT Window;
964 PWND Wnd;
965
966 Window = BaseWindow;
967 while (Window)
968 {
969 Wnd = Window->Wnd;
970 if (Window == Parent)
971 {
972 return(TRUE);
973 }
974 if(!(Wnd->style & WS_CHILD))
975 {
976 break;
977 }
978
979 Window = Window->Parent;
980 }
981
982 return(FALSE);
983 }
984
985 BOOL FASTCALL
986 IntIsWindowVisible(PWINDOW_OBJECT BaseWindow)
987 {
988 PWINDOW_OBJECT Window;
989 PWND Wnd;
990
991 Window = BaseWindow;
992 while(Window)
993 {
994 Wnd = Window->Wnd;
995 if(!(Wnd->style & WS_CHILD))
996 {
997 break;
998 }
999 if(!(Wnd->style & WS_VISIBLE))
1000 {
1001 return FALSE;
1002 }
1003
1004 Window = Window->Parent;
1005 }
1006
1007 if(Window && Wnd->style & WS_VISIBLE)
1008 {
1009 return TRUE;
1010 }
1011
1012 return FALSE;
1013 }
1014
1015
1016 /* link the window into siblings and parent. children are kept in place. */
1017 VOID FASTCALL
1018 IntLinkWindow(
1019 PWINDOW_OBJECT Wnd,
1020 PWINDOW_OBJECT WndParent,
1021 PWINDOW_OBJECT WndPrevSibling /* set to NULL if top sibling */
1022 )
1023 {
1024 PWINDOW_OBJECT Parent;
1025
1026 Wnd->Parent = WndParent;
1027 Wnd->Wnd->spwndParent = WndParent ? WndParent->Wnd : NULL;
1028 if ((Wnd->PrevSibling = WndPrevSibling))
1029 {
1030 /* link after WndPrevSibling */
1031 if ((Wnd->NextSibling = WndPrevSibling->NextSibling))
1032 Wnd->NextSibling->PrevSibling = Wnd;
1033 else if ((Parent = Wnd->Parent))
1034 {
1035 if(Parent->LastChild == WndPrevSibling)
1036 Parent->LastChild = Wnd;
1037 }
1038 Wnd->PrevSibling->NextSibling = Wnd;
1039 }
1040 else
1041 {
1042 /* link at top */
1043 Parent = Wnd->Parent;
1044 if ((Wnd->NextSibling = WndParent->FirstChild))
1045 Wnd->NextSibling->PrevSibling = Wnd;
1046 else if (Parent)
1047 {
1048 Parent->LastChild = Wnd;
1049 Parent->FirstChild = Wnd;
1050 return;
1051 }
1052 if(Parent)
1053 {
1054 Parent->FirstChild = Wnd;
1055 }
1056 }
1057
1058 }
1059
1060 HWND FASTCALL
1061 IntSetOwner(HWND hWnd, HWND hWndNewOwner)
1062 {
1063 PWINDOW_OBJECT Wnd, WndOldOwner, WndNewOwner;
1064 HWND ret;
1065
1066 Wnd = IntGetWindowObject(hWnd);
1067 if(!Wnd)
1068 return NULL;
1069
1070 WndOldOwner = IntGetWindowObject(Wnd->hOwner);
1071 if (WndOldOwner)
1072 {
1073 ret = WndOldOwner->hSelf;
1074 UserDereferenceObject(WndOldOwner);
1075 }
1076 else
1077 {
1078 ret = 0;
1079 }
1080
1081 if((WndNewOwner = UserGetWindowObject(hWndNewOwner)))
1082 {
1083 Wnd->hOwner = hWndNewOwner;
1084 Wnd->Wnd->spwndOwner = WndNewOwner->Wnd;
1085 }
1086 else
1087 {
1088 Wnd->hOwner = NULL;
1089 Wnd->Wnd->spwndOwner = NULL;
1090 }
1091
1092 UserDereferenceObject(Wnd);
1093 return ret;
1094 }
1095
1096 PWINDOW_OBJECT FASTCALL
1097 co_IntSetParent(PWINDOW_OBJECT Wnd, PWINDOW_OBJECT WndNewParent)
1098 {
1099 PWINDOW_OBJECT WndOldParent, Sibling, InsertAfter;
1100 // HWND hWnd, hWndNewParent;
1101 BOOL WasVisible;
1102
1103 ASSERT(Wnd);
1104 ASSERT(WndNewParent);
1105 ASSERT_REFS_CO(Wnd);
1106 ASSERT_REFS_CO(WndNewParent);
1107
1108 // hWnd = Wnd->hSelf;
1109 // hWndNewParent = WndNewParent->hSelf;
1110
1111 /* Some applications try to set a child as a parent */
1112 if (IntIsChildWindow(Wnd, WndNewParent))
1113 {
1114 SetLastWin32Error( ERROR_INVALID_PARAMETER );
1115 return NULL;
1116 }
1117
1118 /*
1119 * Windows hides the window first, then shows it again
1120 * including the WM_SHOWWINDOW messages and all
1121 */
1122 WasVisible = co_WinPosShowWindow(Wnd, SW_HIDE);
1123
1124 // /* Validate that window and parent still exist */
1125 // if (!IntIsWindow(hWnd) || !IntIsWindow(hWndNewParent))
1126 // return NULL;
1127
1128 /* Window must belong to current process */
1129 if (Wnd->OwnerThread->ThreadsProcess != PsGetCurrentProcess())
1130 return NULL;
1131
1132 WndOldParent = Wnd->Parent;
1133
1134 if (WndOldParent) UserReferenceObject(WndOldParent); /* caller must deref */
1135
1136 if (WndNewParent != WndOldParent)
1137 {
1138 IntUnlinkWindow(Wnd);
1139 InsertAfter = NULL;
1140 if (0 == (Wnd->Wnd->ExStyle & WS_EX_TOPMOST))
1141 {
1142 /* Not a TOPMOST window, put after TOPMOSTs of new parent */
1143 Sibling = WndNewParent->FirstChild;
1144 while (NULL != Sibling && 0 != (Sibling->Wnd->ExStyle & WS_EX_TOPMOST))
1145 {
1146 InsertAfter = Sibling;
1147 Sibling = Sibling->NextSibling;
1148 }
1149 }
1150 if (NULL == InsertAfter)
1151 {
1152 IntLinkWindow(Wnd, WndNewParent, InsertAfter /*prev sibling*/);
1153 }
1154 else
1155 {
1156 // UserReferenceObject(InsertAfter);
1157 IntLinkWindow(Wnd, WndNewParent, InsertAfter /*prev sibling*/);
1158 // UserDereferenceObject(InsertAfter);
1159 }
1160 }
1161
1162 /*
1163 * SetParent additionally needs to make hwnd the top window
1164 * in the z-order and send the expected WM_WINDOWPOSCHANGING and
1165 * WM_WINDOWPOSCHANGED notification messages.
1166 */
1167 co_WinPosSetWindowPos(Wnd, (0 == (Wnd->Wnd->ExStyle & WS_EX_TOPMOST) ? HWND_TOP : HWND_TOPMOST),
1168 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE
1169 | (WasVisible ? SWP_SHOWWINDOW : 0));
1170
1171 /*
1172 * FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
1173 * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE
1174 */
1175
1176 /*
1177 * Validate that the old parent still exist, since it migth have been
1178 * destroyed during the last callbacks to user-mode
1179 */
1180 // if(WndOldParent)
1181 // {
1182 // if(!IntIsWindow(WndOldParent->hSelf))
1183 // {
1184 // UserDereferenceObject(WndOldParent);
1185 // return NULL;
1186 // }
1187
1188 /* don't dereference the window object here, it must be done by the caller
1189 of IntSetParent() */
1190 // return WndOldParent;
1191 // }
1192
1193 return WndOldParent;//NULL;
1194 }
1195
1196 BOOL FASTCALL
1197 IntSetSystemMenu(PWINDOW_OBJECT Window, PMENU_OBJECT Menu)
1198 {
1199 PMENU_OBJECT OldMenu;
1200 if(Window->SystemMenu)
1201 {
1202 OldMenu = IntGetMenuObject(Window->SystemMenu);
1203 if(OldMenu)
1204 {
1205 OldMenu->MenuInfo.Flags &= ~ MF_SYSMENU;
1206 IntReleaseMenuObject(OldMenu);
1207 }
1208 }
1209
1210 if(Menu)
1211 {
1212 /* FIXME check window style, propably return FALSE ? */
1213 Window->SystemMenu = Menu->MenuInfo.Self;
1214 Menu->MenuInfo.Flags |= MF_SYSMENU;
1215 }
1216 else
1217 Window->SystemMenu = (HMENU)0;
1218
1219 return TRUE;
1220 }
1221
1222
1223 /* unlink the window from siblings and parent. children are kept in place. */
1224 VOID FASTCALL
1225 IntUnlinkWindow(PWINDOW_OBJECT Wnd)
1226 {
1227 PWINDOW_OBJECT WndParent = Wnd->Parent;
1228
1229 if (Wnd->NextSibling)
1230 Wnd->NextSibling->PrevSibling = Wnd->PrevSibling;
1231 else if (WndParent && WndParent->LastChild == Wnd)
1232 WndParent->LastChild = Wnd->PrevSibling;
1233
1234 if (Wnd->PrevSibling)
1235 Wnd->PrevSibling->NextSibling = Wnd->NextSibling;
1236 else if (WndParent && WndParent->FirstChild == Wnd)
1237 WndParent->FirstChild = Wnd->NextSibling;
1238
1239 Wnd->PrevSibling = Wnd->NextSibling = Wnd->Parent = NULL;
1240 if (Wnd->Wnd)
1241 Wnd->Wnd->spwndParent = NULL;
1242 }
1243
1244 BOOL FASTCALL
1245 IntAnyPopup(VOID)
1246 {
1247 PWINDOW_OBJECT Window, Child;
1248
1249 if(!(Window = UserGetWindowObject(IntGetDesktopWindow())))
1250 {
1251 return FALSE;
1252 }
1253
1254 for(Child = Window->FirstChild; Child; Child = Child->NextSibling)
1255 {
1256 if(Child->hOwner && Child->Wnd->style & WS_VISIBLE)
1257 {
1258 /*
1259 * The desktop has a popup window if one of them has
1260 * an owner window and is visible
1261 */
1262 return TRUE;
1263 }
1264 }
1265
1266 return FALSE;
1267 }
1268
1269 BOOL FASTCALL
1270 IntIsWindowInDestroy(PWINDOW_OBJECT Window)
1271 {
1272 return ((Window->Status & WINDOWSTATUS_DESTROYING) == WINDOWSTATUS_DESTROYING);
1273 }
1274
1275
1276 BOOL
1277 FASTCALL
1278 IntGetWindowPlacement(PWINDOW_OBJECT Window, WINDOWPLACEMENT *lpwndpl)
1279 {
1280 PWND Wnd;
1281 POINT Size;
1282
1283 Wnd = Window->Wnd;
1284 if (!Wnd) return FALSE;
1285
1286 if(lpwndpl->length != sizeof(WINDOWPLACEMENT))
1287 {
1288 return FALSE;
1289 }
1290
1291 lpwndpl->flags = 0;
1292 if (0 == (Wnd->style & WS_VISIBLE))
1293 {
1294 lpwndpl->showCmd = SW_HIDE;
1295 }
1296 else if (0 != (Window->Flags & WINDOWOBJECT_RESTOREMAX) ||
1297 0 != (Wnd->style & WS_MAXIMIZE))
1298 {
1299 lpwndpl->showCmd = SW_MAXIMIZE;
1300 }
1301 else if (0 != (Wnd->style & WS_MINIMIZE))
1302 {
1303 lpwndpl->showCmd = SW_MINIMIZE;
1304 }
1305 else if (0 != (Wnd->style & WS_VISIBLE))
1306 {
1307 lpwndpl->showCmd = SW_SHOWNORMAL;
1308 }
1309
1310 Size.x = Wnd->rcWindow.left;
1311 Size.y = Wnd->rcWindow.top;
1312 WinPosInitInternalPos(Window, &Size,
1313 &Wnd->rcWindow);
1314
1315 lpwndpl->rcNormalPosition = Wnd->InternalPos.NormalRect;
1316 lpwndpl->ptMinPosition = Wnd->InternalPos.IconPos;
1317 lpwndpl->ptMaxPosition = Wnd->InternalPos.MaxPos;
1318
1319 return TRUE;
1320 }
1321
1322
1323 /* FUNCTIONS *****************************************************************/
1324
1325 /*
1326 * @unimplemented
1327 */
1328 DWORD APIENTRY
1329 NtUserAlterWindowStyle(DWORD Unknown0,
1330 DWORD Unknown1,
1331 DWORD Unknown2)
1332 {
1333 UNIMPLEMENTED
1334
1335 return(0);
1336 }
1337
1338 /*
1339 * As best as I can figure, this function is used by EnumWindows,
1340 * EnumChildWindows, EnumDesktopWindows, & EnumThreadWindows.
1341 *
1342 * It's supposed to build a list of HWNDs to return to the caller.
1343 * We can figure out what kind of list by what parameters are
1344 * passed to us.
1345 */
1346 /*
1347 * @implemented
1348 */
1349 NTSTATUS
1350 APIENTRY
1351 NtUserBuildHwndList(
1352 HDESK hDesktop,
1353 HWND hwndParent,
1354 BOOLEAN bChildren,
1355 ULONG dwThreadId,
1356 ULONG lParam,
1357 HWND* pWnd,
1358 ULONG* pBufSize)
1359 {
1360 NTSTATUS Status;
1361 ULONG dwCount = 0;
1362
1363 if (pBufSize == 0)
1364 return ERROR_INVALID_PARAMETER;
1365
1366 if (hwndParent || !dwThreadId)
1367 {
1368 PDESKTOP Desktop;
1369 PWINDOW_OBJECT Parent, Window;
1370
1371 if(!hwndParent)
1372 {
1373 if(hDesktop == NULL && !(Desktop = IntGetActiveDesktop()))
1374 {
1375 return ERROR_INVALID_HANDLE;
1376 }
1377
1378 if(hDesktop)
1379 {
1380 Status = IntValidateDesktopHandle(hDesktop,
1381 UserMode,
1382 0,
1383 &Desktop);
1384 if(!NT_SUCCESS(Status))
1385 {
1386 return ERROR_INVALID_HANDLE;
1387 }
1388 }
1389 hwndParent = Desktop->DesktopWindow;
1390 }
1391 else
1392 {
1393 hDesktop = 0;
1394 }
1395
1396 if((Parent = UserGetWindowObject(hwndParent)) &&
1397 (Window = Parent->FirstChild))
1398 {
1399 BOOL bGoDown = TRUE;
1400
1401 Status = STATUS_SUCCESS;
1402 while(TRUE)
1403 {
1404 if (bGoDown)
1405 {
1406 if(dwCount++ < *pBufSize && pWnd)
1407 {
1408 _SEH2_TRY
1409 {
1410 ProbeForWrite(pWnd, sizeof(HWND), 1);
1411 *pWnd = Window->hSelf;
1412 pWnd++;
1413 }
1414 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1415 {
1416 Status = _SEH2_GetExceptionCode();
1417 }
1418 _SEH2_END
1419 if(!NT_SUCCESS(Status))
1420 {
1421 SetLastNtError(Status);
1422 break;
1423 }
1424 }
1425 if (Window->FirstChild && bChildren)
1426 {
1427 Window = Window->FirstChild;
1428 continue;
1429 }
1430 bGoDown = FALSE;
1431 }
1432 if (Window->NextSibling)
1433 {
1434 Window = Window->NextSibling;
1435 bGoDown = TRUE;
1436 continue;
1437 }
1438 Window = Window->Parent;
1439 if (Window == Parent)
1440 {
1441 break;
1442 }
1443 }
1444 }
1445
1446 if(hDesktop)
1447 {
1448 ObDereferenceObject(Desktop);
1449 }
1450 }
1451 else
1452 {
1453 PETHREAD Thread;
1454 PTHREADINFO W32Thread;
1455 PLIST_ENTRY Current;
1456 PWINDOW_OBJECT Window;
1457
1458 Status = PsLookupThreadByThreadId((HANDLE)dwThreadId, &Thread);
1459 if(!NT_SUCCESS(Status))
1460 {
1461 return ERROR_INVALID_PARAMETER;
1462 }
1463 if(!(W32Thread = (PTHREADINFO)Thread->Tcb.Win32Thread))
1464 {
1465 ObDereferenceObject(Thread);
1466 DPRINT("Thread is not a GUI Thread!\n");
1467 return ERROR_INVALID_PARAMETER;
1468 }
1469
1470 Current = W32Thread->WindowListHead.Flink;
1471 while(Current != &(W32Thread->WindowListHead))
1472 {
1473 Window = CONTAINING_RECORD(Current, WINDOW_OBJECT, ThreadListEntry);
1474 ASSERT(Window);
1475
1476 if(bChildren || Window->hOwner != NULL)
1477 {
1478 if(dwCount < *pBufSize && pWnd)
1479 {
1480 Status = MmCopyToCaller(pWnd++, &Window->hSelf, sizeof(HWND));
1481 if(!NT_SUCCESS(Status))
1482 {
1483 SetLastNtError(Status);
1484 break;
1485 }
1486 }
1487 dwCount++;
1488 }
1489 Current = Current->Flink;
1490 }
1491
1492 ObDereferenceObject(Thread);
1493 }
1494
1495 *pBufSize = dwCount;
1496 return STATUS_SUCCESS;
1497 }
1498
1499
1500 /*
1501 * @implemented
1502 */
1503 HWND APIENTRY
1504 NtUserChildWindowFromPointEx(HWND hwndParent,
1505 LONG x,
1506 LONG y,
1507 UINT uiFlags)
1508 {
1509 PWINDOW_OBJECT Parent;
1510 POINTL Pt;
1511 HWND Ret;
1512 HWND *List, *phWnd;
1513
1514 if(!(Parent = UserGetWindowObject(hwndParent)))
1515 {
1516 return NULL;
1517 }
1518
1519 Pt.x = x;
1520 Pt.y = y;
1521
1522 if(Parent->hSelf != IntGetDesktopWindow())
1523 {
1524 Pt.x += Parent->Wnd->rcClient.left;
1525 Pt.y += Parent->Wnd->rcClient.top;
1526 }
1527
1528 if(!IntPtInWindow(Parent, Pt.x, Pt.y))
1529 {
1530 return NULL;
1531 }
1532
1533 Ret = Parent->hSelf;
1534 if((List = IntWinListChildren(Parent)))
1535 {
1536 for(phWnd = List; *phWnd; phWnd++)
1537 {
1538 PWINDOW_OBJECT Child;
1539 PWND ChildWnd;
1540 if((Child = UserGetWindowObject(*phWnd)))
1541 {
1542 ChildWnd = Child->Wnd;
1543 if(!(ChildWnd->style & WS_VISIBLE) && (uiFlags & CWP_SKIPINVISIBLE))
1544 {
1545 continue;
1546 }
1547 if((ChildWnd->style & WS_DISABLED) && (uiFlags & CWP_SKIPDISABLED))
1548 {
1549 continue;
1550 }
1551 if((ChildWnd->ExStyle & WS_EX_TRANSPARENT) && (uiFlags & CWP_SKIPTRANSPARENT))
1552 {
1553 continue;
1554 }
1555 if(IntPtInWindow(Child, Pt.x, Pt.y))
1556 {
1557 Ret = Child->hSelf;
1558 break;
1559 }
1560 }
1561 }
1562 ExFreePool(List);
1563 }
1564
1565 return Ret;
1566 }
1567
1568
1569 /*
1570 * calculates the default position of a window
1571 */
1572 BOOL FASTCALL
1573 IntCalcDefPosSize(PWINDOW_OBJECT Parent, PWINDOW_OBJECT Window, RECTL *rc, BOOL IncPos)
1574 {
1575 SIZE Sz;
1576 POINT Pos = {0, 0};
1577
1578 if(Parent != NULL)
1579 {
1580 RECTL_bIntersectRect(rc, rc, &Parent->Wnd->rcClient);
1581
1582 if(IncPos)
1583 {
1584 Pos.x = Parent->TiledCounter * (UserGetSystemMetrics(SM_CXSIZE) + UserGetSystemMetrics(SM_CXFRAME));
1585 Pos.y = Parent->TiledCounter * (UserGetSystemMetrics(SM_CYSIZE) + UserGetSystemMetrics(SM_CYFRAME));
1586 if(Pos.x > ((rc->right - rc->left) / 4) ||
1587 Pos.y > ((rc->bottom - rc->top) / 4))
1588 {
1589 /* reset counter and position */
1590 Pos.x = 0;
1591 Pos.y = 0;
1592 Parent->TiledCounter = 0;
1593 }
1594 Parent->TiledCounter++;
1595 }
1596 Pos.x += rc->left;
1597 Pos.y += rc->top;
1598 }
1599 else
1600 {
1601 Pos.x = rc->left;
1602 Pos.y = rc->top;
1603 }
1604
1605 Sz.cx = EngMulDiv(rc->right - rc->left, 3, 4);
1606 Sz.cy = EngMulDiv(rc->bottom - rc->top, 3, 4);
1607
1608 rc->left = Pos.x;
1609 rc->top = Pos.y;
1610 rc->right = rc->left + Sz.cx;
1611 rc->bottom = rc->top + Sz.cy;
1612 return TRUE;
1613 }
1614
1615
1616 /*
1617 * @implemented
1618 */
1619 PWND APIENTRY
1620 co_IntCreateWindowEx(DWORD dwExStyle,
1621 PUNICODE_STRING ClassName,
1622 PUNICODE_STRING WindowName,
1623 DWORD dwStyle,
1624 LONG x,
1625 LONG y,
1626 LONG nWidth,
1627 LONG nHeight,
1628 HWND hWndParent,
1629 HMENU hMenu,
1630 HINSTANCE hInstance,
1631 LPVOID lpParam,
1632 DWORD dwShowMode,
1633 BOOL bUnicodeWindow)
1634 {
1635 PWINSTATION_OBJECT WinSta;
1636 PWND Wnd = NULL;
1637 PCLS *ClassLink, Class = NULL;
1638 RTL_ATOM ClassAtom;
1639 PWINDOW_OBJECT Window = NULL;
1640 PWINDOW_OBJECT ParentWindow = NULL, OwnerWindow;
1641 HWND ParentWindowHandle = NULL;
1642 HWND OwnerWindowHandle;
1643 PMENU_OBJECT SystemMenu;
1644 HWND hWnd;
1645 POINT Pos;
1646 SIZE Size;
1647 PTHREADINFO ti = NULL;
1648 #if 0
1649
1650 POINT MaxSize, MaxPos, MinTrack, MaxTrack;
1651 #else
1652
1653 POINT MaxPos;
1654 #endif
1655 CREATESTRUCTW Cs;
1656 CBT_CREATEWNDW CbtCreate;
1657 LRESULT Result;
1658 BOOL MenuChanged;
1659 DECLARE_RETURN(PWND);
1660 BOOL HasOwner;
1661 USER_REFERENCE_ENTRY ParentRef, Ref;
1662 PTHREADINFO pti;
1663
1664 pti = PsGetCurrentThreadWin32Thread();
1665
1666 if (pti->Desktop)
1667 {
1668 ParentWindowHandle = pti->Desktop->DesktopWindow;
1669 }
1670
1671
1672 if ( !(pti->ppi->W32PF_flags & W32PF_CLASSESREGISTERED ))
1673 {
1674 UserRegisterSystemClasses();
1675 }
1676
1677 OwnerWindowHandle = NULL;
1678
1679 DPRINT("co_IntCreateWindowEx %wZ\n", ClassName);
1680
1681 if (hWndParent == HWND_MESSAGE)
1682 {
1683 /*
1684 * native ole32.OleInitialize uses HWND_MESSAGE to create the
1685 * message window (style: WS_POPUP|WS_DISABLED)
1686 */
1687 ParentWindowHandle = IntGetMessageWindow();
1688 DPRINT("Parent is HWND_MESSAGE 0x%x\n", ParentWindowHandle);
1689 }
1690 else if (hWndParent)
1691 {
1692 if ((dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1693 { //temp hack
1694 PWINDOW_OBJECT Par = UserGetWindowObject(hWndParent), Root;
1695 if (Par && (Root = UserGetAncestor(Par, GA_ROOT)))
1696 OwnerWindowHandle = Root->hSelf;
1697 }
1698 else
1699 ParentWindowHandle = hWndParent;
1700 }
1701 else if ((dwStyle & (WS_CHILD | WS_POPUP)) == WS_CHILD)
1702 {
1703 SetLastWin32Error(ERROR_TLW_WITH_WSCHILD);
1704 RETURN( (PWND)0); /* WS_CHILD needs a parent, but WS_POPUP doesn't */
1705 }
1706
1707 if (ParentWindowHandle)
1708 {
1709 ParentWindow = UserGetWindowObject(ParentWindowHandle);
1710
1711 if (ParentWindow) UserRefObjectCo(ParentWindow, &ParentRef);
1712 }
1713 else
1714 {
1715 ParentWindow = NULL;
1716 }
1717
1718 /* FIXME: parent must belong to the current process */
1719
1720 /* Check the window station. */
1721 ti = GetW32ThreadInfo();
1722 if (ti == NULL || pti->Desktop == NULL)
1723 {
1724 DPRINT1("Thread is not attached to a desktop! Cannot create window!\n");
1725 RETURN( (PWND)0);
1726 }
1727
1728 /* Check the class. */
1729
1730 DPRINT("Class %wZ\n", ClassName);
1731
1732 ClassAtom = IntGetClassAtom(ClassName,
1733 hInstance,
1734 ti->ppi,
1735 &Class,
1736 &ClassLink);
1737
1738 if (ClassAtom == (RTL_ATOM)0)
1739 {
1740 if (IS_ATOM(ClassName->Buffer))
1741 {
1742 DPRINT1("Class 0x%p not found\n", (DWORD_PTR) ClassName->Buffer);
1743 }
1744 else
1745 {
1746 DPRINT1("Class \"%wZ\" not found\n", ClassName);
1747 }
1748
1749 SetLastWin32Error(ERROR_CANNOT_FIND_WND_CLASS);
1750 RETURN((PWND)0);
1751 }
1752 DPRINT("ClassAtom %x\n", ClassAtom);
1753 Class = IntReferenceClass(Class,
1754 ClassLink,
1755 pti->Desktop);
1756 if (Class == NULL)
1757 {
1758 DPRINT1("Failed to reference window class!\n");
1759 RETURN(NULL);
1760 }
1761
1762 WinSta = pti->Desktop->WindowStation;
1763
1764 //FIXME: Reference thread/desktop instead
1765 ObReferenceObjectByPointer(WinSta, KernelMode, ExWindowStationObjectType, 0);
1766
1767 /* Create the window object. */
1768 Window = (PWINDOW_OBJECT) UserCreateObject( gHandleTable,
1769 (PHANDLE)&hWnd,
1770 otWindow,
1771 sizeof(WINDOW_OBJECT));
1772 if (Window)
1773 {
1774 Window->Wnd = DesktopHeapAlloc(pti->Desktop,
1775 sizeof(WND) + Class->cbwndExtra);
1776 if (!Window->Wnd)
1777 goto AllocErr;
1778 RtlZeroMemory(Window->Wnd,
1779 sizeof(WND) + Class->cbwndExtra);
1780 Window->Wnd->head.h = hWnd;
1781 Wnd = Window->Wnd;
1782 Wnd->fnid = 0;
1783
1784 Wnd->head.pti = ti;
1785 Wnd->head.rpdesk = pti->Desktop;
1786 Wnd->hWndLastActive = hWnd;
1787 Wnd->state2 |= WNDS2_WIN40COMPAT;
1788 }
1789
1790 DPRINT("Created object with handle %X\n", hWnd);
1791 if (!Window)
1792 {
1793 AllocErr:
1794 ObDereferenceObject(WinSta);
1795 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
1796 RETURN( (PWND)0);
1797 }
1798
1799 UserRefObjectCo(Window, &Ref);
1800
1801 ObDereferenceObject(WinSta);
1802
1803 if (NULL == pti->Desktop->DesktopWindow)
1804 {
1805 /* If there is no desktop window yet, we must be creating it */
1806 pti->Desktop->DesktopWindow = hWnd;
1807 pti->Desktop->DesktopInfo->Wnd = Wnd;
1808 }
1809
1810 /*
1811 * Fill out the structure describing it.
1812 */
1813 Window->ti = ti;
1814 Wnd->pcls = Class;
1815 Class = NULL;
1816
1817 Window->SystemMenu = (HMENU)0;
1818 Wnd->IDMenu = 0;
1819 Wnd->hModule = hInstance;
1820 Window->hSelf = hWnd;
1821
1822 Window->MessageQueue = pti->MessageQueue;
1823 IntReferenceMessageQueue(Window->MessageQueue);
1824 Window->Parent = ParentWindow;
1825 Wnd->spwndParent = ParentWindow ? ParentWindow->Wnd : NULL;
1826 if (Wnd->spwndParent != NULL && hWndParent != 0)
1827 {
1828 Wnd->HideFocus = Wnd->spwndParent->HideFocus;
1829 Wnd->HideAccel = Wnd->spwndParent->HideAccel;
1830 }
1831
1832 if((OwnerWindow = UserGetWindowObject(OwnerWindowHandle)))
1833 {
1834 Window->hOwner = OwnerWindowHandle;
1835 Wnd->spwndOwner = OwnerWindow->Wnd;
1836 HasOwner = TRUE;
1837 }
1838 else
1839 {
1840 Window->hOwner = NULL;
1841 Wnd->spwndOwner = NULL;
1842 HasOwner = FALSE;
1843 }
1844
1845 Wnd->dwUserData = 0;
1846
1847 if (Wnd->pcls->CSF_flags & CSF_SERVERSIDEPROC)
1848 Wnd->state |= WNDS_SERVERSIDEWINDOWPROC;
1849
1850 /* BugBoy Comments: Comment below say that System classes are always created
1851 as UNICODE. In windows, creating a window with the ANSI version of CreateWindow
1852 sets the window to ansi as verified by testing with IsUnicodeWindow API.
1853
1854 No where can I see in code or through testing does the window change back
1855 to ANSI after being created as UNICODE in ROS. I didnt do more testing to
1856 see what problems this would cause.*/
1857
1858 // Set WndProc from Class.
1859 Wnd->lpfnWndProc = Wnd->pcls->lpfnWndProc;
1860
1861 // GetWindowProc, test for non server side default classes and set WndProc.
1862 if ( Wnd->pcls->fnid <= FNID_GHOST && Wnd->pcls->fnid >= FNID_BUTTON )
1863 {
1864 if (bUnicodeWindow)
1865 {
1866 if (GETPFNCLIENTA(Wnd->pcls->fnid) == Wnd->lpfnWndProc)
1867 Wnd->lpfnWndProc = GETPFNCLIENTW(Wnd->pcls->fnid);
1868 }
1869 else
1870 {
1871 if (GETPFNCLIENTW(Wnd->pcls->fnid) == Wnd->lpfnWndProc)
1872 Wnd->lpfnWndProc = GETPFNCLIENTA(Wnd->pcls->fnid);
1873 }
1874 }
1875
1876 // If not an Unicode caller, set Ansi creator bit.
1877 if (!bUnicodeWindow) Wnd->state |= WNDS_ANSICREATOR;
1878
1879 // Clone Class Ansi/Unicode proc type.
1880 if (Wnd->pcls->CSF_flags & CSF_ANSIPROC)
1881 {
1882 Wnd->state |= WNDS_ANSIWINDOWPROC;
1883 Wnd->Unicode = FALSE;
1884 }
1885 else
1886 { /*
1887 It seems there can be both an Ansi creator and Unicode Class Window
1888 WndProc, unless the following overriding conditions occur:
1889 */
1890 if ( !bUnicodeWindow &&
1891 ( ClassAtom == gpsi->atomSysClass[ICLS_BUTTON] ||
1892 ClassAtom == gpsi->atomSysClass[ICLS_COMBOBOX] ||
1893 ClassAtom == gpsi->atomSysClass[ICLS_COMBOLBOX] ||
1894 ClassAtom == gpsi->atomSysClass[ICLS_DIALOG] ||
1895 ClassAtom == gpsi->atomSysClass[ICLS_EDIT] ||
1896 ClassAtom == gpsi->atomSysClass[ICLS_IME] ||
1897 ClassAtom == gpsi->atomSysClass[ICLS_LISTBOX] ||
1898 ClassAtom == gpsi->atomSysClass[ICLS_MDICLIENT] ||
1899 ClassAtom == gpsi->atomSysClass[ICLS_STATIC] ) )
1900 { // Override Class and set the window Ansi WndProc.
1901 Wnd->state |= WNDS_ANSIWINDOWPROC;
1902 Wnd->Unicode = FALSE;
1903 }
1904 else
1905 { // Set the window Unicode WndProc.
1906 Wnd->state &= ~WNDS_ANSIWINDOWPROC;
1907 Wnd->Unicode = TRUE;
1908 }
1909 }
1910
1911 Window->OwnerThread = PsGetCurrentThread();
1912 Window->FirstChild = NULL;
1913 Window->LastChild = NULL;
1914 Window->PrevSibling = NULL;
1915 Window->NextSibling = NULL;
1916 Wnd->cbwndExtra = Wnd->pcls->cbwndExtra;
1917
1918 InitializeListHead(&Wnd->PropListHead);
1919 InitializeListHead(&Window->WndObjListHead);
1920
1921 if ( NULL != WindowName->Buffer && WindowName->Length > 0 )
1922 {
1923 Wnd->strName.Buffer = DesktopHeapAlloc(Wnd->head.rpdesk,
1924 WindowName->Length + sizeof(UNICODE_NULL));
1925 if (Wnd->strName.Buffer == NULL)
1926 {
1927 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
1928 RETURN( (PWND)0);
1929 }
1930
1931 Wnd->strName.Buffer[WindowName->Length / sizeof(WCHAR)] = L'\0';
1932 _SEH2_TRY
1933 {
1934 RtlCopyMemory(Wnd->strName.Buffer,
1935 WindowName->Buffer,
1936 WindowName->Length);
1937 Wnd->strName.Length = WindowName->Length;
1938 }
1939 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1940 {
1941 WindowName->Length = 0;
1942 Wnd->strName.Buffer[0] = L'\0';
1943 }
1944 _SEH2_END;
1945 }
1946
1947 /*
1948 * This has been tested for WS_CHILD | WS_VISIBLE. It has not been
1949 * tested for WS_POPUP
1950 */
1951 if ((dwExStyle & WS_EX_DLGMODALFRAME) ||
1952 ((!(dwExStyle & WS_EX_STATICEDGE)) &&
1953 (dwStyle & (WS_DLGFRAME | WS_THICKFRAME))))
1954 dwExStyle |= WS_EX_WINDOWEDGE;
1955 else
1956 dwExStyle &= ~WS_EX_WINDOWEDGE;
1957
1958 /* Correct the window style. */
1959 if (!(dwStyle & WS_CHILD))
1960 {
1961 dwStyle |= WS_CLIPSIBLINGS;
1962 DPRINT("3: Style is now %lx\n", dwStyle);
1963 if (!(dwStyle & WS_POPUP))
1964 {
1965 dwStyle |= WS_CAPTION;
1966 Window->Flags |= WINDOWOBJECT_NEED_SIZE;
1967 DPRINT("4: Style is now %lx\n", dwStyle);
1968 }
1969 }
1970
1971 /* create system menu */
1972 if((dwStyle & WS_SYSMENU) )//&& (dwStyle & WS_CAPTION) == WS_CAPTION)
1973 {
1974 SystemMenu = IntGetSystemMenu(Window, TRUE, TRUE);
1975 if(SystemMenu)
1976 {
1977 Window->SystemMenu = SystemMenu->MenuInfo.Self;
1978 IntReleaseMenuObject(SystemMenu);
1979 }
1980 }
1981
1982 /* Set the window menu */
1983 if ((dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1984 {
1985 if (hMenu)
1986 IntSetMenu(Window, hMenu, &MenuChanged);
1987 else if (Wnd->pcls->lpszMenuName) // Take it from the parent.
1988 {
1989 UNICODE_STRING MenuName;
1990 if (IS_INTRESOURCE(Wnd->pcls->lpszMenuName))
1991 {
1992 MenuName.Length = 0;
1993 MenuName.MaximumLength = 0;
1994 MenuName.Buffer = Wnd->pcls->lpszMenuName;
1995 }
1996 else
1997 {
1998 RtlInitUnicodeString( &MenuName, Wnd->pcls->lpszMenuName);
1999 }
2000 hMenu = co_IntCallLoadMenu( Wnd->pcls->hModule, &MenuName);
2001 if (hMenu) IntSetMenu(Window, hMenu, &MenuChanged);
2002 }
2003 }
2004 else // Not a child
2005 Wnd->IDMenu = (UINT) hMenu;
2006
2007 /* Insert the window into the thread's window list. */
2008 InsertTailList (&pti->WindowListHead, &Window->ThreadListEntry);
2009
2010 /* Handle "CS_CLASSDC", it is tested first. */
2011 if ((Wnd->pcls->style & CS_CLASSDC) && !(Wnd->pcls->pdce)) // One DCE per class to have CLASS.
2012 Wnd->pcls->pdce = DceAllocDCE(Window, DCE_CLASS_DC);
2013 /* Allocate a DCE for this window. */
2014 else if ( Wnd->pcls->style & CS_OWNDC)
2015 Window->Dce = DceAllocDCE(Window, DCE_WINDOW_DC);
2016
2017 Pos.x = x;
2018 Pos.y = y;
2019 Size.cx = nWidth;
2020 Size.cy = nHeight;
2021
2022 Wnd->ExStyle = dwExStyle;
2023 Wnd->style = dwStyle & ~WS_VISIBLE;
2024
2025 /* call hook */
2026 Cs.lpCreateParams = lpParam;
2027 Cs.hInstance = hInstance;
2028 Cs.hMenu = hMenu;
2029 Cs.hwndParent = hWndParent; //Pass the original Parent handle!
2030 Cs.cx = Size.cx;
2031 Cs.cy = Size.cy;
2032 Cs.x = Pos.x;
2033 Cs.y = Pos.y;
2034 Cs.style = Wnd->style;
2035 // Cs.lpszName = (LPCWSTR) WindowName->Buffer;
2036 // Cs.lpszClass = (LPCWSTR) ClassName->Buffer;
2037 Cs.lpszName = (LPCWSTR) WindowName;
2038 Cs.lpszClass = (LPCWSTR) ClassName;
2039 Cs.dwExStyle = dwExStyle;
2040 CbtCreate.lpcs = &Cs;
2041 CbtCreate.hwndInsertAfter = HWND_TOP;
2042 if (ISITHOOKED(WH_CBT))
2043 {
2044 if (co_HOOK_CallHooks(WH_CBT, HCBT_CREATEWND, (WPARAM) hWnd, (LPARAM) &CbtCreate))
2045 {
2046 /* FIXME - Delete window object and remove it from the thread windows list */
2047 /* FIXME - delete allocated DCE */
2048 DPRINT1("CBT-hook returned !0\n");
2049 RETURN( (PWND) NULL);
2050 }
2051 }
2052 x = Cs.x;
2053 y = Cs.y;
2054 nWidth = Cs.cx;
2055 nHeight = Cs.cy;
2056 // FIXME: Need to set the Z order in the window link list if the hook callback changed it!
2057 // hwndInsertAfter = CbtCreate.hwndInsertAfter;
2058
2059 /* default positioning for overlapped windows */
2060 if(!(Wnd->style & (WS_POPUP | WS_CHILD)))
2061 {
2062 RECTL rc, WorkArea;
2063 PRTL_USER_PROCESS_PARAMETERS ProcessParams;
2064 BOOL CalculatedDefPosSize = FALSE;
2065
2066 IntGetDesktopWorkArea(((PTHREADINFO)Window->OwnerThread->Tcb.Win32Thread)->Desktop, &WorkArea);
2067
2068 rc = WorkArea;
2069 ProcessParams = PsGetCurrentProcess()->Peb->ProcessParameters;
2070
2071 if(x == CW_USEDEFAULT || x == CW_USEDEFAULT16)
2072 {
2073 CalculatedDefPosSize = IntCalcDefPosSize(ParentWindow, Window, &rc, TRUE);
2074
2075 if(ProcessParams->WindowFlags & STARTF_USEPOSITION)
2076 {
2077 ProcessParams->WindowFlags &= ~STARTF_USEPOSITION;
2078 Pos.x = WorkArea.left + ProcessParams->StartingX;
2079 Pos.y = WorkArea.top + ProcessParams->StartingY;
2080 }
2081 else
2082 {
2083 Pos.x = rc.left;
2084 Pos.y = rc.top;
2085 }
2086
2087 /*
2088 According to wine, the ShowMode is set to y if x == CW_USEDEFAULT(16) and
2089 y is something else. and Quote!
2090 */
2091
2092 /* Never believe Microsoft's documentation... CreateWindowEx doc says
2093 * that if an overlapped window is created with WS_VISIBLE style bit
2094 * set and the x parameter is set to CW_USEDEFAULT, the system ignores
2095 * the y parameter. However, disassembling NT implementation (WIN32K.SYS)
2096 * reveals that
2097 *
2098 * 1) not only it checks for CW_USEDEFAULT but also for CW_USEDEFAULT16
2099 * 2) it does not ignore the y parameter as the docs claim; instead, it
2100 * uses it as second parameter to ShowWindow() unless y is either
2101 * CW_USEDEFAULT or CW_USEDEFAULT16.
2102 *
2103 * The fact that we didn't do 2) caused bogus windows pop up when wine
2104 * was running apps that were using this obscure feature. Example -
2105 * calc.exe that comes with Win98 (only Win98, it's different from
2106 * the one that comes with Win95 and NT)
2107 */
2108 if(y != CW_USEDEFAULT && y != CW_USEDEFAULT16)
2109 {
2110 dwShowMode = y;
2111 }
2112 }
2113 if(nWidth == CW_USEDEFAULT || nWidth == CW_USEDEFAULT16)
2114 {
2115 if(!CalculatedDefPosSize)
2116 {
2117 IntCalcDefPosSize(ParentWindow, Window, &rc, FALSE);
2118 }
2119 if(ProcessParams->WindowFlags & STARTF_USESIZE)
2120 {
2121 ProcessParams->WindowFlags &= ~STARTF_USESIZE;
2122 Size.cx = ProcessParams->CountX;
2123 Size.cy = ProcessParams->CountY;
2124 }
2125 else
2126 {
2127 Size.cx = rc.right - rc.left;
2128 Size.cy = rc.bottom - rc.top;
2129 }
2130
2131 /* move the window if necessary */
2132 if(Pos.x > rc.left)
2133 Pos.x = max(rc.left, 0);
2134 if(Pos.y > rc.top)
2135 Pos.y = max(rc.top, 0);
2136 }
2137 }
2138 else
2139 {
2140 /* if CW_USEDEFAULT(16) is set for non-overlapped windows, both values are set to zero) */
2141 if(x == CW_USEDEFAULT || x == CW_USEDEFAULT16)
2142 {
2143 Pos.x = 0;
2144 Pos.y = 0;
2145 }
2146 if(nWidth == CW_USEDEFAULT || nWidth == CW_USEDEFAULT16)
2147 {
2148 Size.cx = 0;
2149 Size.cy = 0;
2150 }
2151 }
2152
2153 /* Initialize the window dimensions. */
2154 Wnd->rcWindow.left = Pos.x;
2155 Wnd->rcWindow.top = Pos.y;
2156 Wnd->rcWindow.right = Pos.x + Size.cx;
2157 Wnd->rcWindow.bottom = Pos.y + Size.cy;
2158 if (0 != (Wnd->style & WS_CHILD) && ParentWindow)
2159 {
2160 RECTL_vOffsetRect(&(Wnd->rcWindow), ParentWindow->Wnd->rcClient.left,
2161 ParentWindow->Wnd->rcClient.top);
2162 }
2163 Wnd->rcClient = Wnd->rcWindow;
2164
2165 /*
2166 * Get the size and position of the window.
2167 */
2168 if ((dwStyle & WS_THICKFRAME) || !(dwStyle & (WS_POPUP | WS_CHILD)))
2169 {
2170 POINT MaxSize, MaxPos, MinTrack, MaxTrack;
2171
2172 /* WinPosGetMinMaxInfo sends the WM_GETMINMAXINFO message */
2173 co_WinPosGetMinMaxInfo(Window, &MaxSize, &MaxPos, &MinTrack,
2174 &MaxTrack);
2175 if (MaxSize.x < Size.cx)
2176 Size.cx = MaxSize.x;
2177 if (MaxSize.y < Size.cy)
2178 Size.cy = MaxSize.y;
2179 if (Size.cx < MinTrack.x )
2180 Size.cx = MinTrack.x;
2181 if (Size.cy < MinTrack.y )
2182 Size.cy = MinTrack.y;
2183 if (Size.cx < 0)
2184 Size.cx = 0;
2185 if (Size.cy < 0)
2186 Size.cy = 0;
2187 }
2188
2189 Wnd->rcWindow.left = Pos.x;
2190 Wnd->rcWindow.top = Pos.y;
2191 Wnd->rcWindow.right = Pos.x + Size.cx;
2192 Wnd->rcWindow.bottom = Pos.y + Size.cy;
2193 if (0 != (Wnd->style & WS_CHILD) && ParentWindow)
2194 {
2195 RECTL_vOffsetRect(&(Wnd->rcWindow), ParentWindow->Wnd->rcClient.left,
2196 ParentWindow->Wnd->rcClient.top);
2197 }
2198 Wnd->rcClient = Wnd->rcWindow;
2199
2200 /* FIXME: Initialize the window menu. */
2201
2202 /* Send a NCCREATE message. */
2203 Cs.cx = Size.cx;
2204 Cs.cy = Size.cy;
2205 Cs.x = Pos.x;
2206 Cs.y = Pos.y;
2207
2208 DPRINT("[win32k.window] IntCreateWindowEx style %d, exstyle %d, parent %d\n", Cs.style, Cs.dwExStyle, Cs.hwndParent);
2209 DPRINT("IntCreateWindowEx(): (%d,%d-%d,%d)\n", x, y, Size.cx, Size.cy);
2210 DPRINT("IntCreateWindowEx(): About to send NCCREATE message.\n");
2211 Result = co_IntSendMessage(Window->hSelf, WM_NCCREATE, 0, (LPARAM) &Cs);
2212 if (!Result)
2213 {
2214 /* FIXME: Cleanup. */
2215 DPRINT1("IntCreateWindowEx(): NCCREATE message failed. No cleanup performed!\n");
2216 RETURN((PWND)0);
2217 }
2218
2219 /* Calculate the non-client size. */
2220 MaxPos.x = Window->Wnd->rcWindow.left;
2221 MaxPos.y = Window->Wnd->rcWindow.top;
2222
2223
2224 DPRINT("IntCreateWindowEx(): About to get non-client size.\n");
2225 /* WinPosGetNonClientSize SENDS THE WM_NCCALCSIZE message */
2226 Result = co_WinPosGetNonClientSize(Window,
2227 &Window->Wnd->rcWindow,
2228 &Window->Wnd->rcClient);
2229
2230 RECTL_vOffsetRect(&Window->Wnd->rcWindow,
2231 MaxPos.x - Window->Wnd->rcWindow.left,
2232 MaxPos.y - Window->Wnd->rcWindow.top);
2233
2234
2235 if (NULL != ParentWindow)
2236 {
2237 /* link the window into the parent's child list */
2238 if ((dwStyle & (WS_CHILD|WS_MAXIMIZE)) == WS_CHILD)
2239 {
2240 PWINDOW_OBJECT PrevSibling;
2241
2242 PrevSibling = ParentWindow->LastChild;
2243
2244 /* link window as bottom sibling */
2245 IntLinkWindow(Window, ParentWindow, PrevSibling /*prev sibling*/);
2246 }
2247 else
2248 {
2249 /* link window as top sibling (but after topmost siblings) */
2250 PWINDOW_OBJECT InsertAfter, Sibling;
2251 if (!(dwExStyle & WS_EX_TOPMOST))
2252 {
2253 InsertAfter = NULL;
2254 Sibling = ParentWindow->FirstChild;
2255 while (Sibling && (Sibling->Wnd->ExStyle & WS_EX_TOPMOST))
2256 {
2257 InsertAfter = Sibling;
2258 Sibling = Sibling->NextSibling;
2259 }
2260 }
2261 else
2262 {
2263 InsertAfter = NULL;
2264 }
2265
2266 IntLinkWindow(Window, ParentWindow, InsertAfter /* prev sibling */);
2267
2268 }
2269 }
2270
2271 /* Send the WM_CREATE message. */
2272 DPRINT("IntCreateWindowEx(): about to send CREATE message.\n");
2273 Result = co_IntSendMessage(Window->hSelf, WM_CREATE, 0, (LPARAM) &Cs);
2274
2275 if (Result == (LRESULT)-1)
2276 {
2277 /* FIXME: Cleanup. */
2278 DPRINT1("IntCreateWindowEx(): send CREATE message failed. No cleanup performed!\n");
2279 IntUnlinkWindow(Window);
2280 RETURN((PWND)0);
2281 }
2282
2283 IntNotifyWinEvent(EVENT_OBJECT_CREATE, Window->Wnd, OBJID_WINDOW, 0);
2284
2285 /* Send move and size messages. */
2286 if (!(Window->Flags & WINDOWOBJECT_NEED_SIZE))
2287 {
2288 LONG lParam;
2289
2290 DPRINT("IntCreateWindow(): About to send WM_SIZE\n");
2291
2292 if ((Window->Wnd->rcClient.right - Window->Wnd->rcClient.left) < 0 ||
2293 (Window->Wnd->rcClient.bottom - Window->Wnd->rcClient.top) < 0)
2294 {
2295 DPRINT("Sending bogus WM_SIZE\n");
2296 }
2297
2298 lParam = MAKE_LONG(Window->Wnd->rcClient.right -
2299 Window->Wnd->rcClient.left,
2300 Window->Wnd->rcClient.bottom -
2301 Window->Wnd->rcClient.top);
2302 co_IntSendMessage(Window->hSelf, WM_SIZE, SIZE_RESTORED,
2303 lParam);
2304
2305 DPRINT("IntCreateWindow(): About to send WM_MOVE\n");
2306
2307 if (0 != (Wnd->style & WS_CHILD) && ParentWindow)
2308 {
2309 lParam = MAKE_LONG(Wnd->rcClient.left - ParentWindow->Wnd->rcClient.left,
2310 Wnd->rcClient.top - ParentWindow->Wnd->rcClient.top);
2311 }
2312 else
2313 {
2314 lParam = MAKE_LONG(Wnd->rcClient.left,
2315 Wnd->rcClient.top);
2316 }
2317
2318 co_IntSendMessage(Window->hSelf, WM_MOVE, 0, lParam);
2319
2320 /* Call WNDOBJ change procs */
2321 IntEngWindowChanged(Window, WOC_RGN_CLIENT);
2322 }
2323
2324 /* Show or maybe minimize or maximize the window. */
2325 if (Wnd->style & (WS_MINIMIZE | WS_MAXIMIZE))
2326 {
2327 RECTL NewPos;
2328 UINT16 SwFlag;
2329
2330 SwFlag = (Wnd->style & WS_MINIMIZE) ? SW_MINIMIZE :
2331 SW_MAXIMIZE;
2332
2333 co_WinPosMinMaximize(Window, SwFlag, &NewPos);
2334
2335 SwFlag = ((Wnd->style & WS_CHILD) || UserGetActiveWindow()) ?
2336 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED :
2337 SWP_NOZORDER | SWP_FRAMECHANGED;
2338
2339 DPRINT("IntCreateWindow(): About to minimize/maximize\n");
2340 DPRINT("%d,%d %dx%d\n", NewPos.left, NewPos.top, NewPos.right, NewPos.bottom);
2341 co_WinPosSetWindowPos(Window, 0, NewPos.left, NewPos.top,
2342 NewPos.right, NewPos.bottom, SwFlag);
2343 }
2344
2345 /* Notify the parent window of a new child. */
2346 if ((Wnd->style & WS_CHILD) &&
2347 (!(Wnd->ExStyle & WS_EX_NOPARENTNOTIFY)) && ParentWindow)
2348 {
2349 DPRINT("IntCreateWindow(): About to notify parent\n");
2350 co_IntSendMessage(ParentWindow->hSelf,
2351 WM_PARENTNOTIFY,
2352 MAKEWPARAM(WM_CREATE, Wnd->IDMenu),
2353 (LPARAM)Window->hSelf);
2354 }
2355
2356 if ((!hWndParent) && (!HasOwner))
2357 {
2358 DPRINT("Sending CREATED notify\n");
2359 co_IntShellHookNotify(HSHELL_WINDOWCREATED, (LPARAM)hWnd);
2360 }
2361 else
2362 {
2363 DPRINT("Not sending CREATED notify, %x %d\n", ParentWindow, HasOwner);
2364 }
2365
2366 /* Initialize and show the window's scrollbars */
2367 if (Wnd->style & WS_VSCROLL)
2368 {
2369 co_UserShowScrollBar(Window, SB_VERT, TRUE);
2370 }
2371 if (Wnd->style & WS_HSCROLL)
2372 {
2373 co_UserShowScrollBar(Window, SB_HORZ, TRUE);
2374 }
2375
2376 if (dwStyle & WS_VISIBLE)
2377 {
2378 if (Wnd->style & WS_MAXIMIZE)
2379 dwShowMode = SW_SHOW;
2380 else if (Wnd->style & WS_MINIMIZE)
2381 dwShowMode = SW_SHOWMINIMIZED;
2382
2383 DPRINT("IntCreateWindow(): About to show window\n");
2384 co_WinPosShowWindow(Window, dwShowMode);
2385
2386 if (Wnd->ExStyle & WS_EX_MDICHILD)
2387 {
2388 co_IntSendMessage(ParentWindow->hSelf, WM_MDIREFRESHMENU, 0, 0);
2389 /* ShowWindow won't activate child windows */
2390 co_WinPosSetWindowPos(Window, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
2391 }
2392 }
2393
2394 /* BugBoy Comments: if the window being created is a edit control, ATOM 0xCxxx,
2395 then my testing shows that windows (2k and XP) creates a CallProc for it immediately
2396 Dont understand why it does this. */
2397 if (ClassAtom == gpsi->atomSysClass[ICLS_EDIT])
2398 {
2399 PCALLPROCDATA CallProc;
2400 //CallProc = CreateCallProc(NULL, Wnd->lpfnWndProc, bUnicodeWindow, Wnd->ti->ppi);
2401 CallProc = CreateCallProc(NULL, Wnd->lpfnWndProc, Wnd->Unicode , Wnd->head.pti->ppi);
2402
2403 if (!CallProc)
2404 {
2405 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
2406 DPRINT1("Warning: Unable to create CallProc for edit control. Control may not operate correctly! hwnd %x\n",hWnd);
2407 }
2408 else
2409 {
2410 UserAddCallProcToClass(Wnd->pcls, CallProc);
2411 }
2412 }
2413
2414 DPRINT("IntCreateWindow(): = %X\n", hWnd);
2415 DPRINT("WindowObject->SystemMenu = 0x%x\n", Window->SystemMenu);
2416 RETURN( Wnd);
2417
2418 CLEANUP:
2419 if (!_ret_ && Window && Window->Wnd && ti)
2420 UserFreeWindowInfo(ti, Window);
2421 if (Window)
2422 {
2423 UserDerefObjectCo(Window);
2424 UserDereferenceObject(Window);
2425 }
2426 if (ParentWindow) UserDerefObjectCo(ParentWindow);
2427 if (!_ret_ && ti != NULL)
2428 {
2429 if (Class != NULL)
2430 {
2431 IntDereferenceClass(Class,
2432 ti->pDeskInfo,
2433 ti->ppi);
2434 }
2435 }
2436 END_CLEANUP;
2437 }
2438
2439 HWND APIENTRY
2440 NtUserCreateWindowEx(DWORD dwExStyle,
2441 PUNICODE_STRING UnsafeClassName,
2442 PUNICODE_STRING UnsafeWindowName,
2443 DWORD dwStyle,
2444 LONG x,
2445 LONG y,
2446 LONG nWidth,
2447 LONG nHeight,
2448 HWND hWndParent,
2449 HMENU hMenu,
2450 HINSTANCE hInstance,
2451 LPVOID lpParam,
2452 DWORD dwShowMode,
2453 BOOL bUnicodeWindow,
2454 DWORD dwUnknown)
2455 {
2456 NTSTATUS Status;
2457 UNICODE_STRING WindowName;
2458 UNICODE_STRING ClassName;
2459 HWND NewWindow = NULL;
2460 PWND pNewWindow;
2461 DECLARE_RETURN(HWND);
2462
2463 DPRINT("Enter NtUserCreateWindowEx(): (%d,%d-%d,%d)\n", x, y, nWidth, nHeight);
2464 UserEnterExclusive();
2465
2466 /* Get the class name (string or atom) */
2467 Status = MmCopyFromCaller(&ClassName, UnsafeClassName, sizeof(UNICODE_STRING));
2468 if (! NT_SUCCESS(Status))
2469 {
2470 SetLastNtError(Status);
2471 RETURN( NULL);
2472 }
2473 if (ClassName.Length != 0)
2474 {
2475 Status = IntSafeCopyUnicodeStringTerminateNULL(&ClassName, UnsafeClassName);
2476 if (! NT_SUCCESS(Status))
2477 {
2478 SetLastNtError(Status);
2479 RETURN( NULL);
2480 }
2481 }
2482 else if (! IS_ATOM(ClassName.Buffer))
2483 {
2484 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2485 RETURN(NULL);
2486 }
2487
2488 /* safely copy the window name */
2489 if (NULL != UnsafeWindowName)
2490 {
2491 Status = IntSafeCopyUnicodeString(&WindowName, UnsafeWindowName);
2492 if (! NT_SUCCESS(Status))
2493 {
2494 if (! IS_ATOM(ClassName.Buffer))
2495 {
2496 ExFreePoolWithTag(ClassName.Buffer, TAG_STRING);
2497 }
2498 SetLastNtError(Status);
2499 RETURN( NULL);
2500 }
2501 }
2502 else
2503 {
2504 RtlInitUnicodeString(&WindowName, NULL);
2505 }
2506
2507 pNewWindow = co_IntCreateWindowEx( dwExStyle,
2508 &ClassName,
2509 &WindowName,
2510 dwStyle,
2511 x,
2512 y,
2513 nWidth,
2514 nHeight,
2515 hWndParent,
2516 hMenu,
2517 hInstance,
2518 lpParam,
2519 dwShowMode,
2520 bUnicodeWindow);
2521
2522 if (pNewWindow) NewWindow = UserHMGetHandle(pNewWindow);
2523
2524 if (WindowName.Buffer)
2525 {
2526 ExFreePoolWithTag(WindowName.Buffer, TAG_STRING);
2527 }
2528 if (! IS_ATOM(ClassName.Buffer))
2529 {
2530 ExFreePoolWithTag(ClassName.Buffer, TAG_STRING);
2531 }
2532
2533 RETURN( NewWindow);
2534
2535 CLEANUP:
2536 DPRINT("Leave NtUserCreateWindowEx, ret=%i\n",_ret_);
2537 UserLeave();
2538 END_CLEANUP;
2539 }
2540
2541 /*
2542 * @unimplemented
2543 */
2544 HDWP APIENTRY
2545 NtUserDeferWindowPos(HDWP WinPosInfo,
2546 HWND Wnd,
2547 HWND WndInsertAfter,
2548 int x,
2549 int y,
2550 int cx,
2551 int cy,
2552 UINT Flags)
2553 {
2554 UNIMPLEMENTED
2555
2556 return 0;
2557 }
2558
2559
2560 BOOLEAN FASTCALL co_UserDestroyWindow(PWINDOW_OBJECT Window)
2561 {
2562 BOOLEAN isChild;
2563 PWND Wnd;
2564 HWND hWnd;
2565
2566 ASSERT_REFS_CO(Window); // FIXME: temp hack?
2567
2568 hWnd = Window->hSelf;
2569
2570 Wnd = Window->Wnd;
2571
2572 if (!Wnd) return TRUE; // FIXME: Need to finish object rewrite or lock the thread when killing the window!
2573
2574 DPRINT("co_UserDestroyWindow \n");
2575
2576 /* Check for owner thread */
2577 if ((Window->OwnerThread != PsGetCurrentThread()))
2578 {
2579 SetLastWin32Error(ERROR_ACCESS_DENIED);
2580 return FALSE;
2581 }
2582
2583 /* Call hooks */
2584 if (ISITHOOKED(WH_CBT))
2585 {
2586 if (co_HOOK_CallHooks(WH_CBT, HCBT_DESTROYWND, (WPARAM) hWnd, 0)) return FALSE;
2587 }
2588
2589 /* Look whether the focus is within the tree of windows we will
2590 * be destroying.
2591 */
2592 if (!co_WinPosShowWindow(Window, SW_HIDE))
2593 {
2594 if (UserGetActiveWindow() == Window->hSelf)
2595 {
2596 co_WinPosActivateOtherWindow(Window);
2597 }
2598 }
2599
2600 if (Window->MessageQueue->ActiveWindow == Window->hSelf)
2601 Window->MessageQueue->ActiveWindow = NULL;
2602 if (Window->MessageQueue->FocusWindow == Window->hSelf)
2603 Window->MessageQueue->FocusWindow = NULL;
2604 if (Window->MessageQueue->CaptureWindow == Window->hSelf)
2605 Window->MessageQueue->CaptureWindow = NULL;
2606
2607 IntDereferenceMessageQueue(Window->MessageQueue);
2608
2609 IntEngWindowChanged(Window, WOC_DELETE);
2610 isChild = (0 != (Wnd->style & WS_CHILD));
2611
2612 #if 0 /* FIXME */
2613
2614 if (isChild)
2615 {
2616 if (! USER_IsExitingThread(GetCurrentThreadId()))
2617 {
2618 send_parent_notify(hwnd, WM_DESTROY);
2619 }
2620 }
2621 else if (NULL != GetWindow(Wnd, GW_OWNER))
2622 {
2623 co_HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
2624 /* FIXME: clean up palette - see "Internals" p.352 */
2625 }
2626 #endif
2627
2628 if (!IntIsWindow(Window->hSelf))
2629 {
2630 return TRUE;
2631 }
2632
2633 /* Recursively destroy owned windows */
2634 if (! isChild)
2635 {
2636 for (;;)
2637 {
2638 BOOL GotOne = FALSE;
2639 HWND *Children;
2640 HWND *ChildHandle;
2641 PWINDOW_OBJECT Child, Desktop;
2642
2643 Desktop = IntIsDesktopWindow(Window) ? Window :
2644 UserGetWindowObject(IntGetDesktopWindow());
2645 Children = IntWinListChildren(Desktop);
2646
2647 if (Children)
2648 {
2649 for (ChildHandle = Children; *ChildHandle; ++ChildHandle)
2650 {
2651 Child = UserGetWindowObject(*ChildHandle);
2652 if (Child == NULL)
2653 continue;
2654 if (Child->hOwner != Window->hSelf)
2655 {
2656 continue;
2657 }
2658
2659 if (IntWndBelongsToThread(Child, PsGetCurrentThreadWin32Thread()))
2660 {
2661 USER_REFERENCE_ENTRY ChildRef;
2662 UserRefObjectCo(Child, &ChildRef);//temp hack?
2663 co_UserDestroyWindow(Child);
2664 UserDerefObjectCo(Child);//temp hack?
2665
2666 GotOne = TRUE;
2667 continue;
2668 }
2669
2670 if (Child->hOwner != NULL)
2671 {
2672 Child->hOwner = NULL;
2673 Child->Wnd->spwndOwner = NULL;
2674 }
2675
2676 }
2677 ExFreePool(Children);
2678 }
2679 if (! GotOne)
2680 {
2681 break;
2682 }
2683 }
2684 }
2685
2686 if (!IntIsWindow(Window->hSelf))
2687 {
2688 return TRUE;
2689 }
2690
2691 /* Destroy the window storage */
2692 co_UserFreeWindow(Window, PsGetCurrentProcessWin32Process(), PsGetCurrentThreadWin32Thread(), TRUE);
2693
2694 return TRUE;
2695 }
2696
2697
2698 /*
2699 * @implemented
2700 */
2701 BOOLEAN APIENTRY
2702 NtUserDestroyWindow(HWND Wnd)
2703 {
2704 PWINDOW_OBJECT Window;
2705 DECLARE_RETURN(BOOLEAN);
2706 BOOLEAN ret;
2707 USER_REFERENCE_ENTRY Ref;
2708
2709 DPRINT("Enter NtUserDestroyWindow\n");
2710 UserEnterExclusive();
2711
2712 if (!(Window = UserGetWindowObject(Wnd)))
2713 {
2714 RETURN(FALSE);
2715 }
2716
2717 UserRefObjectCo(Window, &Ref);//faxme: dunno if win should be reffed during destroy..
2718 ret = co_UserDestroyWindow(Window);
2719 UserDerefObjectCo(Window);//faxme: dunno if win should be reffed during destroy..
2720
2721 RETURN(ret);
2722
2723 CLEANUP:
2724 DPRINT("Leave NtUserDestroyWindow, ret=%i\n",_ret_);
2725 UserLeave();
2726 END_CLEANUP;
2727 }
2728
2729
2730
2731 /*
2732 * @unimplemented
2733 */
2734 DWORD
2735 APIENTRY
2736 NtUserDrawMenuBarTemp(
2737 HWND hWnd,
2738 HDC hDC,
2739 PRECT hRect,
2740 HMENU hMenu,
2741 HFONT hFont)
2742 {
2743 /* we'll use this function just for caching the menu bar */
2744 UNIMPLEMENTED
2745 return 0;
2746 }
2747
2748
2749 /*
2750 * @unimplemented
2751 */
2752 DWORD APIENTRY
2753 NtUserEndDeferWindowPosEx(DWORD Unknown0,
2754 DWORD Unknown1)
2755 {
2756 UNIMPLEMENTED
2757
2758 return 0;
2759 }
2760
2761
2762 /*
2763 * FillWindow: Called from User; Dialog, Edit and ListBox procs during a WM_ERASEBKGND.
2764 */
2765 /*
2766 * @unimplemented
2767 */
2768 BOOL APIENTRY
2769 NtUserFillWindow(HWND hWndPaint,
2770 HWND hWndPaint1,
2771 HDC hDC,
2772 HBRUSH hBrush)
2773 {
2774 UNIMPLEMENTED
2775
2776 return 0;
2777 }
2778
2779
2780 static HWND FASTCALL
2781 IntFindWindow(PWINDOW_OBJECT Parent,
2782 PWINDOW_OBJECT ChildAfter,
2783 RTL_ATOM ClassAtom,
2784 PUNICODE_STRING WindowName)
2785 {
2786 BOOL CheckWindowName;
2787 HWND *List, *phWnd;
2788 HWND Ret = NULL;
2789
2790 ASSERT(Parent);
2791
2792 CheckWindowName = WindowName->Length != 0;
2793
2794 if((List = IntWinListChildren(Parent)))
2795 {
2796 phWnd = List;
2797 if(ChildAfter)
2798 {
2799 /* skip handles before and including ChildAfter */
2800 while(*phWnd && (*(phWnd++) != ChildAfter->hSelf))
2801 ;
2802 }
2803
2804 /* search children */
2805 while(*phWnd)
2806 {
2807 PWINDOW_OBJECT Child;
2808 if(!(Child = UserGetWindowObject(*(phWnd++))))
2809 {
2810 continue;
2811 }
2812
2813 /* Do not send WM_GETTEXT messages in the kernel mode version!
2814 The user mode version however calls GetWindowText() which will
2815 send WM_GETTEXT messages to windows belonging to its processes */
2816 if((!CheckWindowName || !RtlCompareUnicodeString(WindowName, &(Child->Wnd->strName), TRUE)) &&
2817 (!ClassAtom || Child->Wnd->pcls->atomClassName == ClassAtom))
2818 {
2819 Ret = Child->hSelf;
2820 break;
2821 }
2822
2823 }
2824 ExFreePool(List);
2825 }
2826
2827 return Ret;
2828 }
2829
2830 /*
2831 * FUNCTION:
2832 * Searches a window's children for a window with the specified
2833 * class and name
2834 * ARGUMENTS:
2835 * hwndParent = The window whose childs are to be searched.
2836 * NULL = desktop
2837 * HWND_MESSAGE = message-only windows
2838 *
2839 * hwndChildAfter = Search starts after this child window.
2840 * NULL = start from beginning
2841 *
2842 * ucClassName = Class name to search for
2843 * Reguired parameter.
2844 *
2845 * ucWindowName = Window name
2846 * ->Buffer == NULL = don't care
2847 *
2848 * RETURNS:
2849 * The HWND of the window if it was found, otherwise NULL
2850 */
2851 /*
2852 * @implemented
2853 */
2854 HWND APIENTRY
2855 NtUserFindWindowEx(HWND hwndParent,
2856 HWND hwndChildAfter,
2857 PUNICODE_STRING ucClassName,
2858 PUNICODE_STRING ucWindowName,
2859 DWORD dwUnknown)
2860 {
2861 PWINDOW_OBJECT Parent, ChildAfter;
2862 UNICODE_STRING ClassName = {0}, WindowName = {0};
2863 HWND Desktop, Ret = NULL;
2864 RTL_ATOM ClassAtom = (RTL_ATOM)0;
2865 DECLARE_RETURN(HWND);
2866
2867 DPRINT("Enter NtUserFindWindowEx\n");
2868 UserEnterShared();
2869
2870 if (ucClassName != NULL || ucWindowName != NULL)
2871 {
2872 _SEH2_TRY
2873 {
2874 if (ucClassName != NULL)
2875 {
2876 ClassName = ProbeForReadUnicodeString(ucClassName);
2877 if (ClassName.Length != 0)
2878 {
2879 ProbeForRead(ClassName.Buffer,
2880 ClassName.Length,
2881 sizeof(WCHAR));
2882 }
2883 else if (!IS_ATOM(ClassName.Buffer))
2884 {
2885 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2886 _SEH2_LEAVE;
2887 }
2888
2889 if (!IntGetAtomFromStringOrAtom(&ClassName,
2890 &ClassAtom))
2891 {
2892 _SEH2_LEAVE;
2893 }
2894 }
2895
2896 if (ucWindowName != NULL)
2897 {
2898 WindowName = ProbeForReadUnicodeString(ucWindowName);
2899 if (WindowName.Length != 0)
2900 {
2901 ProbeForRead(WindowName.Buffer,
2902 WindowName.Length,
2903 sizeof(WCHAR));
2904 }
2905 }
2906 }
2907 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2908 {
2909 SetLastNtError(_SEH2_GetExceptionCode());
2910 _SEH2_YIELD(RETURN(NULL));
2911 }
2912 _SEH2_END;
2913
2914 if (ucClassName != NULL)
2915 {
2916 if (ClassName.Length == 0 && ClassName.Buffer != NULL &&
2917 !IS_ATOM(ClassName.Buffer))
2918 {
2919 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2920 RETURN(NULL);
2921 }
2922 else if (ClassAtom == (RTL_ATOM)0)
2923 {
2924 /* LastError code was set by IntGetAtomFromStringOrAtom */
2925 RETURN(NULL);
2926 }
2927 }
2928 }
2929
2930 Desktop = IntGetCurrentThreadDesktopWindow();
2931
2932 if(hwndParent == NULL)
2933 hwndParent = Desktop;
2934 else if(hwndParent == HWND_MESSAGE)
2935 {
2936 hwndParent = IntGetMessageWindow();
2937 }
2938
2939 if(!(Parent = UserGetWindowObject(hwndParent)))
2940 {
2941 RETURN( NULL);
2942 }
2943
2944 ChildAfter = NULL;
2945 if(hwndChildAfter && !(ChildAfter = UserGetWindowObject(hwndChildAfter)))
2946 {
2947 RETURN( NULL);
2948 }
2949
2950 _SEH2_TRY
2951 {
2952 if(Parent->hSelf == Desktop)
2953 {
2954 HWND *List, *phWnd;
2955 PWINDOW_OBJECT TopLevelWindow;
2956 BOOLEAN CheckWindowName;
2957 BOOLEAN WindowMatches;
2958 BOOLEAN ClassMatches;
2959
2960 /* windows searches through all top-level windows if the parent is the desktop
2961 window */
2962
2963 if((List = IntWinListChildren(Parent)))
2964 {
2965 phWnd = List;
2966
2967 if(ChildAfter)
2968 {
2969 /* skip handles before and including ChildAfter */
2970 while(*phWnd && (*(phWnd++) != ChildAfter->hSelf))
2971 ;
2972 }
2973
2974 CheckWindowName = WindowName.Length != 0;
2975
2976 /* search children */
2977 while(*phWnd)
2978 {
2979 if(!(TopLevelWindow = UserGetWindowObject(*(phWnd++))))
2980 {
2981 continue;
2982 }
2983
2984 /* Do not send WM_GETTEXT messages in the kernel mode version!
2985 The user mode version however calls GetWindowText() which will
2986 send WM_GETTEXT messages to windows belonging to its processes */
2987 WindowMatches = !CheckWindowName || !RtlCompareUnicodeString(
2988 &WindowName, &TopLevelWindow->Wnd->strName, TRUE);
2989 ClassMatches = (ClassAtom == (RTL_ATOM)0) ||
2990 ClassAtom == TopLevelWindow->Wnd->pcls->atomClassName;
2991
2992 if (WindowMatches && ClassMatches)
2993 {
2994 Ret = TopLevelWindow->hSelf;
2995 break;
2996 }
2997
2998 if (IntFindWindow(TopLevelWindow, NULL, ClassAtom, &WindowName))
2999 {
3000 /* window returns the handle of the top-level window, in case it found
3001 the child window */
3002 Ret = TopLevelWindow->hSelf;
3003 break;
3004 }
3005
3006 }
3007 ExFreePool(List);
3008 }
3009 }
3010 else
3011 Ret = IntFindWindow(Parent, ChildAfter, ClassAtom, &WindowName);
3012
3013 #if 0
3014
3015 if(Ret == NULL && hwndParent == NULL && hwndChildAfter == NULL)
3016 {
3017 /* FIXME - if both hwndParent and hwndChildAfter are NULL, we also should
3018 search the message-only windows. Should this also be done if
3019 Parent is the desktop window??? */
3020 PWINDOW_OBJECT MsgWindows;
3021
3022 if((MsgWindows = UserGetWindowObject(IntGetMessageWindow())))
3023 {
3024 Ret = IntFindWindow(MsgWindows, ChildAfter, ClassAtom, &WindowName);
3025 }
3026 }
3027 #endif
3028 }
3029 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3030 {
3031 SetLastNtError(_SEH2_GetExceptionCode());
3032 Ret = NULL;
3033 }
3034 _SEH2_END;
3035
3036 RETURN( Ret);
3037
3038 CLEANUP:
3039 DPRINT("Leave NtUserFindWindowEx, ret %i\n",_ret_);
3040 UserLeave();
3041 END_CLEANUP;
3042 }
3043
3044
3045 /*
3046 * @unimplemented
3047 */
3048 BOOL APIENTRY
3049 NtUserFlashWindowEx(IN PFLASHWINFO pfwi)
3050 {
3051 UNIMPLEMENTED
3052
3053 return 0;
3054 }
3055
3056
3057 /*
3058 * @implemented
3059 */
3060 PWINDOW_OBJECT FASTCALL UserGetAncestor(PWINDOW_OBJECT Wnd, UINT Type)
3061 {
3062 PWINDOW_OBJECT WndAncestor, Parent;
3063
3064 if (Wnd->hSelf == IntGetDesktopWindow())
3065 {
3066 return NULL;
3067 }
3068
3069 switch (Type)
3070 {
3071 case GA_PARENT:
3072 {
3073 WndAncestor = Wnd->Parent;
3074 break;
3075 }
3076
3077 case GA_ROOT:
3078 {
3079 WndAncestor = Wnd;
3080 Parent = NULL;
3081
3082 for(;;)
3083 {
3084 if(!(Parent = WndAncestor->Parent))
3085 {
3086 break;
3087 }
3088 if(IntIsDesktopWindow(Parent))
3089 {
3090 break;
3091 }
3092
3093 WndAncestor = Parent;
3094 }
3095 break;
3096 }
3097
3098 case GA_ROOTOWNER:
3099 {
3100 WndAncestor = Wnd;
3101
3102 for (;;)
3103 {
3104 PWINDOW_OBJECT Parent, Old;
3105
3106 Old = WndAncestor;
3107 Parent = IntGetParent(WndAncestor);
3108
3109 if (!Parent)
3110 {
3111 break;
3112 }
3113
3114 //temp hack
3115 // UserDereferenceObject(Parent);
3116
3117 WndAncestor = Parent;
3118 }
3119 break;
3120 }
3121
3122 default:
3123 {
3124 return NULL;
3125 }
3126 }
3127
3128 return WndAncestor;
3129 }
3130
3131 /*
3132 * @implemented
3133 */
3134 HWND APIENTRY
3135 NtUserGetAncestor(HWND hWnd, UINT Type)
3136 {
3137 PWINDOW_OBJECT Window, Ancestor;
3138 DECLARE_RETURN(HWND);
3139
3140 DPRINT("Enter NtUserGetAncestor\n");
3141 UserEnterExclusive();
3142
3143 if (!(Window = UserGetWindowObject(hWnd)))
3144 {
3145 RETURN(NULL);
3146 }
3147
3148 Ancestor = UserGetAncestor(Window, Type);
3149 /* faxme: can UserGetAncestor ever return NULL for a valid window? */
3150
3151 RETURN(Ancestor ? Ancestor->hSelf : NULL);
3152
3153 CLEANUP:
3154 DPRINT("Leave NtUserGetAncestor, ret=%i\n",_ret_);
3155 UserLeave();
3156 END_CLEANUP;
3157 }
3158
3159
3160 BOOL
3161 APIENTRY
3162 NtUserGetComboBoxInfo(
3163 HWND hWnd,
3164 PCOMBOBOXINFO pcbi)
3165 {
3166 PWINDOW_OBJECT Wnd;
3167 DECLARE_RETURN(BOOL);
3168
3169 DPRINT("Enter NtUserGetComboBoxInfo\n");
3170 UserEnterShared();
3171
3172 if (!(Wnd = UserGetWindowObject(hWnd)))
3173 {
3174 RETURN( FALSE );
3175 }
3176 _SEH2_TRY
3177 {
3178 if(pcbi)
3179 {
3180 ProbeForWrite(pcbi,
3181 sizeof(COMBOBOXINFO),
3182 1);
3183 }
3184 }
3185 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3186 {
3187 SetLastNtError(_SEH2_GetExceptionCode());
3188 _SEH2_YIELD(RETURN(FALSE));
3189 }
3190 _SEH2_END;
3191
3192 // Pass the user pointer, it was already probed.
3193 RETURN( (BOOL) co_IntSendMessage( Wnd->hSelf, CB_GETCOMBOBOXINFO, 0, (LPARAM)pcbi));
3194
3195 CLEANUP:
3196 DPRINT("Leave NtUserGetComboBoxInfo, ret=%i\n",_ret_);
3197 UserLeave();
3198 END_CLEANUP;
3199 }
3200
3201
3202 /*
3203 * @implemented
3204 */
3205 DWORD APIENTRY
3206 NtUserGetInternalWindowPos( HWND hWnd,
3207 LPRECT rectWnd,
3208 LPPOINT ptIcon)
3209 {
3210 PWINDOW_OBJECT Window;
3211 PWND Wnd;
3212 DWORD Ret = 0;
3213 BOOL Hit = FALSE;
3214 WINDOWPLACEMENT wndpl;
3215
3216 UserEnterShared();
3217
3218 if (!(Window = UserGetWindowObject(hWnd)) || !Window->Wnd)
3219 {
3220 Hit = FALSE;
3221 goto Exit;
3222 }
3223 Wnd = Window->Wnd;
3224
3225 _SEH2_TRY
3226 {
3227 if(rectWnd)
3228 {
3229 ProbeForWrite(rectWnd,
3230 sizeof(RECT),
3231 1);
3232 }
3233 if(ptIcon)
3234 {
3235 ProbeForWrite(ptIcon,
3236 sizeof(POINT),
3237 1);
3238 }
3239
3240 }
3241 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3242 {
3243 SetLastNtError(_SEH2_GetExceptionCode());
3244 Hit = TRUE;
3245 }
3246 _SEH2_END;
3247
3248 wndpl.length = sizeof(WINDOWPLACEMENT);
3249
3250 if (IntGetWindowPlacement(Window, &wndpl) && !Hit)
3251 {
3252 _SEH2_TRY
3253 {
3254 if (rectWnd)
3255 {
3256 RtlCopyMemory(rectWnd, &wndpl.rcNormalPosition , sizeof(RECT));
3257 }
3258 if (ptIcon)
3259 {
3260 RtlCopyMemory(ptIcon, &wndpl.ptMinPosition, sizeof(POINT));
3261 }
3262
3263 }
3264 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3265 {
3266 SetLastNtError(_SEH2_GetExceptionCode());
3267 Hit = TRUE;
3268 }
3269 _SEH2_END;
3270
3271 if (!Hit) Ret = wndpl.showCmd;
3272 }
3273 Exit:
3274 UserLeave();
3275 return Ret;
3276 }
3277
3278 DWORD
3279 APIENTRY
3280 NtUserGetListBoxInfo(
3281 HWND hWnd)
3282 {
3283 PWINDOW_OBJECT Wnd;
3284 DECLARE_RETURN(DWORD);
3285
3286 DPRINT("Enter NtUserGetListBoxInfo\n");
3287 UserEnterShared();
3288
3289 if (!(Wnd = UserGetWindowObject(hWnd)))
3290 {
3291 RETURN( 0 );
3292 }
3293
3294 RETURN( (DWORD) co_IntSendMessage( Wnd->hSelf, LB_GETLISTBOXINFO, 0, 0 ));
3295
3296 CLEANUP:
3297 DPRINT("Leave NtUserGetListBoxInfo, ret=%i\n",_ret_);
3298 UserLeave();
3299 END_CLEANUP;
3300 }
3301
3302
3303 HWND FASTCALL
3304 co_UserSetParent(HWND hWndChild, HWND hWndNewParent)
3305 {
3306 PWINDOW_OBJECT Wnd = NULL, WndParent = NULL, WndOldParent;
3307 HWND hWndOldParent = NULL;
3308 USER_REFERENCE_ENTRY Ref, ParentRef;
3309
3310 if (IntIsBroadcastHwnd(hWndChild) || IntIsBroadcastHwnd(hWndNewParent))
3311 {
3312 SetLastWin32Error(ERROR_INVALID_PARAMETER);
3313 return( NULL);
3314 }
3315
3316 if (hWndChild == IntGetDesktopWindow())
3317 {
3318 SetLastWin32Error(ERROR_ACCESS_DENIED);
3319 return( NULL);
3320 }
3321
3322 if (hWndNewParent)
3323 {
3324 if (!(WndParent = UserGetWindowObject(hWndNewParent)))
3325 {
3326 return( NULL);
3327 }
3328 }
3329 else
3330 {
3331 if (!(WndParent = UserGetWindowObject(IntGetDesktopWindow())))
3332 {
3333 return( NULL);
3334 }
3335 }
3336
3337 if (!(Wnd = UserGetWindowObject(hWndChild)))
3338 {
3339 return( NULL);
3340 }
3341
3342 UserRefObjectCo(Wnd, &Ref);
3343 UserRefObjectCo(WndParent, &ParentRef);
3344
3345 WndOldParent = co_IntSetParent(Wnd, WndParent);
3346
3347 UserDerefObjectCo(WndParent);
3348 UserDerefObjectCo(Wnd);
3349
3350 if (WndOldParent)
3351 {
3352 hWndOldParent = WndOldParent->hSelf;
3353 UserDereferenceObject(WndOldParent);
3354 }
3355
3356 return( hWndOldParent);
3357 }
3358
3359 /*
3360 * NtUserSetParent
3361 *
3362 * The NtUserSetParent function changes the parent window of the specified
3363 * child window.
3364 *
3365 * Remarks
3366 * The new parent window and the child window must belong to the same
3367 * application. If the window identified by the hWndChild parameter is
3368 * visible, the system performs the appropriate redrawing and repainting.
3369 * For compatibility reasons, NtUserSetParent does not modify the WS_CHILD
3370 * or WS_POPUP window styles of the window whose parent is being changed.
3371 *
3372 * Status
3373 * @implemented
3374 */
3375
3376 HWND APIENTRY
3377 NtUserSetParent(HWND hWndChild, HWND hWndNewParent)
3378 {
3379 DECLARE_RETURN(HWND);
3380
3381 DPRINT("Enter NtUserSetParent\n");
3382 UserEnterExclusive();
3383
3384 /*
3385 Check Parent first from user space, set it here.
3386 */
3387 if (!hWndNewParent)
3388 {
3389 hWndNewParent = IntGetDesktopWindow();
3390 }
3391 else if (hWndNewParent == HWND_MESSAGE)
3392 {
3393 hWndNewParent = IntGetMessageWindow();
3394 }
3395
3396 RETURN( co_UserSetParent(hWndChild, hWndNewParent));
3397
3398 CLEANUP:
3399 DPRINT("Leave NtUserSetParent, ret=%i\n",_ret_);
3400 UserLeave();
3401 END_CLEANUP;
3402 }
3403
3404 /*
3405 * UserGetShellWindow
3406 *
3407 * Returns a handle to shell window that was set by NtUserSetShellWindowEx.
3408 *
3409 * Status
3410 * @implemented
3411 */
3412 HWND FASTCALL UserGetShellWindow(VOID)
3413 {
3414 PWINSTATION_OBJECT WinStaObject;
3415 HWND Ret;
3416
3417 NTSTATUS Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
3418 KernelMode,
3419 0,
3420 &WinStaObject);
3421
3422 if (!NT_SUCCESS(Status))
3423 {
3424 SetLastNtError(Status);
3425 return( (HWND)0);
3426 }
3427
3428 Ret = (HWND)WinStaObject->ShellWindow;
3429
3430 ObDereferenceObject(WinStaObject);
3431 return( Ret);
3432 }
3433
3434 /*
3435 * NtUserSetShellWindowEx
3436 *
3437 * This is undocumented function to set global shell window. The global
3438 * shell window has special handling of window position.
3439 *
3440 * Status
3441 * @implemented
3442 */
3443 BOOL APIENTRY
3444 NtUserSetShellWindowEx(HWND hwndShell, HWND hwndListView)
3445 {
3446 PWINSTATION_OBJECT WinStaObject;
3447 PWINDOW_OBJECT WndShell;
3448 DECLARE_RETURN(BOOL);
3449 USER_REFERENCE_ENTRY Ref;
3450 NTSTATUS Status;
3451 PTHREADINFO ti;
3452
3453 DPRINT("Enter NtUserSetShellWindowEx\n");
3454 UserEnterExclusive();
3455
3456 if (!(WndShell = UserGetWindowObject(hwndShell)))
3457 {
3458 RETURN(FALSE);
3459 }
3460
3461 Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
3462 KernelMode,
3463 0,
3464 &WinStaObject);
3465
3466 if (!NT_SUCCESS(Status))
3467 {
3468 SetLastNtError(Status);
3469 RETURN( FALSE);
3470 }
3471
3472 /*
3473 * Test if we are permitted to change the shell window.
3474 */
3475 if (WinStaObject->ShellWindow)
3476 {
3477 ObDereferenceObject(WinStaObject);
3478 RETURN( FALSE);
3479 }
3480
3481 /*
3482 * Move shell window into background.
3483 */
3484 if (hwndListView && hwndListView != hwndShell)
3485 {
3486 /*
3487 * Disabled for now to get Explorer working.
3488 * -- Filip, 01/nov/2003
3489 */
3490 #if 0
3491 co_WinPosSetWindowPos(hwndListView, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
3492 #endif
3493
3494 if (UserGetWindowLong(hwndListView, GWL_EXSTYLE, FALSE) & WS_EX_TOPMOST)
3495 {
3496 ObDereferenceObject(WinStaObject);
3497 RETURN( FALSE);
3498 }
3499 }
3500
3501 if (UserGetWindowLong(hwndShell, GWL_EXSTYLE, FALSE) & WS_EX_TOPMOST)
3502 {
3503 ObDereferenceObject(WinStaObject);
3504 RETURN( FALSE);
3505 }
3506
3507 UserRefObjectCo(WndShell, &Ref);
3508 co_WinPosSetWindowPos(WndShell, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
3509
3510 WinStaObject->ShellWindow = hwndShell;
3511 WinStaObject->ShellListView = hwndListView;
3512
3513 ti = GetW32ThreadInfo();
3514 if (ti->pDeskInfo) ti->pDeskInfo->hShellWindow = hwndShell;
3515
3516 UserDerefObjectCo(WndShell);
3517
3518 ObDereferenceObject(WinStaObject);
3519 RETURN( TRUE);
3520
3521 CLEANUP:
3522 DPRINT("Leave NtUserSetShellWindowEx, ret=%i\n",_ret_);
3523 UserLeave();
3524 END_CLEANUP;
3525 }
3526
3527 /*
3528 * NtUserGetSystemMenu
3529 *
3530 * The NtUserGetSystemMenu function allows the application to access the
3531 * window menu (also known as the system menu or the control menu) for
3532 * copying and modifying.
3533 *
3534 * Parameters
3535 * hWnd
3536 * Handle to the window that will own a copy of the window menu.
3537 * bRevert
3538 * Specifies the action to be taken. If this parameter is FALSE,
3539 * NtUserGetSystemMenu returns a handle to the copy of the window menu
3540 * currently in use. The copy is initially identical to the window menu
3541 * but it can be modified.
3542 * If this parameter is TRUE, GetSystemMenu resets the window menu back
3543 * to the default state. The previous window menu, if any, is destroyed.
3544 *
3545 * Return Value
3546 * If the bRevert parameter is FALSE, the return value is a handle to a
3547 * copy of the window menu. If the bRevert parameter is TRUE, the return
3548 * value is NULL.
3549 *
3550 * Status
3551 * @implemented
3552 */
3553
3554 HMENU APIENTRY
3555 NtUserGetSystemMenu(HWND hWnd, BOOL bRevert)
3556 {
3557 PWINDOW_OBJECT Window;
3558 PMENU_OBJECT Menu;
3559 DECLARE_RETURN(HMENU);
3560
3561 DPRINT("Enter NtUserGetSystemMenu\n");
3562 UserEnterShared();
3563
3564 if (!(Window = UserGetWindowObject(hWnd)))
3565 {
3566 RETURN(NULL);
3567 }
3568
3569 if (!(Menu = IntGetSystemMenu(Window, bRevert, FALSE)))
3570 {
3571 RETURN(NULL);
3572 }
3573
3574 RETURN(Menu->MenuInfo.Self);
3575
3576 CLEANUP:
3577 DPRINT("Leave NtUserGetSystemMenu, ret=%i\n",_ret_);
3578 UserLeave();
3579 END_CLEANUP;
3580 }
3581
3582 /*
3583 * NtUserSetSystemMenu
3584 *
3585 * Status
3586 * @implemented
3587 */
3588
3589 BOOL APIENTRY
3590 NtUserSetSystemMenu(HWND hWnd, HMENU hMenu)
3591 {
3592 BOOL Result = FALSE;
3593 PWINDOW_OBJECT Window;
3594 PMENU_OBJECT Menu;
3595 DECLARE_RETURN(BOOL);
3596
3597 DPRINT("Enter NtUserSetSystemMenu\n");
3598 UserEnterExclusive();
3599
3600 if (!(Window = UserGetWindowObject(hWnd)))
3601 {
3602 RETURN( FALSE);
3603 }
3604
3605 if (hMenu)
3606 {
3607 /*
3608 * Assign new menu handle.
3609 */
3610 if (!(Menu = UserGetMenuObject(hMenu)))
3611 {
3612 RETURN( FALSE);
3613 }
3614
3615 Result = IntSetSystemMenu(Window, Menu);
3616 }
3617
3618 RETURN( Result);
3619
3620 CLEANUP:
3621 DPRINT("Leave NtUserSetSystemMenu, ret=%i\n",_ret_);
3622 UserLeave();
3623 END_CLEANUP;
3624 }
3625
3626 HWND FASTCALL
3627 UserGetWindow(HWND hWnd, UINT Relationship)
3628 {
3629 PWINDOW_OBJECT Parent, Window;
3630 HWND hWndResult = NULL;
3631
3632 if (!(Window = UserGetWindowObject(hWnd)))
3633 return NULL;
3634
3635 switch (Relationship)
3636 {
3637 case GW_HWNDFIRST:
3638 if((Parent = Window->Parent))
3639 {
3640 if (Parent->FirstChild)
3641 hWndResult = Parent->FirstChild->hSelf;
3642 }
3643 break;
3644
3645 case GW_HWNDLAST:
3646 if((Parent = Window->Parent))
3647 {
3648 if (Parent->LastChild)
3649 hWndResult = Parent->LastChild->hSelf;
3650 }
3651 break;
3652
3653 case GW_HWNDNEXT:
3654 if (Window->NextSibling)
3655 hWndResult = Window->NextSibling->hSelf;
3656 break;
3657
3658 case GW_HWNDPREV:
3659 if (Window->PrevSibling)
3660 hWndResult = Window->PrevSibling->hSelf;
3661 break;
3662
3663 case GW_OWNER:
3664 if((Parent = UserGetWindowObject(Window->hOwner)))
3665 {
3666 hWndResult = Parent->hSelf;
3667 }
3668 break;
3669 case GW_CHILD:
3670 if (Window->FirstChild)
3671 hWndResult = Window->FirstChild->hSelf;
3672 break;
3673 }
3674
3675 return hWndResult;
3676 }
3677
3678 /*
3679 * NtUserGetWindow
3680 *
3681 * The NtUserGetWindow function retrieves a handle to a window that has the
3682 * specified relationship (Z order or owner) to the specified window.
3683 *
3684 * Status
3685 * @implemented
3686 */
3687
3688 HWND APIENTRY
3689 NtUserGetWindow(HWND hWnd, UINT Relationship)
3690 {
3691 DECLARE_RETURN(HWND);
3692
3693 DPRINT("Enter NtUserGetWindow\n");
3694 UserEnterShared();
3695
3696 RETURN(UserGetWindow(hWnd, Relationship));
3697
3698 CLEANUP:
3699 DPRINT("Leave NtUserGetWindow, ret=%i\n",_ret_);
3700 UserLeave();
3701 END_CLEANUP;
3702 }
3703
3704 /*
3705 * NtUserGetWindowLong
3706 *
3707 * The NtUserGetWindowLong function retrieves information about the specified
3708 * window. The function also retrieves the 32-bit (long) value at the
3709 * specified offset into the extra window memory.
3710 *
3711 * Status
3712 * @implemented
3713 */
3714
3715 LONG FASTCALL
3716 UserGetWindowLong(HWND hWnd, DWORD Index, BOOL Ansi)
3717 {
3718 PWINDOW_OBJECT Window, Parent;
3719 PWND Wnd;
3720 LONG Result = 0;
3721
3722 DPRINT("NtUserGetWindowLong(%x,%d,%d)\n", hWnd, (INT)Index, Ansi);
3723
3724 if (!(Window = UserGetWindowObject(hWnd)) || !Window->Wnd)
3725 {
3726 return 0;
3727 }
3728
3729 Wnd = Window->Wnd;
3730
3731 /*
3732 * WndProc is only available to the owner process
3733 */
3734 if (GWL_WNDPROC == Index
3735 && Window->OwnerThread->ThreadsProcess != PsGetCurrentProcess())
3736 {
3737 SetLastWin32Error(ERROR_ACCESS_DENIED);
3738 return 0;
3739 }
3740
3741 if ((INT)Index >= 0)
3742 {
3743 if ((Index + sizeof(LONG)) > Window->Wnd->cbwndExtra)
3744 {
3745 SetLastWin32Error(ERROR_INVALID_PARAMETER);
3746 return 0;
3747 }
3748 Result = *((LONG *)((PCHAR)(Window->Wnd + 1) + Index));
3749 }
3750 else
3751 {
3752 switch (Index)
3753 {
3754 case GWL_EXSTYLE:
3755 Result = Wnd->ExStyle;
3756 break;
3757
3758 case GWL_STYLE:
3759 Result = Wnd->style;
3760 break;
3761
3762 case GWL_WNDPROC:
3763 Result = (LONG)IntGetWindowProc(Wnd, Ansi);
3764 break;
3765
3766 case GWL_HINSTANCE:
3767 Result = (LONG) Wnd->hModule;
3768 break;
3769
3770 case GWL_HWNDPARENT:
3771 Parent = Window->Parent;
3772 if(Parent)
3773 {
3774 if (Parent && Parent->hSelf == IntGetDesktopWindow())
3775 Result = (LONG) UserGetWindow(Window->hSelf, GW_OWNER);
3776 else
3777 Result = (LONG) Parent->hSelf;
3778 }
3779 break;
3780
3781 case GWL_ID:
3782 Result = (LONG) Wnd->IDMenu;
3783 break;
3784
3785 case GWL_USERDATA:
3786 Result = Wnd->dwUserData;
3787 break;
3788
3789 default:
3790 DPRINT1("NtUserGetWindowLong(): Unsupported index %d\n", Index);
3791 SetLastWin32Error(ERROR_INVALID_PARAMETER);
3792 Result = 0;
3793 break;
3794 }
3795 }
3796
3797 return Result;
3798 }
3799
3800 /*
3801 * NtUserGetWindowLong
3802 *
3803 * The NtUserGetWindowLong function retrieves information about the specified
3804 * window. The function also retrieves the 32-bit (long) value at the
3805 * specified offset into the extra window memory.
3806 *
3807 * Status
3808 * @implemented
3809 */
3810
3811 LONG APIENTRY
3812 NtUserGetWindowLong(HWND hWnd, DWORD Index, BOOL Ansi)
3813 {
3814 DECLARE_RETURN(LONG);
3815
3816 DPRINT("Enter NtUserGetWindowLong(%x,%d,%d)\n", hWnd, (INT)Index, Ansi);
3817 UserEnterExclusive();
3818
3819 RETURN(UserGetWindowLong(hWnd, Index, Ansi));
3820
3821 CLEANUP:
3822 DPRINT("Leave NtUserGetWindowLong, ret=%i\n",_ret_);
3823 UserLeave();
3824 END_CLEANUP;
3825 }
3826
3827
3828
3829 LONG FASTCALL
3830 co_UserSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi)
3831 {
3832 PWINDOW_OBJECT Window, Parent;
3833 PWND Wnd;
3834 PWINSTATION_OBJECT WindowStation;
3835 LONG OldValue;
3836 STYLESTRUCT Style;
3837
3838 if (hWnd == IntGetDesktopWindow())
3839 {
3840 SetLastWin32Error(STATUS_ACCESS_DENIED);
3841 return( 0);
3842 }
3843
3844 if (!(Window = UserGetWindowObject(hWnd)))
3845 {
3846 return( 0);
3847 }
3848
3849 Wnd = Window->Wnd;
3850
3851 if (!Wnd) return 0; // No go on zero.
3852
3853 if ((INT)Index >= 0)
3854 {
3855 if ((Index + sizeof(LONG)) > Wnd->cbwndExtra)
3856 {
3857 SetLastWin32Error(ERROR_INVALID_PARAMETER);
3858 return( 0);
3859 }
3860
3861 OldValue = *((LONG *)((PCHAR)(Wnd + 1) + Index));
3862 /*
3863 if ( Index == DWLP_DLGPROC && Wnd->state & WNDS_DIALOGWINDOW)
3864 {
3865 OldValue = (LONG)IntSetWindowProc( Wnd,
3866 (WNDPROC)NewValue,
3867 Ansi);
3868 if (!OldValue) return 0;
3869 }
3870 */
3871 *((LONG *)((PCHAR)(Wnd + 1) + Index)) = NewValue;
3872 }
3873 else