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