[Win32k]
[reactos.git] / reactos / win32ss / user / ntuser / window.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Win32k subsystem
4 * PURPOSE: Windows
5 * FILE: win32ss/user/ntuser/window.c
6 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 */
8
9 #include <win32k.h>
10 DBG_DEFAULT_CHANNEL(UserWnd);
11
12 INT gNestedWindowLimit = 50;
13
14 /* HELPER FUNCTIONS ***********************************************************/
15
16 BOOL FASTCALL UserUpdateUiState(PWND Wnd, WPARAM wParam)
17 {
18 WORD Action = LOWORD(wParam);
19 WORD Flags = HIWORD(wParam);
20
21 if (Flags & ~(UISF_HIDEFOCUS | UISF_HIDEACCEL | UISF_ACTIVE))
22 {
23 EngSetLastError(ERROR_INVALID_PARAMETER);
24 return FALSE;
25 }
26
27 switch (Action)
28 {
29 case UIS_INITIALIZE:
30 EngSetLastError(ERROR_INVALID_PARAMETER);
31 return FALSE;
32
33 case UIS_SET:
34 if (Flags & UISF_HIDEFOCUS)
35 Wnd->HideFocus = TRUE;
36 if (Flags & UISF_HIDEACCEL)
37 Wnd->HideAccel = TRUE;
38 break;
39
40 case UIS_CLEAR:
41 if (Flags & UISF_HIDEFOCUS)
42 Wnd->HideFocus = FALSE;
43 if (Flags & UISF_HIDEACCEL)
44 Wnd->HideAccel = FALSE;
45 break;
46 }
47
48 return TRUE;
49 }
50
51 PWND FASTCALL IntGetWindowObject(HWND hWnd)
52 {
53 PWND Window;
54
55 if (!hWnd) return NULL;
56
57 Window = UserGetWindowObject(hWnd);
58 if (Window)
59 Window->head.cLockObj++;
60
61 return Window;
62 }
63
64 PWND FASTCALL VerifyWnd(PWND pWnd)
65 {
66 HWND hWnd;
67 UINT State, State2;
68
69 if (!pWnd) return NULL;
70
71 _SEH2_TRY
72 {
73 hWnd = UserHMGetHandle(pWnd);
74 State = pWnd->state;
75 State2 = pWnd->state2;
76 }
77 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
78 {
79 _SEH2_YIELD(return NULL);
80 }
81 _SEH2_END
82
83 if ( UserObjectInDestroy(hWnd) ||
84 State & WNDS_DESTROYED ||
85 State2 & WNDS2_INDESTROY )
86 return NULL;
87
88 return pWnd;
89 }
90
91 PWND FASTCALL ValidateHwndNoErr(HWND hWnd)
92 {
93 if (hWnd) return (PWND)UserGetObjectNoErr(gHandleTable, hWnd, TYPE_WINDOW);
94 return NULL;
95 }
96
97 /* Temp HACK */
98 PWND FASTCALL UserGetWindowObject(HWND hWnd)
99 {
100 PWND Window;
101
102 if (!hWnd)
103 {
104 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
105 return NULL;
106 }
107
108 Window = (PWND)UserGetObject(gHandleTable, hWnd, TYPE_WINDOW);
109 if (!Window || 0 != (Window->state & WNDS_DESTROYED))
110 {
111 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
112 return NULL;
113 }
114
115 return Window;
116 }
117
118 ULONG FASTCALL
119 IntSetStyle( PWND pwnd, ULONG set_bits, ULONG clear_bits )
120 {
121 ULONG styleOld, styleNew;
122 styleOld = pwnd->style;
123 styleNew = (pwnd->style | set_bits) & ~clear_bits;
124 if (styleNew == styleOld) return styleNew;
125 pwnd->style = styleNew;
126 if ((styleOld ^ styleNew) & WS_VISIBLE) // State Change.
127 {
128 if (styleOld & WS_VISIBLE) pwnd->head.pti->cVisWindows--;
129 if (styleNew & WS_VISIBLE) pwnd->head.pti->cVisWindows++;
130 DceResetActiveDCEs( pwnd );
131 }
132 return styleOld;
133 }
134
135 /*
136 * IntIsWindow
137 *
138 * The function determines whether the specified window handle identifies
139 * an existing window.
140 *
141 * Parameters
142 * hWnd
143 * Handle to the window to test.
144 *
145 * Return Value
146 * If the window handle identifies an existing window, the return value
147 * is TRUE. If the window handle does not identify an existing window,
148 * the return value is FALSE.
149 */
150
151 BOOL FASTCALL
152 IntIsWindow(HWND hWnd)
153 {
154 PWND Window;
155
156 if (!(Window = UserGetWindowObject(hWnd)))
157 {
158 return FALSE;
159 }
160
161 return TRUE;
162 }
163
164 BOOL FASTCALL
165 IntIsWindowVisible(PWND Wnd)
166 {
167 PWND Temp = Wnd;
168 for (;;)
169 {
170 if (!Temp) return TRUE;
171 if (!(Temp->style & WS_VISIBLE)) break;
172 if (Temp->style & WS_MINIMIZE && Temp != Wnd) break;
173 if (Temp->fnid == FNID_DESKTOP) return TRUE;
174 Temp = Temp->spwndParent;
175 }
176 return FALSE;
177 }
178
179 PWND FASTCALL
180 IntGetParent(PWND Wnd)
181 {
182 if (Wnd->style & WS_POPUP)
183 {
184 return Wnd->spwndOwner;
185 }
186 else if (Wnd->style & WS_CHILD)
187 {
188 return Wnd->spwndParent;
189 }
190
191 return NULL;
192 }
193
194 BOOL
195 FASTCALL
196 IntEnableWindow( HWND hWnd, BOOL bEnable )
197 {
198 BOOL Update;
199 PWND pWnd;
200 UINT bIsDisabled;
201
202 if(!(pWnd = UserGetWindowObject(hWnd)))
203 {
204 return FALSE;
205 }
206
207 /* check if updating is needed */
208 bIsDisabled = !!(pWnd->style & WS_DISABLED);
209 Update = bIsDisabled;
210
211 if (bEnable)
212 {
213 IntSetStyle( pWnd, 0, WS_DISABLED );
214 }
215 else
216 {
217 Update = !bIsDisabled;
218
219 co_IntSendMessage( hWnd, WM_CANCELMODE, 0, 0);
220
221 /* Remove keyboard focus from that window if it had focus */
222 if (hWnd == IntGetThreadFocusWindow())
223 {
224 TRACE("IntEnableWindow SF NULL\n");
225 co_UserSetFocus(NULL);
226 }
227 IntSetStyle( pWnd, WS_DISABLED, 0 );
228 }
229
230 if (Update)
231 {
232 IntNotifyWinEvent(EVENT_OBJECT_STATECHANGE, pWnd, OBJID_WINDOW, CHILDID_SELF, 0);
233 co_IntSendMessage(hWnd, WM_ENABLE, (LPARAM)bEnable, 0);
234 }
235 // Return nonzero if it was disabled, or zero if it wasn't:
236 return bIsDisabled;
237 }
238
239 /*
240 * IntWinListChildren
241 *
242 * Compile a list of all child window handles from given window.
243 *
244 * Remarks
245 * This function is similar to Wine WIN_ListChildren. The caller
246 * must free the returned list with ExFreePool.
247 */
248
249 HWND* FASTCALL
250 IntWinListChildren(PWND Window)
251 {
252 PWND Child;
253 HWND *List;
254 UINT Index, NumChildren = 0;
255
256 if (!Window) return NULL;
257
258 for (Child = Window->spwndChild; Child; Child = Child->spwndNext)
259 ++NumChildren;
260
261 List = ExAllocatePoolWithTag(PagedPool, (NumChildren + 1) * sizeof(HWND), USERTAG_WINDOWLIST);
262 if(!List)
263 {
264 ERR("Failed to allocate memory for children array\n");
265 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
266 return NULL;
267 }
268 for (Child = Window->spwndChild, Index = 0;
269 Child != NULL;
270 Child = Child->spwndNext, ++Index)
271 List[Index] = Child->head.h;
272 List[Index] = NULL;
273
274 return List;
275 }
276
277 PWND FASTCALL
278 IntGetNonChildAncestor(PWND pWnd)
279 {
280 while(pWnd && (pWnd->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
281 pWnd = pWnd->spwndParent;
282 return pWnd;
283 }
284
285 BOOL FASTCALL
286 IntIsTopLevelWindow(PWND pWnd)
287 {
288 if ( pWnd->spwndParent &&
289 pWnd->spwndParent == co_GetDesktopWindow(pWnd) ) return TRUE;
290 return FALSE;
291 }
292
293 BOOL FASTCALL
294 IntValidateOwnerDepth(PWND Wnd, PWND Owner)
295 {
296 INT Depth = 1;
297 for (;;)
298 {
299 if ( !Owner ) return gNestedWindowLimit >= Depth;
300 if (Owner == Wnd) break;
301 Owner = Owner->spwndOwner;
302 Depth++;
303 }
304 return FALSE;
305 }
306
307 HWND FASTCALL
308 IntGetWindow(HWND hWnd,
309 UINT uCmd)
310 {
311 PWND Wnd, FoundWnd;
312 HWND Ret = NULL;
313
314 Wnd = ValidateHwndNoErr(hWnd);
315 if (!Wnd)
316 return NULL;
317
318 FoundWnd = NULL;
319 switch (uCmd)
320 {
321 case GW_OWNER:
322 if (Wnd->spwndOwner != NULL)
323 FoundWnd = Wnd->spwndOwner;
324 break;
325
326 case GW_HWNDFIRST:
327 if(Wnd->spwndParent != NULL)
328 {
329 FoundWnd = Wnd->spwndParent;
330 if (FoundWnd->spwndChild != NULL)
331 FoundWnd = FoundWnd->spwndChild;
332 }
333 break;
334 case GW_HWNDNEXT:
335 if (Wnd->spwndNext != NULL)
336 FoundWnd = Wnd->spwndNext;
337 break;
338
339 case GW_HWNDPREV:
340 if (Wnd->spwndPrev != NULL)
341 FoundWnd = Wnd->spwndPrev;
342 break;
343
344 case GW_CHILD:
345 if (Wnd->spwndChild != NULL)
346 FoundWnd = Wnd->spwndChild;
347 break;
348
349 case GW_HWNDLAST:
350 FoundWnd = Wnd;
351 while ( FoundWnd->spwndNext != NULL)
352 FoundWnd = FoundWnd->spwndNext;
353 break;
354
355 default:
356 Wnd = NULL;
357 break;
358 }
359
360 if (FoundWnd != NULL)
361 Ret = UserHMGetHandle(FoundWnd);
362 return Ret;
363 }
364
365 /***********************************************************************
366 * IntSendDestroyMsg
367 */
368 static void IntSendDestroyMsg(HWND hWnd)
369 {
370 PTHREADINFO ti;
371 PWND Window;
372
373 ti = PsGetCurrentThreadWin32Thread();
374 Window = UserGetWindowObject(hWnd);
375
376 if (Window)
377 {
378 /* Look whether the focus is within the tree of windows we will
379 * be destroying.
380 */
381 // Rule #1
382 if ( ti->MessageQueue->spwndActive == Window || // Fixes CORE-106 RegSvr32 exit and return focus to CMD.
383 (ti->MessageQueue->spwndActive == NULL && ti->MessageQueue == IntGetFocusMessageQueue()) )
384 {
385 co_WinPosActivateOtherWindow(Window);
386 }
387
388 /* Fixes CMD properties closing and returning focus to CMD */
389 if (ti->MessageQueue->spwndFocus == Window)
390 {
391 if ((Window->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
392 {
393 co_UserSetFocus(Window->spwndParent);
394 }
395 else
396 {
397 co_UserSetFocus(NULL);
398 }
399 }
400
401 if (ti->MessageQueue->CaretInfo->hWnd == UserHMGetHandle(Window))
402 {
403 co_IntDestroyCaret(ti);
404 }
405 }
406
407 /*
408 * Send the WM_DESTROY to the window.
409 */
410
411 co_IntSendMessage(hWnd, WM_DESTROY, 0, 0);
412
413 /*
414 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
415 * make sure that the window still exists when we come back.
416 */
417
418 if (IntIsWindow(hWnd))
419 {
420 HWND* pWndArray;
421 int i;
422
423 if (!(pWndArray = IntWinListChildren( Window ))) return;
424
425 for (i = 0; pWndArray[i]; i++)
426 {
427 if (IntIsWindow( pWndArray[i] )) IntSendDestroyMsg( pWndArray[i] );
428 }
429 ExFreePoolWithTag(pWndArray, USERTAG_WINDOWLIST);
430 }
431 else
432 {
433 TRACE("destroyed itself while in WM_DESTROY!\n");
434 }
435 }
436
437 static VOID
438 UserFreeWindowInfo(PTHREADINFO ti, PWND Wnd)
439 {
440 PCLIENTINFO ClientInfo = GetWin32ClientInfo();
441
442 if (!Wnd) return;
443
444 if (ClientInfo->CallbackWnd.pWnd == DesktopHeapAddressToUser(Wnd))
445 {
446 ClientInfo->CallbackWnd.hWnd = NULL;
447 ClientInfo->CallbackWnd.pWnd = NULL;
448 }
449
450 if (Wnd->strName.Buffer != NULL)
451 {
452 Wnd->strName.Length = 0;
453 Wnd->strName.MaximumLength = 0;
454 DesktopHeapFree(Wnd->head.rpdesk,
455 Wnd->strName.Buffer);
456 Wnd->strName.Buffer = NULL;
457 }
458
459 // DesktopHeapFree(Wnd->head.rpdesk, Wnd);
460 // WindowObject->hWnd = NULL;
461 }
462
463 /***********************************************************************
464 * IntDestroyWindow
465 *
466 * Destroy storage associated to a window. "Internals" p.358
467 *
468 * This is the "functional" DestroyWindows function ei. all stuff
469 * done in CreateWindow is undone here and not in DestroyWindow:-P
470
471 */
472 LRESULT co_UserFreeWindow(PWND Window,
473 PPROCESSINFO ProcessData,
474 PTHREADINFO ThreadData,
475 BOOLEAN SendMessages)
476 {
477 HWND *Children;
478 HWND *ChildHandle;
479 PWND Child;
480 PMENU Menu;
481 BOOLEAN BelongsToThreadData;
482
483 ASSERT(Window);
484
485 if(Window->state2 & WNDS2_INDESTROY)
486 {
487 TRACE("Tried to call IntDestroyWindow() twice\n");
488 return 0;
489 }
490 Window->state2 |= WNDS2_INDESTROY;
491 Window->style &= ~WS_VISIBLE;
492 Window->head.pti->cVisWindows--;
493
494
495 /* remove the window already at this point from the thread window list so we
496 don't get into trouble when destroying the thread windows while we're still
497 in IntDestroyWindow() */
498 RemoveEntryList(&Window->ThreadListEntry);
499
500 BelongsToThreadData = IntWndBelongsToThread(Window, ThreadData);
501
502 IntDeRegisterShellHookWindow(UserHMGetHandle(Window));
503
504 /* free child windows */
505 Children = IntWinListChildren(Window);
506 if (Children)
507 {
508 for (ChildHandle = Children; *ChildHandle; ++ChildHandle)
509 {
510 if ((Child = IntGetWindowObject(*ChildHandle)))
511 {
512 if(!IntWndBelongsToThread(Child, ThreadData))
513 {
514 /* send WM_DESTROY messages to windows not belonging to the same thread */
515 co_IntSendMessage( UserHMGetHandle(Child), WM_ASYNC_DESTROYWINDOW, 0, 0 );
516 }
517 else
518 co_UserFreeWindow(Child, ProcessData, ThreadData, SendMessages);
519
520 UserDereferenceObject(Child);
521 }
522 }
523 ExFreePoolWithTag(Children, USERTAG_WINDOWLIST);
524 }
525
526 if(SendMessages)
527 {
528 /*
529 * Clear the update region to make sure no WM_PAINT messages will be
530 * generated for this window while processing the WM_NCDESTROY.
531 */
532 co_UserRedrawWindow(Window, NULL, 0,
533 RDW_VALIDATE | RDW_NOFRAME | RDW_NOERASE |
534 RDW_NOINTERNALPAINT | RDW_NOCHILDREN);
535 if(BelongsToThreadData)
536 co_IntSendMessage(UserHMGetHandle(Window), WM_NCDESTROY, 0, 0);
537 }
538
539 DestroyTimersForWindow(ThreadData, Window);
540
541 /* Unregister hot keys */
542 UnregisterWindowHotKeys(Window);
543
544 /* flush the message queue */
545 MsqRemoveWindowMessagesFromQueue(Window);
546
547 /* from now on no messages can be sent to this window anymore */
548 Window->state |= WNDS_DESTROYED;
549 Window->fnid |= FNID_FREED;
550
551 /* don't remove the WINDOWSTATUS_DESTROYING bit */
552
553 /* reset shell window handles */
554 if(ThreadData->rpdesk)
555 {
556 if (Window->head.h == ThreadData->rpdesk->rpwinstaParent->ShellWindow)
557 ThreadData->rpdesk->rpwinstaParent->ShellWindow = NULL;
558
559 if (Window->head.h == ThreadData->rpdesk->rpwinstaParent->ShellListView)
560 ThreadData->rpdesk->rpwinstaParent->ShellListView = NULL;
561 }
562
563 /* Fixes dialog test_focus breakage due to r66237. */
564 if (ThreadData->MessageQueue->spwndFocus == Window)
565 ThreadData->MessageQueue->spwndFocus = NULL;
566
567 if (ThreadData->MessageQueue->spwndActive == Window)
568 ThreadData->MessageQueue->spwndActive = NULL;
569
570 if (ThreadData->MessageQueue->spwndCapture == Window)
571 {
572 IntReleaseCapture();
573 }
574
575 //// Now kill those remaining "PAINTING BUG: Thread marked as containing dirty windows" spam!!!
576 if ( Window->hrgnUpdate != NULL || Window->state & WNDS_INTERNALPAINT )
577 {
578 MsqDecPaintCountQueue(Window->head.pti);
579 if (Window->hrgnUpdate > HRGN_WINDOW && GreIsHandleValid(Window->hrgnUpdate))
580 {
581 GreDeleteObject(Window->hrgnUpdate);
582 }
583 Window->hrgnUpdate = NULL;
584 Window->state &= ~WNDS_INTERNALPAINT;
585 }
586
587 if (Window->state & (WNDS_SENDERASEBACKGROUND|WNDS_SENDNCPAINT))
588 {
589 Window->state &= ~(WNDS_SENDERASEBACKGROUND|WNDS_SENDNCPAINT);
590 }
591
592 if ( ((Window->style & (WS_CHILD|WS_POPUP)) != WS_CHILD) &&
593 Window->IDMenu &&
594 (Menu = UserGetMenuObject((HMENU)Window->IDMenu)))
595 {
596 IntDestroyMenuObject(Menu, TRUE);
597 Window->IDMenu = 0;
598 }
599
600 if(Window->SystemMenu
601 && (Menu = UserGetMenuObject(Window->SystemMenu)))
602 {
603 IntDestroyMenuObject(Menu, TRUE);
604 Window->SystemMenu = (HMENU)0;
605 }
606
607 DceFreeWindowDCE(Window); /* Always do this to catch orphaned DCs */
608
609 IntUnlinkWindow(Window);
610
611 if (Window->PropListItems)
612 {
613 IntRemoveWindowProp(Window);
614 TRACE("Window->PropListItems %lu\n",Window->PropListItems);
615 ASSERT(Window->PropListItems==0);
616 }
617
618 UserReferenceObject(Window);
619 UserDeleteObject(UserHMGetHandle(Window), TYPE_WINDOW);
620
621 IntDestroyScrollBars(Window);
622
623 if (Window->pcls->atomClassName == gaGuiConsoleWndClass)
624 {
625 /* Count only console windows manually */
626 co_IntUserManualGuiCheck(FALSE);
627 }
628
629 /* dereference the class */
630 NT_ASSERT(Window->head.pti != NULL);
631 IntDereferenceClass(Window->pcls,
632 Window->head.pti->pDeskInfo,
633 Window->head.pti->ppi);
634 Window->pcls = NULL;
635
636 if(Window->hrgnClip)
637 {
638 IntGdiSetRegionOwner(Window->hrgnClip, GDI_OBJ_HMGR_POWNED);
639 GreDeleteObject(Window->hrgnClip);
640 Window->hrgnClip = NULL;
641 }
642 Window->head.pti->cWindows--;
643
644 // ASSERT(Window != NULL);
645 UserFreeWindowInfo(Window->head.pti, Window);
646
647 UserDereferenceObject(Window);
648
649 UserClipboardFreeWindow(Window);
650
651 return 0;
652 }
653
654 //
655 // Same as User32:IntGetWndProc.
656 //
657 WNDPROC FASTCALL
658 IntGetWindowProc(PWND pWnd,
659 BOOL Ansi)
660 {
661 INT i;
662 PCLS Class;
663 WNDPROC gcpd, Ret = 0;
664
665 ASSERT(UserIsEnteredExclusive() == TRUE);
666
667 Class = pWnd->pcls;
668
669 if (pWnd->state & WNDS_SERVERSIDEWINDOWPROC)
670 {
671 for ( i = FNID_FIRST; i <= FNID_SWITCH; i++)
672 {
673 if (GETPFNSERVER(i) == pWnd->lpfnWndProc)
674 {
675 if (Ansi)
676 Ret = GETPFNCLIENTA(i);
677 else
678 Ret = GETPFNCLIENTW(i);
679 }
680 }
681 return Ret;
682 }
683
684 if (Class->fnid == FNID_EDIT)
685 Ret = pWnd->lpfnWndProc;
686 else
687 {
688 Ret = pWnd->lpfnWndProc;
689
690 if (Class->fnid <= FNID_GHOST && Class->fnid >= FNID_BUTTON)
691 {
692 if (Ansi)
693 {
694 if (GETPFNCLIENTW(Class->fnid) == pWnd->lpfnWndProc)
695 Ret = GETPFNCLIENTA(Class->fnid);
696 }
697 else
698 {
699 if (GETPFNCLIENTA(Class->fnid) == pWnd->lpfnWndProc)
700 Ret = GETPFNCLIENTW(Class->fnid);
701 }
702 }
703 if ( Ret != pWnd->lpfnWndProc)
704 return Ret;
705 }
706 if ( Ansi == !!(pWnd->state & WNDS_ANSIWINDOWPROC) )
707 return Ret;
708
709 gcpd = (WNDPROC)UserGetCPD(
710 pWnd,
711 (Ansi ? UserGetCPDA2U : UserGetCPDU2A )|UserGetCPDWindow,
712 (ULONG_PTR)Ret);
713
714 return (gcpd ? gcpd : Ret);
715 }
716
717 static WNDPROC
718 IntSetWindowProc(PWND pWnd,
719 WNDPROC NewWndProc,
720 BOOL Ansi)
721 {
722 INT i;
723 PCALLPROCDATA CallProc;
724 PCLS Class;
725 WNDPROC Ret, chWndProc = NULL;
726
727 // Retrieve previous window proc.
728 Ret = IntGetWindowProc(pWnd, Ansi);
729
730 Class = pWnd->pcls;
731
732 if (IsCallProcHandle(NewWndProc))
733 {
734 CallProc = UserGetObject(gHandleTable, NewWndProc, TYPE_CALLPROC);
735 if (CallProc)
736 { // Reset new WndProc.
737 NewWndProc = CallProc->pfnClientPrevious;
738 // Reset Ansi from CallProc handle. This is expected with wine "deftest".
739 Ansi = !!(CallProc->wType & UserGetCPDU2A);
740 }
741 }
742 // Switch from Client Side call to Server Side call if match. Ref: "deftest".
743 for ( i = FNID_FIRST; i <= FNID_SWITCH; i++)
744 {
745 if (GETPFNCLIENTW(i) == NewWndProc)
746 {
747 chWndProc = GETPFNSERVER(i);
748 break;
749 }
750 if (GETPFNCLIENTA(i) == NewWndProc)
751 {
752 chWndProc = GETPFNSERVER(i);
753 break;
754 }
755 }
756 // If match, set/reset to Server Side and clear ansi.
757 if (chWndProc)
758 {
759 pWnd->lpfnWndProc = chWndProc;
760 pWnd->Unicode = TRUE;
761 pWnd->state &= ~WNDS_ANSIWINDOWPROC;
762 pWnd->state |= WNDS_SERVERSIDEWINDOWPROC;
763 }
764 else
765 {
766 pWnd->Unicode = !Ansi;
767 // Handle the state change in here.
768 if (Ansi)
769 pWnd->state |= WNDS_ANSIWINDOWPROC;
770 else
771 pWnd->state &= ~WNDS_ANSIWINDOWPROC;
772
773 if (pWnd->state & WNDS_SERVERSIDEWINDOWPROC)
774 pWnd->state &= ~WNDS_SERVERSIDEWINDOWPROC;
775
776 if (!NewWndProc) NewWndProc = pWnd->lpfnWndProc;
777
778 if (Class->fnid <= FNID_GHOST && Class->fnid >= FNID_BUTTON)
779 {
780 if (Ansi)
781 {
782 if (GETPFNCLIENTW(Class->fnid) == NewWndProc)
783 chWndProc = GETPFNCLIENTA(Class->fnid);
784 }
785 else
786 {
787 if (GETPFNCLIENTA(Class->fnid) == NewWndProc)
788 chWndProc = GETPFNCLIENTW(Class->fnid);
789 }
790 }
791 // Now set the new window proc.
792 pWnd->lpfnWndProc = (chWndProc ? chWndProc : NewWndProc);
793 }
794 return Ret;
795 }
796
797
798 /* INTERNAL ******************************************************************/
799
800 ////
801 // This fixes a check for children messages that need paint while searching the parents messages!
802 // Fixes wine msg:test_paint_messages:WmParentErasePaint ..
803 ////
804 BOOL FASTCALL
805 IntIsChildWindow(PWND Parent, PWND BaseWindow)
806 {
807 PWND Window = BaseWindow;
808 do
809 {
810 if ( Window == NULL || (Window->style & (WS_POPUP|WS_CHILD)) != WS_CHILD )
811 return FALSE;
812
813 Window = Window->spwndParent;
814 }
815 while(Parent != Window);
816 return TRUE;
817 }
818 ////
819
820 /*
821 Link the window into siblings list
822 children and parent are kept in place.
823 */
824 VOID FASTCALL
825 IntLinkWindow(
826 PWND Wnd,
827 PWND WndInsertAfter /* set to NULL if top sibling */
828 )
829 {
830 if ((Wnd->spwndPrev = WndInsertAfter))
831 {
832 /* link after WndInsertAfter */
833 if ((Wnd->spwndNext = WndInsertAfter->spwndNext))
834 Wnd->spwndNext->spwndPrev = Wnd;
835
836 Wnd->spwndPrev->spwndNext = Wnd;
837 }
838 else
839 {
840 /* link at top */
841 if ((Wnd->spwndNext = Wnd->spwndParent->spwndChild))
842 Wnd->spwndNext->spwndPrev = Wnd;
843
844 Wnd->spwndParent->spwndChild = Wnd;
845 }
846 }
847
848 /*
849 Note: Wnd->spwndParent can be null if it is the desktop.
850 */
851 VOID FASTCALL IntLinkHwnd(PWND Wnd, HWND hWndPrev)
852 {
853 if (hWndPrev == HWND_NOTOPMOST)
854 {
855 if (!(Wnd->ExStyle & WS_EX_TOPMOST) &&
856 (Wnd->ExStyle2 & WS_EX2_LINKED)) return; /* nothing to do */
857 Wnd->ExStyle &= ~WS_EX_TOPMOST;
858 hWndPrev = HWND_TOP; /* fallback to the HWND_TOP case */
859 }
860
861 IntUnlinkWindow(Wnd); /* unlink it from the previous location */
862
863 if (hWndPrev == HWND_BOTTOM)
864 {
865 /* Link in the bottom of the list */
866 PWND WndInsertAfter;
867
868 WndInsertAfter = Wnd->spwndParent->spwndChild;
869 while( WndInsertAfter && WndInsertAfter->spwndNext)
870 WndInsertAfter = WndInsertAfter->spwndNext;
871
872 IntLinkWindow(Wnd, WndInsertAfter);
873 Wnd->ExStyle &= ~WS_EX_TOPMOST;
874 }
875 else if (hWndPrev == HWND_TOPMOST)
876 {
877 /* Link in the top of the list */
878 IntLinkWindow(Wnd, NULL);
879
880 Wnd->ExStyle |= WS_EX_TOPMOST;
881 }
882 else if (hWndPrev == HWND_TOP)
883 {
884 /* Link it after the last topmost window */
885 PWND WndInsertBefore;
886
887 WndInsertBefore = Wnd->spwndParent->spwndChild;
888
889 if (!(Wnd->ExStyle & WS_EX_TOPMOST)) /* put it above the first non-topmost window */
890 {
891 while (WndInsertBefore != NULL && WndInsertBefore->spwndNext != NULL)
892 {
893 if (!(WndInsertBefore->ExStyle & WS_EX_TOPMOST)) break;
894 if (WndInsertBefore == Wnd->spwndOwner) /* keep it above owner */
895 {
896 Wnd->ExStyle |= WS_EX_TOPMOST;
897 break;
898 }
899 WndInsertBefore = WndInsertBefore->spwndNext;
900 }
901 }
902
903 IntLinkWindow(Wnd, WndInsertBefore ? WndInsertBefore->spwndPrev : NULL);
904 }
905 else
906 {
907 /* Link it after hWndPrev */
908 PWND WndInsertAfter;
909
910 WndInsertAfter = UserGetWindowObject(hWndPrev);
911 /* Are we called with an erroneous handle */
912 if(WndInsertAfter == NULL)
913 {
914 /* Link in a default position */
915 IntLinkHwnd(Wnd, HWND_TOP);
916 return;
917 }
918
919 IntLinkWindow(Wnd, WndInsertAfter);
920
921 /* Fix the WS_EX_TOPMOST flag */
922 if (!(WndInsertAfter->ExStyle & WS_EX_TOPMOST))
923 {
924 Wnd->ExStyle &= ~WS_EX_TOPMOST;
925 }
926 else
927 {
928 if(WndInsertAfter->spwndNext &&
929 WndInsertAfter->spwndNext->ExStyle & WS_EX_TOPMOST)
930 {
931 Wnd->ExStyle |= WS_EX_TOPMOST;
932 }
933 }
934 }
935 Wnd->ExStyle2 |= WS_EX2_LINKED;
936 }
937
938 VOID FASTCALL
939 IntProcessOwnerSwap(PWND Wnd, PWND WndNewOwner, PWND WndOldOwner)
940 {
941 if (WndOldOwner)
942 {
943 if (Wnd->head.pti != WndOldOwner->head.pti)
944 {
945 if (!WndNewOwner ||
946 Wnd->head.pti == WndNewOwner->head.pti ||
947 WndOldOwner->head.pti != WndNewOwner->head.pti )
948 {
949 //ERR("ProcessOwnerSwap Old out.\n");
950 UserAttachThreadInput(Wnd->head.pti, WndOldOwner->head.pti, FALSE);
951 }
952 }
953 }
954 if (WndNewOwner)
955 {
956 if (Wnd->head.pti != WndNewOwner->head.pti)
957 {
958 if (!WndOldOwner ||
959 WndOldOwner->head.pti != WndNewOwner->head.pti )
960 {
961 //ERR("ProcessOwnerSwap New in.\n");
962 UserAttachThreadInput(Wnd->head.pti, WndNewOwner->head.pti, TRUE);
963 }
964 }
965 }
966 // FIXME: System Tray checks.
967 }
968
969 HWND FASTCALL
970 IntSetOwner(HWND hWnd, HWND hWndNewOwner)
971 {
972 PWND Wnd, WndOldOwner, WndNewOwner;
973 HWND ret;
974
975 Wnd = IntGetWindowObject(hWnd);
976 if(!Wnd)
977 return NULL;
978
979 WndOldOwner = Wnd->spwndOwner;
980
981 ret = WndOldOwner ? UserHMGetHandle(WndOldOwner) : 0;
982 WndNewOwner = UserGetWindowObject(hWndNewOwner);
983
984 if (!WndNewOwner && hWndNewOwner)
985 {
986 EngSetLastError(ERROR_INVALID_PARAMETER);
987 ret = NULL;
988 goto Error;
989 }
990
991 /* if parent belongs to a different thread and the window isn't */
992 /* top-level, attach the two threads */
993 IntProcessOwnerSwap(Wnd, WndNewOwner, WndOldOwner);
994
995 if (IntValidateOwnerDepth(Wnd, WndNewOwner))
996 {
997 if (WndNewOwner)
998 {
999 Wnd->spwndOwner= WndNewOwner;
1000 }
1001 else
1002 {
1003 Wnd->spwndOwner = NULL;
1004 }
1005 }
1006 else
1007 {
1008 IntProcessOwnerSwap(Wnd, WndOldOwner, WndNewOwner);
1009 EngSetLastError(ERROR_INVALID_PARAMETER);
1010 ret = NULL;
1011 }
1012 Error:
1013 UserDereferenceObject(Wnd);
1014 return ret;
1015 }
1016
1017 PWND FASTCALL
1018 co_IntSetParent(PWND Wnd, PWND WndNewParent)
1019 {
1020 PWND WndOldParent, pWndExam;
1021 BOOL WasVisible;
1022 POINT pt;
1023 int swFlags = SWP_NOSIZE|SWP_NOZORDER;
1024
1025 ASSERT(Wnd);
1026 ASSERT(WndNewParent);
1027 ASSERT_REFS_CO(Wnd);
1028 ASSERT_REFS_CO(WndNewParent);
1029
1030 if (Wnd == Wnd->head.rpdesk->spwndMessage)
1031 {
1032 EngSetLastError(ERROR_ACCESS_DENIED);
1033 return( NULL);
1034 }
1035
1036 /* Some applications try to set a child as a parent */
1037 if (IntIsChildWindow(Wnd, WndNewParent))
1038 {
1039 TRACE("IntSetParent try to set a child as a parent.\n");
1040 EngSetLastError( ERROR_INVALID_PARAMETER );
1041 return NULL;
1042 }
1043
1044 pWndExam = WndNewParent; // Load parent Window to examine.
1045 // Now test for set parent to parent hit.
1046 while (pWndExam)
1047 {
1048 if (Wnd == pWndExam)
1049 {
1050 TRACE("IntSetParent Failed Test for set parent to parent!\n");
1051 EngSetLastError(ERROR_INVALID_PARAMETER);
1052 return NULL;
1053 }
1054 pWndExam = pWndExam->spwndParent;
1055 }
1056
1057 /*
1058 * Windows hides the window first, then shows it again
1059 * including the WM_SHOWWINDOW messages and all
1060 */
1061 WasVisible = co_WinPosShowWindow(Wnd, SW_HIDE);
1062
1063 /* Window must belong to current process */
1064 if (Wnd->head.pti->ppi != PsGetCurrentProcessWin32Process())
1065 {
1066 ERR("IntSetParent Window must belong to current process!\n");
1067 return NULL;
1068 }
1069
1070 WndOldParent = Wnd->spwndParent;
1071
1072 if ( WndOldParent &&
1073 WndOldParent->ExStyle & WS_EX_LAYOUTRTL)
1074 pt.x = Wnd->rcWindow.right;
1075 else
1076 pt.x = Wnd->rcWindow.left;
1077 pt.y = Wnd->rcWindow.top;
1078
1079 IntScreenToClient(WndOldParent, &pt);
1080
1081 if (WndOldParent) UserReferenceObject(WndOldParent); /* Caller must deref */
1082
1083 if (WndNewParent != WndOldParent)
1084 {
1085 /* Unlink the window from the siblings list */
1086 IntUnlinkWindow(Wnd);
1087 Wnd->ExStyle2 &= ~WS_EX2_LINKED;
1088
1089 /* Set the new parent */
1090 Wnd->spwndParent = WndNewParent;
1091
1092 if ( Wnd->style & WS_CHILD &&
1093 Wnd->spwndOwner &&
1094 Wnd->spwndOwner->ExStyle & WS_EX_TOPMOST )
1095 {
1096 ERR("SetParent Top Most from Pop up!\n");
1097 Wnd->ExStyle |= WS_EX_TOPMOST;
1098 }
1099
1100 /* Link the window with its new siblings */
1101 IntLinkHwnd( Wnd,
1102 ((0 == (Wnd->ExStyle & WS_EX_TOPMOST) &&
1103 WndNewParent == UserGetDesktopWindow() ) ? HWND_TOP : HWND_TOPMOST ) );
1104
1105 }
1106
1107 if ( WndNewParent == co_GetDesktopWindow(Wnd) &&
1108 !(Wnd->style & WS_CLIPSIBLINGS) )
1109 {
1110 Wnd->style |= WS_CLIPSIBLINGS;
1111 DceResetActiveDCEs(Wnd);
1112 }
1113
1114 /* if parent belongs to a different thread and the window isn't */
1115 /* top-level, attach the two threads */
1116 if ((Wnd->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
1117 {
1118 if ( Wnd->spwndParent != co_GetDesktopWindow(Wnd))
1119 {
1120 if (WndOldParent && (Wnd->head.pti != WndOldParent->head.pti))
1121 {
1122 //ERR("SetParent Old out.\n");
1123 UserAttachThreadInput(Wnd->head.pti, WndOldParent->head.pti, FALSE);
1124 }
1125 }
1126 if ( WndNewParent != co_GetDesktopWindow(Wnd))
1127 {
1128 if (Wnd->head.pti != WndNewParent->head.pti)
1129 {
1130 //ERR("SetParent New in.\n");
1131 UserAttachThreadInput(Wnd->head.pti, WndNewParent->head.pti, TRUE);
1132 }
1133 }
1134 }
1135
1136 if (WndOldParent == UserGetMessageWindow() || WndNewParent == UserGetMessageWindow())
1137 swFlags |= SWP_NOACTIVATE;
1138
1139 IntNotifyWinEvent(EVENT_OBJECT_PARENTCHANGE, Wnd ,OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
1140 /*
1141 * SetParent additionally needs to make hwnd the top window
1142 * in the z-order and send the expected WM_WINDOWPOSCHANGING and
1143 * WM_WINDOWPOSCHANGED notification messages.
1144 */
1145 //ERR("IntSetParent SetWindowPos 1\n");
1146 co_WinPosSetWindowPos( Wnd,
1147 (0 == (Wnd->ExStyle & WS_EX_TOPMOST) ? HWND_TOP : HWND_TOPMOST),
1148 pt.x, pt.y, 0, 0, swFlags);
1149 //ERR("IntSetParent SetWindowPos 2 X %d Y %d\n",pt.x, pt.y);
1150 if (WasVisible) co_WinPosShowWindow(Wnd, SW_SHOWNORMAL);
1151
1152 return WndOldParent;
1153 }
1154
1155 HWND FASTCALL
1156 co_UserSetParent(HWND hWndChild, HWND hWndNewParent)
1157 {
1158 PWND Wnd = NULL, WndParent = NULL, WndOldParent;
1159 HWND hWndOldParent = NULL;
1160 USER_REFERENCE_ENTRY Ref, ParentRef;
1161
1162 if (IntIsBroadcastHwnd(hWndChild) || IntIsBroadcastHwnd(hWndNewParent))
1163 {
1164 EngSetLastError(ERROR_INVALID_PARAMETER);
1165 return( NULL);
1166 }
1167
1168 if (hWndChild == IntGetDesktopWindow())
1169 {
1170 ERR("UserSetParent Access Denied!\n");
1171 EngSetLastError(ERROR_ACCESS_DENIED);
1172 return( NULL);
1173 }
1174
1175 if (hWndNewParent)
1176 {
1177 if (!(WndParent = UserGetWindowObject(hWndNewParent)))
1178 {
1179 ERR("UserSetParent Bad New Parent!\n");
1180 return( NULL);
1181 }
1182 }
1183 else
1184 {
1185 if (!(WndParent = UserGetWindowObject(IntGetDesktopWindow())))
1186 {
1187 return( NULL);
1188 }
1189 }
1190
1191 if (!(Wnd = UserGetWindowObject(hWndChild)))
1192 {
1193 ERR("UserSetParent Bad Child!\n");
1194 return( NULL);
1195 }
1196
1197 UserRefObjectCo(Wnd, &Ref);
1198 UserRefObjectCo(WndParent, &ParentRef);
1199 //ERR("Enter co_IntSetParent\n");
1200 WndOldParent = co_IntSetParent(Wnd, WndParent);
1201 //ERR("Leave co_IntSetParent\n");
1202 UserDerefObjectCo(WndParent);
1203 UserDerefObjectCo(Wnd);
1204
1205 if (WndOldParent)
1206 {
1207 hWndOldParent = WndOldParent->head.h;
1208 UserDereferenceObject(WndOldParent);
1209 }
1210
1211 return( hWndOldParent);
1212 }
1213
1214 /* Unlink the window from siblings. children and parent are kept in place. */
1215 VOID FASTCALL
1216 IntUnlinkWindow(PWND Wnd)
1217 {
1218 if (Wnd->spwndNext)
1219 Wnd->spwndNext->spwndPrev = Wnd->spwndPrev;
1220
1221 if (Wnd->spwndPrev)
1222 Wnd->spwndPrev->spwndNext = Wnd->spwndNext;
1223
1224 if (Wnd->spwndParent && Wnd->spwndParent->spwndChild == Wnd)
1225 Wnd->spwndParent->spwndChild = Wnd->spwndNext;
1226
1227 Wnd->spwndPrev = Wnd->spwndNext = NULL;
1228 }
1229
1230 /* FUNCTIONS *****************************************************************/
1231
1232 /*
1233 * As best as I can figure, this function is used by EnumWindows,
1234 * EnumChildWindows, EnumDesktopWindows, & EnumThreadWindows.
1235 *
1236 * It's supposed to build a list of HWNDs to return to the caller.
1237 * We can figure out what kind of list by what parameters are
1238 * passed to us.
1239 */
1240 /*
1241 * @implemented
1242 */
1243 NTSTATUS
1244 APIENTRY
1245 NtUserBuildHwndList(
1246 HDESK hDesktop,
1247 HWND hwndParent,
1248 BOOLEAN bChildren,
1249 ULONG dwThreadId,
1250 ULONG lParam,
1251 HWND* pWnd,
1252 ULONG* pBufSize)
1253 {
1254 NTSTATUS Status;
1255 ULONG dwCount = 0;
1256
1257 if (pBufSize == 0)
1258 return ERROR_INVALID_PARAMETER;
1259
1260 if (hwndParent || !dwThreadId)
1261 {
1262 PDESKTOP Desktop;
1263 PWND Parent, Window;
1264
1265 if(!hwndParent)
1266 {
1267 if(hDesktop == NULL && !(Desktop = IntGetActiveDesktop()))
1268 {
1269 return ERROR_INVALID_HANDLE;
1270 }
1271
1272 if(hDesktop)
1273 {
1274 Status = IntValidateDesktopHandle(hDesktop,
1275 UserMode,
1276 0,
1277 &Desktop);
1278 if(!NT_SUCCESS(Status))
1279 {
1280 return ERROR_INVALID_HANDLE;
1281 }
1282 }
1283 hwndParent = Desktop->DesktopWindow;
1284 }
1285 else
1286 {
1287 hDesktop = 0;
1288 }
1289
1290 if((Parent = UserGetWindowObject(hwndParent)) &&
1291 (Window = Parent->spwndChild))
1292 {
1293 BOOL bGoDown = TRUE;
1294
1295 Status = STATUS_SUCCESS;
1296 while(TRUE)
1297 {
1298 if (bGoDown)
1299 {
1300 if(dwCount++ < *pBufSize && pWnd)
1301 {
1302 _SEH2_TRY
1303 {
1304 ProbeForWrite(pWnd, sizeof(HWND), 1);
1305 *pWnd = Window->head.h;
1306 pWnd++;
1307 }
1308 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1309 {
1310 Status = _SEH2_GetExceptionCode();
1311 }
1312 _SEH2_END
1313 if(!NT_SUCCESS(Status))
1314 {
1315 SetLastNtError(Status);
1316 break;
1317 }
1318 }
1319 if (Window->spwndChild && bChildren)
1320 {
1321 Window = Window->spwndChild;
1322 continue;
1323 }
1324 bGoDown = FALSE;
1325 }
1326 if (Window->spwndNext)
1327 {
1328 Window = Window->spwndNext;
1329 bGoDown = TRUE;
1330 continue;
1331 }
1332 Window = Window->spwndParent;
1333 if (Window == Parent)
1334 {
1335 break;
1336 }
1337 }
1338 }
1339
1340 if(hDesktop)
1341 {
1342 ObDereferenceObject(Desktop);
1343 }
1344 }
1345 else // Build EnumThreadWindows list!
1346 {
1347 PETHREAD Thread;
1348 PTHREADINFO W32Thread;
1349 PWND Window;
1350 HWND *List = NULL;
1351
1352 Status = PsLookupThreadByThreadId((HANDLE)dwThreadId, &Thread);
1353 if (!NT_SUCCESS(Status))
1354 {
1355 ERR("Thread Id is not valid!\n");
1356 return ERROR_INVALID_PARAMETER;
1357 }
1358 if (!(W32Thread = (PTHREADINFO)Thread->Tcb.Win32Thread))
1359 {
1360 ObDereferenceObject(Thread);
1361 TRACE("Tried to enumerate windows of a non gui thread\n");
1362 return ERROR_INVALID_PARAMETER;
1363 }
1364
1365 // Do not use Thread link list due to co_UserFreeWindow!!!
1366 // Current = W32Thread->WindowListHead.Flink;
1367 // Fixes Api:CreateWindowEx tests!!!
1368 List = IntWinListChildren(UserGetDesktopWindow());
1369 if (List)
1370 {
1371 int i;
1372 for (i = 0; List[i]; i++)
1373 {
1374 Window = ValidateHwndNoErr(List[i]);
1375 if (Window && Window->head.pti == W32Thread)
1376 {
1377 if (dwCount < *pBufSize && pWnd)
1378 {
1379 _SEH2_TRY
1380 {
1381 ProbeForWrite(pWnd, sizeof(HWND), 1);
1382 *pWnd = Window->head.h;
1383 pWnd++;
1384 }
1385 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1386 {
1387 Status = _SEH2_GetExceptionCode();
1388 }
1389 _SEH2_END
1390 if (!NT_SUCCESS(Status))
1391 {
1392 ERR("Failure to build window list!\n");
1393 SetLastNtError(Status);
1394 break;
1395 }
1396 }
1397 dwCount++;
1398 }
1399 }
1400 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
1401 }
1402
1403 ObDereferenceObject(Thread);
1404 }
1405
1406 *pBufSize = dwCount;
1407 return STATUS_SUCCESS;
1408 }
1409
1410 static void IntSendParentNotify( PWND pWindow, UINT msg )
1411 {
1412 if ( (pWindow->style & (WS_CHILD | WS_POPUP)) == WS_CHILD &&
1413 !(pWindow->ExStyle & WS_EX_NOPARENTNOTIFY))
1414 {
1415 if (VerifyWnd(pWindow->spwndParent) && pWindow->spwndParent != UserGetDesktopWindow())
1416 {
1417 USER_REFERENCE_ENTRY Ref;
1418 UserRefObjectCo(pWindow->spwndParent, &Ref);
1419 co_IntSendMessage( pWindow->spwndParent->head.h,
1420 WM_PARENTNOTIFY,
1421 MAKEWPARAM( msg, pWindow->IDMenu),
1422 (LPARAM)pWindow->head.h );
1423 UserDerefObjectCo(pWindow->spwndParent);
1424 }
1425 }
1426 }
1427
1428 void FASTCALL
1429 IntFixWindowCoordinates(CREATESTRUCTW* Cs, PWND ParentWindow, DWORD* dwShowMode)
1430 {
1431 #define IS_DEFAULT(x) ((x) == CW_USEDEFAULT || (x) == (SHORT)0x8000)
1432
1433 /* default positioning for overlapped windows */
1434 if(!(Cs->style & (WS_POPUP | WS_CHILD)))
1435 {
1436 PMONITOR pMonitor;
1437 PRTL_USER_PROCESS_PARAMETERS ProcessParams;
1438
1439 pMonitor = UserGetPrimaryMonitor();
1440
1441 /* Check if we don't have a monitor attached yet */
1442 if(pMonitor == NULL)
1443 {
1444 Cs->x = Cs->y = 0;
1445 Cs->cx = 800;
1446 Cs->cy = 600;
1447 return;
1448 }
1449
1450 ProcessParams = PsGetCurrentProcess()->Peb->ProcessParameters;
1451
1452 if (IS_DEFAULT(Cs->x))
1453 {
1454 if (!IS_DEFAULT(Cs->y)) *dwShowMode = Cs->y;
1455
1456 if(ProcessParams->WindowFlags & STARTF_USEPOSITION)
1457 {
1458 Cs->x = ProcessParams->StartingX;
1459 Cs->y = ProcessParams->StartingY;
1460 }
1461 else
1462 {
1463 Cs->x = pMonitor->cWndStack * (UserGetSystemMetrics(SM_CXSIZE) + UserGetSystemMetrics(SM_CXFRAME));
1464 Cs->y = pMonitor->cWndStack * (UserGetSystemMetrics(SM_CYSIZE) + UserGetSystemMetrics(SM_CYFRAME));
1465 if (Cs->x > ((pMonitor->rcWork.right - pMonitor->rcWork.left) / 4) ||
1466 Cs->y > ((pMonitor->rcWork.bottom - pMonitor->rcWork.top) / 4))
1467 {
1468 /* reset counter and position */
1469 Cs->x = 0;
1470 Cs->y = 0;
1471 pMonitor->cWndStack = 0;
1472 }
1473 pMonitor->cWndStack++;
1474 }
1475 }
1476
1477 if (IS_DEFAULT(Cs->cx))
1478 {
1479 if (ProcessParams->WindowFlags & STARTF_USEPOSITION)
1480 {
1481 Cs->cx = ProcessParams->CountX;
1482 Cs->cy = ProcessParams->CountY;
1483 }
1484 else
1485 {
1486 Cs->cx = (pMonitor->rcWork.right - pMonitor->rcWork.left) * 3 / 4;
1487 Cs->cy = (pMonitor->rcWork.bottom - pMonitor->rcWork.top) * 3 / 4;
1488 }
1489 }
1490 /* neither x nor cx are default. Check the y values .
1491 * In the trace we see Outlook and Outlook Express using
1492 * cy set to CW_USEDEFAULT when opening the address book.
1493 */
1494 else if (IS_DEFAULT(Cs->cy))
1495 {
1496 TRACE("Strange use of CW_USEDEFAULT in nHeight\n");
1497 Cs->cy = (pMonitor->rcWork.bottom - pMonitor->rcWork.top) * 3 / 4;
1498 }
1499 }
1500 else
1501 {
1502 /* if CW_USEDEFAULT is set for non-overlapped windows, both values are set to zero */
1503 if(IS_DEFAULT(Cs->x))
1504 {
1505 Cs->x = 0;
1506 Cs->y = 0;
1507 }
1508 if(IS_DEFAULT(Cs->cx))
1509 {
1510 Cs->cx = 0;
1511 Cs->cy = 0;
1512 }
1513 }
1514
1515 #undef IS_DEFAULT
1516 }
1517
1518 /* Allocates and initializes a window */
1519 PWND FASTCALL IntCreateWindow(CREATESTRUCTW* Cs,
1520 PLARGE_STRING WindowName,
1521 PCLS Class,
1522 PWND ParentWindow,
1523 PWND OwnerWindow,
1524 PVOID acbiBuffer,
1525 PDESKTOP pdeskCreated)
1526 {
1527 PWND pWnd = NULL;
1528 HWND hWnd;
1529 PTHREADINFO pti = NULL;
1530 BOOL MenuChanged;
1531 BOOL bUnicodeWindow;
1532
1533 pti = pdeskCreated ? gptiDesktopThread : GetW32ThreadInfo();
1534
1535 if (!(Cs->dwExStyle & WS_EX_LAYOUTRTL))
1536 { // Need both here for wine win.c test_CreateWindow.
1537 //if (Cs->hwndParent && ParentWindow)
1538 if (ParentWindow) // It breaks more tests..... WIP.
1539 {
1540 if ( (Cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD &&
1541 ParentWindow->ExStyle & WS_EX_LAYOUTRTL &&
1542 !(ParentWindow->ExStyle & WS_EX_NOINHERITLAYOUT) )
1543 Cs->dwExStyle |= WS_EX_LAYOUTRTL;
1544 }
1545 else
1546 { /*
1547 * Note from MSDN <http://msdn.microsoft.com/en-us/library/aa913269.aspx>:
1548 *
1549 * Dialog boxes and message boxes do not inherit layout, so you must
1550 * set the layout explicitly.
1551 */
1552 if ( Class->fnid != FNID_DIALOG )
1553 {
1554 if (pti->ppi->dwLayout & LAYOUT_RTL)
1555 {
1556 Cs->dwExStyle |= WS_EX_LAYOUTRTL;
1557 }
1558 }
1559 }
1560 }
1561
1562 /* Automatically add WS_EX_WINDOWEDGE */
1563 if ((Cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
1564 ((!(Cs->dwExStyle & WS_EX_STATICEDGE)) &&
1565 (Cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
1566 Cs->dwExStyle |= WS_EX_WINDOWEDGE;
1567 else
1568 Cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
1569
1570 /* Is it a unicode window? */
1571 bUnicodeWindow =!(Cs->dwExStyle & WS_EX_SETANSICREATOR);
1572 Cs->dwExStyle &= ~WS_EX_SETANSICREATOR;
1573
1574 /* Allocate the new window */
1575 pWnd = (PWND) UserCreateObject( gHandleTable,
1576 pdeskCreated ? pdeskCreated : pti->rpdesk,
1577 pti,
1578 (PHANDLE)&hWnd,
1579 TYPE_WINDOW,
1580 sizeof(WND) + Class->cbwndExtra);
1581
1582 if (!pWnd)
1583 {
1584 goto AllocError;
1585 }
1586
1587 TRACE("Created window object with handle %p\n", hWnd);
1588
1589 if (pdeskCreated && pdeskCreated->DesktopWindow == NULL )
1590 { /* HACK: Helper for win32csr/desktopbg.c */
1591 /* If there is no desktop window yet, we must be creating it */
1592 TRACE("CreateWindow setting desktop.\n");
1593 pdeskCreated->DesktopWindow = hWnd;
1594 pdeskCreated->pDeskInfo->spwnd = pWnd;
1595 }
1596
1597 /*
1598 * Fill out the structure describing it.
1599 */
1600 /* Remember, pWnd->head is setup in object.c ... */
1601 pWnd->spwndParent = ParentWindow;
1602 pWnd->spwndOwner = OwnerWindow;
1603 pWnd->fnid = 0;
1604 pWnd->spwndLastActive = pWnd;
1605 pWnd->state2 |= WNDS2_WIN40COMPAT; // FIXME!!!
1606 pWnd->pcls = Class;
1607 pWnd->hModule = Cs->hInstance;
1608 pWnd->style = Cs->style & ~WS_VISIBLE;
1609 pWnd->ExStyle = Cs->dwExStyle;
1610 pWnd->cbwndExtra = pWnd->pcls->cbwndExtra;
1611 pWnd->pActCtx = acbiBuffer;
1612 pWnd->InternalPos.MaxPos.x = pWnd->InternalPos.MaxPos.y = -1;
1613 pWnd->InternalPos.IconPos.x = pWnd->InternalPos.IconPos.y = -1;
1614
1615 if (pWnd->spwndParent != NULL && Cs->hwndParent != 0)
1616 {
1617 pWnd->HideFocus = pWnd->spwndParent->HideFocus;
1618 pWnd->HideAccel = pWnd->spwndParent->HideAccel;
1619 }
1620
1621 pWnd->head.pti->cWindows++;
1622
1623 if (Class->spicn && !Class->spicnSm)
1624 {
1625 HICON IconSmHandle = NULL;
1626 if((Class->spicn->CURSORF_flags & (CURSORF_LRSHARED | CURSORF_FROMRESOURCE))
1627 == (CURSORF_LRSHARED | CURSORF_FROMRESOURCE))
1628 {
1629 IconSmHandle = co_IntCopyImage(
1630 UserHMGetHandle(Class->spicn),
1631 IMAGE_ICON,
1632 UserGetSystemMetrics( SM_CXSMICON ),
1633 UserGetSystemMetrics( SM_CYSMICON ),
1634 LR_COPYFROMRESOURCE);
1635 }
1636 if (!IconSmHandle)
1637 {
1638 /* Retry without copying from resource */
1639 IconSmHandle = co_IntCopyImage(
1640 UserHMGetHandle(Class->spicn),
1641 IMAGE_ICON,
1642 UserGetSystemMetrics( SM_CXSMICON ),
1643 UserGetSystemMetrics( SM_CYSMICON ),
1644 0);
1645 }
1646
1647 if (IconSmHandle)
1648 {
1649 Class->spicnSm = UserGetCurIconObject(IconSmHandle);
1650 Class->CSF_flags |= CSF_CACHEDSMICON;
1651 }
1652 }
1653
1654 if (pWnd->pcls->CSF_flags & CSF_SERVERSIDEPROC)
1655 pWnd->state |= WNDS_SERVERSIDEWINDOWPROC;
1656
1657 /* BugBoy Comments: Comment below say that System classes are always created
1658 as UNICODE. In windows, creating a window with the ANSI version of CreateWindow
1659 sets the window to ansi as verified by testing with IsUnicodeWindow API.
1660
1661 No where can I see in code or through testing does the window change back
1662 to ANSI after being created as UNICODE in ROS. I didnt do more testing to
1663 see what problems this would cause. */
1664
1665 // Set WndProc from Class.
1666 pWnd->lpfnWndProc = pWnd->pcls->lpfnWndProc;
1667
1668 // GetWindowProc, test for non server side default classes and set WndProc.
1669 if ( pWnd->pcls->fnid <= FNID_GHOST && pWnd->pcls->fnid >= FNID_BUTTON )
1670 {
1671 if (bUnicodeWindow)
1672 {
1673 if (GETPFNCLIENTA(pWnd->pcls->fnid) == pWnd->lpfnWndProc)
1674 pWnd->lpfnWndProc = GETPFNCLIENTW(pWnd->pcls->fnid);
1675 }
1676 else
1677 {
1678 if (GETPFNCLIENTW(pWnd->pcls->fnid) == pWnd->lpfnWndProc)
1679 pWnd->lpfnWndProc = GETPFNCLIENTA(pWnd->pcls->fnid);
1680 }
1681 }
1682
1683 // If not an Unicode caller, set Ansi creator bit.
1684 if (!bUnicodeWindow) pWnd->state |= WNDS_ANSICREATOR;
1685
1686 // Clone Class Ansi/Unicode proc type.
1687 if (pWnd->pcls->CSF_flags & CSF_ANSIPROC)
1688 {
1689 pWnd->state |= WNDS_ANSIWINDOWPROC;
1690 pWnd->Unicode = FALSE;
1691 }
1692 else
1693 { /*
1694 * It seems there can be both an Ansi creator and Unicode Class Window
1695 * WndProc, unless the following overriding conditions occur:
1696 */
1697 if ( !bUnicodeWindow &&
1698 ( Class->atomClassName == gpsi->atomSysClass[ICLS_BUTTON] ||
1699 Class->atomClassName == gpsi->atomSysClass[ICLS_COMBOBOX] ||
1700 Class->atomClassName == gpsi->atomSysClass[ICLS_COMBOLBOX] ||
1701 Class->atomClassName == gpsi->atomSysClass[ICLS_DIALOG] ||
1702 Class->atomClassName == gpsi->atomSysClass[ICLS_EDIT] ||
1703 Class->atomClassName == gpsi->atomSysClass[ICLS_IME] ||
1704 Class->atomClassName == gpsi->atomSysClass[ICLS_LISTBOX] ||
1705 Class->atomClassName == gpsi->atomSysClass[ICLS_MDICLIENT] ||
1706 Class->atomClassName == gpsi->atomSysClass[ICLS_STATIC] ) )
1707 { // Override Class and set the window Ansi WndProc.
1708 pWnd->state |= WNDS_ANSIWINDOWPROC;
1709 pWnd->Unicode = FALSE;
1710 }
1711 else
1712 { // Set the window Unicode WndProc.
1713 pWnd->state &= ~WNDS_ANSIWINDOWPROC;
1714 pWnd->Unicode = TRUE;
1715 }
1716 }
1717
1718 /* BugBoy Comments: if the window being created is a edit control, ATOM 0xCxxx,
1719 then my testing shows that windows (2k and XP) creates a CallProc for it immediately
1720 Dont understand why it does this. */
1721 if (Class->atomClassName == gpsi->atomSysClass[ICLS_EDIT])
1722 {
1723 PCALLPROCDATA CallProc;
1724 CallProc = CreateCallProc(pWnd->head.rpdesk, pWnd->lpfnWndProc, pWnd->Unicode , pWnd->head.pti->ppi);
1725
1726 if (!CallProc)
1727 {
1728 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
1729 ERR("Warning: Unable to create CallProc for edit control. Control may not operate correctly! hwnd %p\n", hWnd);
1730 }
1731 else
1732 {
1733 UserAddCallProcToClass(pWnd->pcls, CallProc);
1734 }
1735 }
1736
1737 InitializeListHead(&pWnd->PropListHead);
1738 pWnd->PropListItems = 0;
1739
1740 if ( WindowName->Buffer != NULL && WindowName->Length > 0 )
1741 {
1742 pWnd->strName.Buffer = DesktopHeapAlloc(pWnd->head.rpdesk,
1743 WindowName->Length + sizeof(UNICODE_NULL));
1744 if (pWnd->strName.Buffer == NULL)
1745 {
1746 goto AllocError;
1747 }
1748
1749 RtlCopyMemory(pWnd->strName.Buffer, WindowName->Buffer, WindowName->Length);
1750 pWnd->strName.Buffer[WindowName->Length / sizeof(WCHAR)] = L'\0';
1751 pWnd->strName.Length = WindowName->Length;
1752 pWnd->strName.MaximumLength = WindowName->Length + sizeof(UNICODE_NULL);
1753 }
1754
1755 /* Correct the window style. */
1756 if ((pWnd->style & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1757 {
1758 pWnd->style |= WS_CLIPSIBLINGS;
1759 if (!(pWnd->style & WS_POPUP))
1760 {
1761 pWnd->style |= WS_CAPTION;
1762 }
1763 }
1764
1765 /* WS_EX_WINDOWEDGE depends on some other styles */
1766 if (pWnd->ExStyle & WS_EX_DLGMODALFRAME)
1767 pWnd->ExStyle |= WS_EX_WINDOWEDGE;
1768 else if (pWnd->style & (WS_DLGFRAME | WS_THICKFRAME))
1769 {
1770 if (!((pWnd->ExStyle & WS_EX_STATICEDGE) &&
1771 (pWnd->style & (WS_CHILD | WS_POPUP))))
1772 pWnd->ExStyle |= WS_EX_WINDOWEDGE;
1773 }
1774 else
1775 pWnd->ExStyle &= ~WS_EX_WINDOWEDGE;
1776
1777 if (!(pWnd->style & (WS_CHILD | WS_POPUP)))
1778 pWnd->state |= WNDS_SENDSIZEMOVEMSGS;
1779
1780 /* Set the window menu */
1781 if ((Cs->style & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1782 {
1783 if (Cs->hMenu)
1784 {
1785 IntSetMenu(pWnd, Cs->hMenu, &MenuChanged);
1786 }
1787 else if (pWnd->pcls->lpszMenuName) // Take it from the parent.
1788 {
1789 UNICODE_STRING MenuName;
1790 HMENU hMenu;
1791
1792 if (IS_INTRESOURCE(pWnd->pcls->lpszMenuName))
1793 {
1794 MenuName.Length = 0;
1795 MenuName.MaximumLength = 0;
1796 MenuName.Buffer = pWnd->pcls->lpszMenuName;
1797 }
1798 else
1799 {
1800 RtlInitUnicodeString( &MenuName, pWnd->pcls->lpszMenuName);
1801 }
1802 hMenu = co_IntCallLoadMenu( pWnd->pcls->hModule, &MenuName);
1803 if (hMenu) IntSetMenu(pWnd, hMenu, &MenuChanged);
1804 }
1805 }
1806 else // Not a child
1807 pWnd->IDMenu = (UINT) Cs->hMenu;
1808
1809
1810 if ( ParentWindow &&
1811 ParentWindow != ParentWindow->head.rpdesk->spwndMessage &&
1812 ParentWindow != ParentWindow->head.rpdesk->pDeskInfo->spwnd )
1813 {
1814 PWND Owner = IntGetNonChildAncestor(ParentWindow);
1815
1816 if (!IntValidateOwnerDepth(pWnd, Owner))
1817 {
1818 EngSetLastError(ERROR_INVALID_PARAMETER);
1819 goto Error;
1820 }
1821 if ( pWnd->spwndOwner &&
1822 pWnd->spwndOwner->ExStyle & WS_EX_TOPMOST )
1823 {
1824 pWnd->ExStyle |= WS_EX_TOPMOST;
1825 }
1826 if ( pWnd->spwndOwner &&
1827 Class->atomClassName != gpsi->atomSysClass[ICLS_IME] &&
1828 pti != pWnd->spwndOwner->head.pti)
1829 {
1830 //ERR("CreateWindow Owner in.\n");
1831 UserAttachThreadInput(pti, pWnd->spwndOwner->head.pti, TRUE);
1832 }
1833 }
1834
1835 /* Insert the window into the thread's window list. */
1836 InsertTailList (&pti->WindowListHead, &pWnd->ThreadListEntry);
1837
1838 /* Handle "CS_CLASSDC", it is tested first. */
1839 if ( (pWnd->pcls->style & CS_CLASSDC) && !(pWnd->pcls->pdce) )
1840 { /* One DCE per class to have CLASS. */
1841 pWnd->pcls->pdce = DceAllocDCE( pWnd, DCE_CLASS_DC );
1842 }
1843 else if ( pWnd->pcls->style & CS_OWNDC)
1844 { /* Allocate a DCE for this window. */
1845 DceAllocDCE(pWnd, DCE_WINDOW_DC);
1846 }
1847
1848 return pWnd;
1849
1850 AllocError:
1851 ERR("IntCreateWindow Allocation Error.\n");
1852 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
1853 Error:
1854 if(pWnd)
1855 UserDereferenceObject(pWnd);
1856 return NULL;
1857 }
1858
1859 /*
1860 * @implemented
1861 */
1862 PWND FASTCALL
1863 co_UserCreateWindowEx(CREATESTRUCTW* Cs,
1864 PUNICODE_STRING ClassName,
1865 PLARGE_STRING WindowName,
1866 PVOID acbiBuffer)
1867 {
1868 ULONG style;
1869 PWND Window = NULL, ParentWindow = NULL, OwnerWindow;
1870 HWND hWnd, hWndParent, hWndOwner, hwndInsertAfter;
1871 PWINSTATION_OBJECT WinSta;
1872 PCLS Class = NULL;
1873 SIZE Size;
1874 POINT MaxSize, MaxPos, MinTrack, MaxTrack;
1875 CBT_CREATEWNDW * pCbtCreate;
1876 LRESULT Result;
1877 USER_REFERENCE_ENTRY ParentRef, Ref;
1878 PTHREADINFO pti;
1879 DWORD dwShowMode = SW_SHOW;
1880 CREATESTRUCTW *pCsw = NULL;
1881 PVOID pszClass = NULL, pszName = NULL;
1882 PWND ret = NULL;
1883
1884 /* Get the current window station and reference it */
1885 pti = GetW32ThreadInfo();
1886 if (pti == NULL || pti->rpdesk == NULL)
1887 {
1888 ERR("Thread is not attached to a desktop! Cannot create window!\n");
1889 return NULL; // There is nothing to cleanup.
1890 }
1891 WinSta = pti->rpdesk->rpwinstaParent;
1892 ObReferenceObjectByPointer(WinSta, KernelMode, ExWindowStationObjectType, 0);
1893
1894 pCsw = NULL;
1895 pCbtCreate = NULL;
1896
1897 /* Get the class and reference it */
1898 Class = IntGetAndReferenceClass(ClassName, Cs->hInstance, FALSE);
1899 if(!Class)
1900 {
1901 ERR("Failed to find class %wZ\n", ClassName);
1902 goto cleanup;
1903 }
1904
1905 /* Now find the parent and the owner window */
1906 hWndParent = pti->rpdesk->pDeskInfo->spwnd->head.h;
1907 hWndOwner = NULL;
1908
1909 if (Cs->hwndParent == HWND_MESSAGE)
1910 {
1911 Cs->hwndParent = hWndParent = pti->rpdesk->spwndMessage->head.h;
1912 }
1913 else if (Cs->hwndParent)
1914 {
1915 if ((Cs->style & (WS_CHILD|WS_POPUP)) != WS_CHILD)
1916 hWndOwner = Cs->hwndParent;
1917 else
1918 hWndParent = Cs->hwndParent;
1919 }
1920 else if ((Cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
1921 {
1922 ERR("Cannot create a child window without a parrent!\n");
1923 EngSetLastError(ERROR_TLW_WITH_WSCHILD);
1924 goto cleanup; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
1925 }
1926
1927 ParentWindow = hWndParent ? UserGetWindowObject(hWndParent): NULL;
1928 OwnerWindow = hWndOwner ? UserGetWindowObject(hWndOwner): NULL;
1929
1930 /* FIXME: Is this correct? */
1931 if(OwnerWindow)
1932 OwnerWindow = UserGetAncestor(OwnerWindow, GA_ROOT);
1933
1934 /* Fix the position and the size of the window */
1935 if (ParentWindow)
1936 {
1937 UserRefObjectCo(ParentWindow, &ParentRef);
1938 IntFixWindowCoordinates(Cs, ParentWindow, &dwShowMode);
1939 }
1940
1941 /* Allocate and initialize the new window */
1942 Window = IntCreateWindow(Cs,
1943 WindowName,
1944 Class,
1945 ParentWindow,
1946 OwnerWindow,
1947 acbiBuffer,
1948 NULL);
1949 if(!Window)
1950 {
1951 ERR("IntCreateWindow failed!\n");
1952 goto cleanup;
1953 }
1954
1955 hWnd = UserHMGetHandle(Window);
1956 hwndInsertAfter = HWND_TOP;
1957
1958 UserRefObjectCo(Window, &Ref);
1959 UserDereferenceObject(Window);
1960 ObDereferenceObject(WinSta);
1961
1962 //// Check for a hook to eliminate overhead. ////
1963 if ( ISITHOOKED(WH_CBT) || (pti->rpdesk->pDeskInfo->fsHooks & HOOKID_TO_FLAG(WH_CBT)) )
1964 {
1965 // Allocate the calling structures Justin Case this goes Global.
1966 pCsw = ExAllocatePoolWithTag(NonPagedPool, sizeof(CREATESTRUCTW), TAG_HOOK);
1967 pCbtCreate = ExAllocatePoolWithTag(NonPagedPool, sizeof(CBT_CREATEWNDW), TAG_HOOK);
1968 if (!pCsw || !pCbtCreate)
1969 {
1970 ERR("UserHeapAlloc() failed!\n");
1971 goto cleanup;
1972 }
1973
1974 /* Fill the new CREATESTRUCTW */
1975 RtlCopyMemory(pCsw, Cs, sizeof(CREATESTRUCTW));
1976 pCsw->style = Window->style; /* HCBT_CREATEWND needs the real window style */
1977
1978 // Based on the assumption this is from "unicode source" user32, ReactOS, answer is yes.
1979 if (!IS_ATOM(ClassName->Buffer))
1980 {
1981 if (Window->state & WNDS_ANSICREATOR)
1982 {
1983 ANSI_STRING AnsiString;
1984 AnsiString.MaximumLength = (USHORT)RtlUnicodeStringToAnsiSize(ClassName)+sizeof(CHAR);
1985 pszClass = UserHeapAlloc(AnsiString.MaximumLength);
1986 if (!pszClass)
1987 {
1988 ERR("UserHeapAlloc() failed!\n");
1989 goto cleanup;
1990 }
1991 RtlZeroMemory(pszClass, AnsiString.MaximumLength);
1992 AnsiString.Buffer = (PCHAR)pszClass;
1993 RtlUnicodeStringToAnsiString(&AnsiString, ClassName, FALSE);
1994 }
1995 else
1996 {
1997 UNICODE_STRING UnicodeString;
1998 UnicodeString.MaximumLength = ClassName->Length + sizeof(UNICODE_NULL);
1999 pszClass = UserHeapAlloc(UnicodeString.MaximumLength);
2000 if (!pszClass)
2001 {
2002 ERR("UserHeapAlloc() failed!\n");
2003 goto cleanup;
2004 }
2005 RtlZeroMemory(pszClass, UnicodeString.MaximumLength);
2006 UnicodeString.Buffer = (PWSTR)pszClass;
2007 RtlCopyUnicodeString(&UnicodeString, ClassName);
2008 }
2009 pCsw->lpszClass = UserHeapAddressToUser(pszClass);
2010 }
2011 if (WindowName->Length)
2012 {
2013 UNICODE_STRING Name;
2014 Name.Buffer = WindowName->Buffer;
2015 Name.Length = (USHORT)min(WindowName->Length, MAXUSHORT); // FIXME: LARGE_STRING truncated
2016 Name.MaximumLength = (USHORT)min(WindowName->MaximumLength, MAXUSHORT);
2017
2018 if (Window->state & WNDS_ANSICREATOR)
2019 {
2020 ANSI_STRING AnsiString;
2021 AnsiString.MaximumLength = (USHORT)RtlUnicodeStringToAnsiSize(&Name) + sizeof(CHAR);
2022 pszName = UserHeapAlloc(AnsiString.MaximumLength);
2023 if (!pszName)
2024 {
2025 ERR("UserHeapAlloc() failed!\n");
2026 goto cleanup;
2027 }
2028 RtlZeroMemory(pszName, AnsiString.MaximumLength);
2029 AnsiString.Buffer = (PCHAR)pszName;
2030 RtlUnicodeStringToAnsiString(&AnsiString, &Name, FALSE);
2031 }
2032 else
2033 {
2034 UNICODE_STRING UnicodeString;
2035 UnicodeString.MaximumLength = Name.Length + sizeof(UNICODE_NULL);
2036 pszName = UserHeapAlloc(UnicodeString.MaximumLength);
2037 if (!pszName)
2038 {
2039 ERR("UserHeapAlloc() failed!\n");
2040 goto cleanup;
2041 }
2042 RtlZeroMemory(pszName, UnicodeString.MaximumLength);
2043 UnicodeString.Buffer = (PWSTR)pszName;
2044 RtlCopyUnicodeString(&UnicodeString, &Name);
2045 }
2046 pCsw->lpszName = UserHeapAddressToUser(pszName);
2047 }
2048
2049 pCbtCreate->lpcs = pCsw;
2050 pCbtCreate->hwndInsertAfter = hwndInsertAfter;
2051
2052 //// Call the WH_CBT hook ////
2053 Result = co_HOOK_CallHooks(WH_CBT, HCBT_CREATEWND, (WPARAM) hWnd, (LPARAM) pCbtCreate);
2054 if (Result != 0)
2055 {
2056 ERR("WH_CBT HCBT_CREATEWND hook failed! 0x%x\n", Result);
2057 goto cleanup;
2058 }
2059 // Write back changes.
2060 Cs->cx = pCsw->cx;
2061 Cs->cy = pCsw->cy;
2062 Cs->x = pCsw->x;
2063 Cs->y = pCsw->y;
2064 hwndInsertAfter = pCbtCreate->hwndInsertAfter;
2065 }
2066
2067 /* NCCREATE and WM_NCCALCSIZE need the original values */
2068 Cs->lpszName = (LPCWSTR) WindowName;
2069 Cs->lpszClass = (LPCWSTR) ClassName;
2070
2071 if ((Cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
2072 {
2073 if (ParentWindow != co_GetDesktopWindow(Window))
2074 {
2075 Cs->x += ParentWindow->rcClient.left;
2076 Cs->y += ParentWindow->rcClient.top;
2077 }
2078 }
2079
2080 /* Send the WM_GETMINMAXINFO message */
2081 Size.cx = Cs->cx;
2082 Size.cy = Cs->cy;
2083
2084 if ((Cs->style & WS_THICKFRAME) || !(Cs->style & (WS_POPUP | WS_CHILD)))
2085 {
2086 co_WinPosGetMinMaxInfo(Window, &MaxSize, &MaxPos, &MinTrack, &MaxTrack);
2087 if (Size.cx > MaxTrack.x) Size.cx = MaxTrack.x;
2088 if (Size.cy > MaxTrack.y) Size.cy = MaxTrack.y;
2089 if (Size.cx < MinTrack.x) Size.cx = MinTrack.x;
2090 if (Size.cy < MinTrack.y) Size.cy = MinTrack.y;
2091 }
2092
2093 Window->rcWindow.left = Cs->x;
2094 Window->rcWindow.top = Cs->y;
2095 Window->rcWindow.right = Cs->x + Size.cx;
2096 Window->rcWindow.bottom = Cs->y + Size.cy;
2097 /*
2098 if (0 != (Window->style & WS_CHILD) && ParentWindow)
2099 {
2100 ERR("co_UserCreateWindowEx(): Offset rcWindow\n");
2101 RECTL_vOffsetRect(&Window->rcWindow,
2102 ParentWindow->rcClient.left,
2103 ParentWindow->rcClient.top);
2104 }
2105 */
2106 /* correct child window coordinates if mirroring on parent is enabled */
2107 if (ParentWindow != NULL)
2108 {
2109 if ( ((Cs->style & WS_CHILD) == WS_CHILD) &&
2110 ((ParentWindow->ExStyle & WS_EX_LAYOUTRTL) == WS_EX_LAYOUTRTL))
2111 {
2112 Window->rcWindow.right = ParentWindow->rcClient.right - (Window->rcWindow.left - ParentWindow->rcClient.left);
2113 Window->rcWindow.left = Window->rcWindow.right - Size.cx;
2114 }
2115 }
2116
2117 Window->rcClient = Window->rcWindow;
2118
2119 /* Link the window */
2120 if (NULL != ParentWindow)
2121 {
2122 /* Link the window into the siblings list */
2123 if ((Cs->style & (WS_CHILD|WS_MAXIMIZE)) == WS_CHILD)
2124 IntLinkHwnd(Window, HWND_BOTTOM);
2125 else
2126 IntLinkHwnd(Window, hwndInsertAfter);
2127 }
2128
2129 if (!(Window->state2 & WNDS2_WIN31COMPAT))
2130 {
2131 if (Class->style & CS_PARENTDC && !(ParentWindow->style & WS_CLIPCHILDREN))
2132 Window->style &= ~(WS_CLIPSIBLINGS | WS_CLIPCHILDREN);
2133 }
2134
2135 if ((Window->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
2136 {
2137 if ( !IntIsTopLevelWindow(Window) )
2138 {
2139 if (pti != Window->spwndParent->head.pti)
2140 {
2141 //ERR("CreateWindow Parent in.\n");
2142 UserAttachThreadInput(pti, Window->spwndParent->head.pti, TRUE);
2143 }
2144 }
2145 }
2146
2147 /* Send the NCCREATE message */
2148 Result = co_IntSendMessage(UserHMGetHandle(Window), WM_NCCREATE, 0, (LPARAM) Cs);
2149 if (!Result)
2150 {
2151 ERR("co_UserCreateWindowEx(): NCCREATE message failed\n");
2152 goto cleanup;
2153 }
2154
2155 /* Send the WM_NCCALCSIZE message */
2156 {
2157 // RECT rc;
2158 MaxPos.x = Window->rcWindow.left;
2159 MaxPos.y = Window->rcWindow.top;
2160
2161 Result = co_WinPosGetNonClientSize(Window, &Window->rcWindow, &Window->rcClient);
2162 //rc = Window->rcWindow;
2163 //Result = co_IntSendMessageNoWait(Window->head.h, WM_NCCALCSIZE, FALSE, (LPARAM)&rc);
2164 //Window->rcClient = rc;
2165
2166 RECTL_vOffsetRect(&Window->rcWindow, MaxPos.x - Window->rcWindow.left,
2167 MaxPos.y - Window->rcWindow.top);
2168 }
2169
2170 /* Send the WM_CREATE message. */
2171 Result = co_IntSendMessage(UserHMGetHandle(Window), WM_CREATE, 0, (LPARAM) Cs);
2172 if (Result == (LRESULT)-1)
2173 {
2174 ERR("co_UserCreateWindowEx(): WM_CREATE message failed\n");
2175 goto cleanup;
2176 }
2177
2178 /* Send the EVENT_OBJECT_CREATE event */
2179 IntNotifyWinEvent(EVENT_OBJECT_CREATE, Window, OBJID_WINDOW, CHILDID_SELF, 0);
2180
2181 /* By setting the flag below it can be examined to determine if the window
2182 was created successfully and a valid pwnd was passed back to caller since
2183 from here the function has to succeed. */
2184 Window->state2 |= WNDS2_WMCREATEMSGPROCESSED;
2185
2186 /* Send the WM_SIZE and WM_MOVE messages. */
2187 if (!(Window->state & WNDS_SENDSIZEMOVEMSGS))
2188 {
2189 co_WinPosSendSizeMove(Window);
2190 }
2191
2192 /* Show or maybe minimize or maximize the window. */
2193
2194 style = IntSetStyle( Window, 0, WS_MAXIMIZE | WS_MINIMIZE );
2195 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
2196 {
2197 RECTL NewPos;
2198 UINT SwFlag = (style & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;
2199
2200 SwFlag = co_WinPosMinMaximize(Window, SwFlag, &NewPos);
2201 SwFlag |= SWP_NOZORDER|SWP_FRAMECHANGED; /* Frame always gets changed */
2202 if (!(style & WS_VISIBLE) || (style & WS_CHILD) || UserGetActiveWindow()) SwFlag |= SWP_NOACTIVATE;
2203 co_WinPosSetWindowPos(Window, 0, NewPos.left, NewPos.top,
2204 NewPos.right, NewPos.bottom, SwFlag);
2205 }
2206
2207 /* Send the WM_PARENTNOTIFY message */
2208 IntSendParentNotify(Window, WM_CREATE);
2209
2210 /* Notify the shell that a new window was created */
2211 if (Window->spwndParent == UserGetDesktopWindow() &&
2212 Window->spwndOwner == NULL &&
2213 (Window->style & WS_VISIBLE) &&
2214 (!(Window->ExStyle & WS_EX_TOOLWINDOW) ||
2215 (Window->ExStyle & WS_EX_APPWINDOW)))
2216 {
2217 co_IntShellHookNotify(HSHELL_WINDOWCREATED, (WPARAM)hWnd, 0);
2218 }
2219
2220 /* Initialize and show the window's scrollbars */
2221 if (Window->style & WS_VSCROLL)
2222 {
2223 co_UserShowScrollBar(Window, SB_VERT, FALSE, TRUE);
2224 }
2225 if (Window->style & WS_HSCROLL)
2226 {
2227 co_UserShowScrollBar(Window, SB_HORZ, TRUE, FALSE);
2228 }
2229
2230 /* Show the new window */
2231 if (Cs->style & WS_VISIBLE)
2232 {
2233 if (Window->style & WS_MAXIMIZE)
2234 dwShowMode = SW_SHOW;
2235 else if (Window->style & WS_MINIMIZE)
2236 dwShowMode = SW_SHOWMINIMIZED;
2237
2238 co_WinPosShowWindow(Window, dwShowMode);
2239
2240 if (Window->ExStyle & WS_EX_MDICHILD)
2241 {
2242 ASSERT(ParentWindow);
2243 if(!ParentWindow)
2244 goto cleanup;
2245 co_IntSendMessage(UserHMGetHandle(ParentWindow), WM_MDIREFRESHMENU, 0, 0);
2246 /* ShowWindow won't activate child windows */
2247 co_WinPosSetWindowPos(Window, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
2248 }
2249 }
2250
2251 if (Class->atomClassName == gaGuiConsoleWndClass)
2252 {
2253 /* Count only console windows manually */
2254 co_IntUserManualGuiCheck(TRUE);
2255 }
2256
2257 TRACE("co_UserCreateWindowEx(): Created window %p\n", hWnd);
2258 ret = Window;
2259
2260 cleanup:
2261 if (!ret)
2262 {
2263 TRACE("co_UserCreateWindowEx(): Error Created window!\n");
2264 /* If the window was created, the class will be dereferenced by co_UserDestroyWindow */
2265 if (Window)
2266 co_UserDestroyWindow(Window);
2267 else if (Class)
2268 IntDereferenceClass(Class, pti->pDeskInfo, pti->ppi);
2269 }
2270
2271 if (pCsw) ExFreePoolWithTag(pCsw, TAG_HOOK);
2272 if (pCbtCreate) ExFreePoolWithTag(pCbtCreate, TAG_HOOK);
2273 if (pszName) UserHeapFree(pszName);
2274 if (pszClass) UserHeapFree(pszClass);
2275
2276 if (Window)
2277 {
2278 UserDerefObjectCo(Window);
2279 }
2280 if (ParentWindow) UserDerefObjectCo(ParentWindow);
2281
2282 return ret;
2283 }
2284
2285 NTSTATUS
2286 NTAPI
2287 ProbeAndCaptureLargeString(
2288 OUT PLARGE_STRING plstrSafe,
2289 IN PLARGE_STRING plstrUnsafe)
2290 {
2291 LARGE_STRING lstrTemp;
2292 PVOID pvBuffer = NULL;
2293
2294 _SEH2_TRY
2295 {
2296 /* Probe and copy the string */
2297 ProbeForRead(plstrUnsafe, sizeof(LARGE_STRING), sizeof(ULONG));
2298 lstrTemp = *plstrUnsafe;
2299 }
2300 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2301 {
2302 /* Fail */
2303 _SEH2_YIELD(return _SEH2_GetExceptionCode();)
2304 }
2305 _SEH2_END
2306
2307 if (lstrTemp.Length != 0)
2308 {
2309 /* Allocate a buffer from paged pool */
2310 pvBuffer = ExAllocatePoolWithTag(PagedPool, lstrTemp.Length, TAG_STRING);
2311 if (!pvBuffer)
2312 {
2313 return STATUS_NO_MEMORY;
2314 }
2315
2316 _SEH2_TRY
2317 {
2318 /* Probe and copy the buffer */
2319 ProbeForRead(lstrTemp.Buffer, lstrTemp.Length, sizeof(WCHAR));
2320 RtlCopyMemory(pvBuffer, lstrTemp.Buffer, lstrTemp.Length);
2321 }
2322 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2323 {
2324 /* Cleanup and fail */
2325 ExFreePoolWithTag(pvBuffer, TAG_STRING);
2326 _SEH2_YIELD(return _SEH2_GetExceptionCode();)
2327 }
2328 _SEH2_END
2329 }
2330
2331 /* Set the output string */
2332 plstrSafe->Buffer = pvBuffer;
2333 plstrSafe->Length = lstrTemp.Length;
2334 plstrSafe->MaximumLength = lstrTemp.Length;
2335
2336 return STATUS_SUCCESS;
2337 }
2338
2339 /**
2340 * \todo Allow passing plstrClassName as ANSI.
2341 */
2342 HWND
2343 NTAPI
2344 NtUserCreateWindowEx(
2345 DWORD dwExStyle,
2346 PLARGE_STRING plstrClassName,
2347 PLARGE_STRING plstrClsVersion,
2348 PLARGE_STRING plstrWindowName,
2349 DWORD dwStyle,
2350 int x,
2351 int y,
2352 int nWidth,
2353 int nHeight,
2354 HWND hWndParent,
2355 HMENU hMenu,
2356 HINSTANCE hInstance,
2357 LPVOID lpParam,
2358 DWORD dwFlags,
2359 PVOID acbiBuffer)
2360 {
2361 NTSTATUS Status;
2362 LARGE_STRING lstrWindowName;
2363 LARGE_STRING lstrClassName;
2364 UNICODE_STRING ustrClassName;
2365 CREATESTRUCTW Cs;
2366 HWND hwnd = NULL;
2367 PWND pwnd;
2368
2369 lstrWindowName.Buffer = NULL;
2370 lstrClassName.Buffer = NULL;
2371
2372 ASSERT(plstrWindowName);
2373
2374 if ( (dwStyle & (WS_POPUP|WS_CHILD)) != WS_CHILD)
2375 {
2376 /* check hMenu is valid handle */
2377 if (hMenu && !UserGetMenuObject(hMenu))
2378 {
2379 ERR("NtUserCreateWindowEx: Got an invalid menu handle!\n");
2380 EngSetLastError(ERROR_INVALID_MENU_HANDLE);
2381 return NULL;
2382 }
2383 }
2384
2385 /* Copy the window name to kernel mode */
2386 Status = ProbeAndCaptureLargeString(&lstrWindowName, plstrWindowName);
2387 if (!NT_SUCCESS(Status))
2388 {
2389 ERR("NtUserCreateWindowEx: failed to capture plstrWindowName\n");
2390 SetLastNtError(Status);
2391 return NULL;
2392 }
2393
2394 plstrWindowName = &lstrWindowName;
2395
2396 /* Check if the class is an atom */
2397 if (IS_ATOM(plstrClassName))
2398 {
2399 /* It is, pass the atom in the UNICODE_STRING */
2400 ustrClassName.Buffer = (PVOID)plstrClassName;
2401 ustrClassName.Length = 0;
2402 ustrClassName.MaximumLength = 0;
2403 }
2404 else
2405 {
2406 /* It's not, capture the class name */
2407 Status = ProbeAndCaptureLargeString(&lstrClassName, plstrClassName);
2408 if (!NT_SUCCESS(Status))
2409 {
2410 ERR("NtUserCreateWindowEx: failed to capture plstrClassName\n");
2411 /* Set last error, cleanup and return */
2412 SetLastNtError(Status);
2413 goto cleanup;
2414 }
2415
2416 /* We pass it on as a UNICODE_STRING */
2417 ustrClassName.Buffer = lstrClassName.Buffer;
2418 ustrClassName.Length = (USHORT)min(lstrClassName.Length, MAXUSHORT); // FIXME: LARGE_STRING truncated
2419 ustrClassName.MaximumLength = (USHORT)min(lstrClassName.MaximumLength, MAXUSHORT);
2420 }
2421
2422 /* Fill the CREATESTRUCTW */
2423 /* we will keep here the original parameters */
2424 Cs.style = dwStyle;
2425 Cs.lpCreateParams = lpParam;
2426 Cs.hInstance = hInstance;
2427 Cs.hMenu = hMenu;
2428 Cs.hwndParent = hWndParent;
2429 Cs.cx = nWidth;
2430 Cs.cy = nHeight;
2431 Cs.x = x;
2432 Cs.y = y;
2433 Cs.lpszName = (LPCWSTR) plstrWindowName->Buffer;
2434 Cs.lpszClass = ustrClassName.Buffer;
2435 Cs.dwExStyle = dwExStyle;
2436
2437 UserEnterExclusive();
2438
2439 /* Call the internal function */
2440 pwnd = co_UserCreateWindowEx(&Cs, &ustrClassName, plstrWindowName, acbiBuffer);
2441
2442 if(!pwnd)
2443 {
2444 ERR("co_UserCreateWindowEx failed!\n");
2445 }
2446 hwnd = pwnd ? UserHMGetHandle(pwnd) : NULL;
2447
2448 UserLeave();
2449
2450 cleanup:
2451 if (lstrWindowName.Buffer)
2452 {
2453 ExFreePoolWithTag(lstrWindowName.Buffer, TAG_STRING);
2454 }
2455 if (lstrClassName.Buffer)
2456 {
2457 ExFreePoolWithTag(lstrClassName.Buffer, TAG_STRING);
2458 }
2459
2460 return hwnd;
2461 }
2462
2463
2464 BOOLEAN co_UserDestroyWindow(PVOID Object)
2465 {
2466 HWND hWnd;
2467 PWND pwndTemp;
2468 PTHREADINFO ti;
2469 MSG msg;
2470 PWND Window = Object;
2471
2472 ASSERT_REFS_CO(Window); // FIXME: Temp HACK?
2473
2474 hWnd = Window->head.h;
2475 ti = PsGetCurrentThreadWin32Thread();
2476
2477 TRACE("co_UserDestroyWindow \n");
2478
2479 /* Check for owner thread */
2480 if ( Window->head.pti != PsGetCurrentThreadWin32Thread())
2481 {
2482 /* Check if we are destroying the desktop window */
2483 if (! ((Window->head.rpdesk->dwDTFlags & DF_DESTROYED) && Window == Window->head.rpdesk->pDeskInfo->spwnd))
2484 {
2485 EngSetLastError(ERROR_ACCESS_DENIED);
2486 return FALSE;
2487 }
2488 }
2489
2490 /* If window was created successfully and it is hooked */
2491 if ((Window->state2 & WNDS2_WMCREATEMSGPROCESSED))
2492 {
2493 if (co_HOOK_CallHooks(WH_CBT, HCBT_DESTROYWND, (WPARAM) hWnd, 0))
2494 {
2495 ERR("Destroy Window WH_CBT Call Hook return!\n");
2496 return FALSE;
2497 }
2498 }
2499
2500 if (Window->pcls->atomClassName != gpsi->atomSysClass[ICLS_IME])
2501 {
2502 if ((Window->style & (WS_POPUP|WS_CHILD)) != WS_CHILD)
2503 {
2504 if (Window->spwndOwner)
2505 {
2506 //ERR("DestroyWindow Owner out.\n");
2507 UserAttachThreadInput(Window->head.pti, Window->spwndOwner->head.pti, FALSE);
2508 }
2509 }
2510 }
2511
2512 /* Inform the parent */
2513 if (Window->style & WS_CHILD)
2514 {
2515 IntSendParentNotify(Window, WM_DESTROY);
2516 }
2517
2518 if (!Window->spwndOwner && !IntGetParent(Window))
2519 {
2520 co_IntShellHookNotify(HSHELL_WINDOWDESTROYED, (WPARAM) hWnd, 0);
2521 }
2522
2523 /* Hide the window */
2524 if (Window->style & WS_VISIBLE)
2525 {
2526 if (Window->style & WS_CHILD)
2527 {
2528 /* Only child windows receive WM_SHOWWINDOW in DestroyWindow() */
2529 co_WinPosShowWindow(Window, SW_HIDE);
2530 }
2531 else
2532 {
2533 co_WinPosSetWindowPos(Window, 0, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_HIDEWINDOW );
2534 }
2535 }
2536
2537 // Adjust last active.
2538 if ((pwndTemp = Window->spwndOwner))
2539 {
2540 while (pwndTemp->spwndOwner)
2541 pwndTemp = pwndTemp->spwndOwner;
2542
2543 if (pwndTemp->spwndLastActive == Window)
2544 pwndTemp->spwndLastActive = Window->spwndOwner;
2545 }
2546
2547 if (Window->spwndParent && IntIsWindow(UserHMGetHandle(Window)))
2548 {
2549 if ((Window->style & (WS_POPUP | WS_CHILD)) == WS_CHILD)
2550 {
2551 if (!IntIsTopLevelWindow(Window))
2552 {
2553 //ERR("DestroyWindow Parent out.\n");
2554 UserAttachThreadInput(Window->head.pti, Window->spwndParent->head.pti, FALSE);
2555 }
2556 }
2557 }
2558
2559 if (Window->head.pti->MessageQueue->spwndActive == Window)
2560 Window->head.pti->MessageQueue->spwndActive = NULL;
2561 if (Window->head.pti->MessageQueue->spwndFocus == Window)
2562 Window->head.pti->MessageQueue->spwndFocus = NULL;
2563 if (Window->head.pti->MessageQueue->spwndActivePrev == Window)
2564 Window->head.pti->MessageQueue->spwndActivePrev = NULL;
2565 if (Window->head.pti->MessageQueue->spwndCapture == Window)
2566 Window->head.pti->MessageQueue->spwndCapture = NULL;
2567
2568 /*
2569 * Check if this window is the Shell's Desktop Window. If so set hShellWindow to NULL
2570 */
2571
2572 if ((ti != NULL) && (ti->pDeskInfo != NULL))
2573 {
2574 if (ti->pDeskInfo->hShellWindow == hWnd)
2575 {
2576 ERR("Destroying the ShellWindow!\n");
2577 ti->pDeskInfo->hShellWindow = NULL;
2578 }
2579 }
2580
2581 IntEngWindowChanged(Window, WOC_DELETE);
2582
2583 if (!IntIsWindow(UserHMGetHandle(Window)))
2584 {
2585 return TRUE;
2586 }
2587
2588 /* Recursively destroy owned windows */
2589
2590 if (! (Window->style & WS_CHILD))
2591 {
2592 for (;;)
2593 {
2594 BOOL GotOne = FALSE;
2595 HWND *Children;
2596 HWND *ChildHandle;
2597 PWND Child, Desktop;
2598
2599 Desktop = IntIsDesktopWindow(Window) ? Window :
2600 UserGetWindowObject(IntGetDesktopWindow());
2601 Children = IntWinListChildren(Desktop);
2602
2603 if (Children)
2604 {
2605 for (ChildHandle = Children; *ChildHandle; ++ChildHandle)
2606 {
2607 Child = UserGetWindowObject(*ChildHandle);
2608 if (Child == NULL)
2609 continue;
2610 if (Child->spwndOwner != Window)
2611 {
2612 continue;
2613 }
2614
2615 if (IntWndBelongsToThread(Child, PsGetCurrentThreadWin32Thread()))
2616 {
2617 USER_REFERENCE_ENTRY ChildRef;
2618 UserRefObjectCo(Child, &ChildRef); // Temp HACK?
2619 co_UserDestroyWindow(Child);
2620 UserDerefObjectCo(Child); // Temp HACK?
2621
2622 GotOne = TRUE;
2623 continue;
2624 }
2625
2626 if (Child->spwndOwner != NULL)
2627 {
2628 Child->spwndOwner = NULL;
2629 }
2630
2631 }
2632 ExFreePoolWithTag(Children, USERTAG_WINDOWLIST);
2633 }
2634 if (! GotOne)
2635 {
2636 break;
2637 }
2638 }
2639 }
2640
2641 /* Generate mouse move message for the next window */
2642 msg.message = WM_MOUSEMOVE;
2643 msg.wParam = UserGetMouseButtonsState();
2644 msg.lParam = MAKELPARAM(gpsi->ptCursor.x, gpsi->ptCursor.y);
2645 msg.pt = gpsi->ptCursor;
2646 co_MsqInsertMouseMessage(&msg, 0, 0, TRUE);
2647
2648 IntNotifyWinEvent(EVENT_OBJECT_DESTROY, Window, OBJID_WINDOW, CHILDID_SELF, 0);
2649
2650 /* Send destroy messages */
2651
2652 IntSendDestroyMsg(UserHMGetHandle(Window));
2653
2654 if (!IntIsWindow(UserHMGetHandle(Window)))
2655 {
2656 return TRUE;
2657 }
2658
2659 /* Destroy the window storage */
2660 co_UserFreeWindow(Window, PsGetCurrentProcessWin32Process(), PsGetCurrentThreadWin32Thread(), TRUE);
2661
2662 return TRUE;
2663 }
2664
2665
2666 /*
2667 * @implemented
2668 */
2669 BOOLEAN APIENTRY
2670 NtUserDestroyWindow(HWND Wnd)
2671 {
2672 PWND Window;
2673 DECLARE_RETURN(BOOLEAN);
2674 BOOLEAN ret;
2675 USER_REFERENCE_ENTRY Ref;
2676
2677 TRACE("Enter NtUserDestroyWindow\n");
2678 UserEnterExclusive();
2679
2680 if (!(Window = UserGetWindowObject(Wnd)))
2681 {
2682 RETURN(FALSE);
2683 }
2684
2685 UserRefObjectCo(Window, &Ref); // FIXME: Dunno if win should be reffed during destroy...
2686 ret = co_UserDestroyWindow(Window);
2687 UserDerefObjectCo(Window); // FIXME: Dunno if win should be reffed during destroy...
2688
2689 RETURN(ret);
2690
2691 CLEANUP:
2692 TRACE("Leave NtUserDestroyWindow, ret=%u\n", _ret_);
2693 UserLeave();
2694 END_CLEANUP;
2695 }
2696
2697
2698 static HWND FASTCALL
2699 IntFindWindow(PWND Parent,
2700 PWND ChildAfter,
2701 RTL_ATOM ClassAtom,
2702 PUNICODE_STRING WindowName)
2703 {
2704 BOOL CheckWindowName;
2705 HWND *List, *phWnd;
2706 HWND Ret = NULL;
2707 UNICODE_STRING CurrentWindowName;
2708
2709 ASSERT(Parent);
2710
2711 CheckWindowName = WindowName->Buffer != 0;
2712
2713 if((List = IntWinListChildren(Parent)))
2714 {
2715 phWnd = List;
2716 if(ChildAfter)
2717 {
2718 /* skip handles before and including ChildAfter */
2719 while(*phWnd && (*(phWnd++) != ChildAfter->head.h))
2720 ;
2721 }
2722
2723 /* search children */
2724 while(*phWnd)
2725 {
2726 PWND Child;
2727 if(!(Child = UserGetWindowObject(*(phWnd++))))
2728 {
2729 continue;
2730 }
2731
2732 /* Do not send WM_GETTEXT messages in the kernel mode version!
2733 The user mode version however calls GetWindowText() which will
2734 send WM_GETTEXT messages to windows belonging to its processes */
2735 if (!ClassAtom || Child->pcls->atomClassName == ClassAtom)
2736 {
2737 // FIXME: LARGE_STRING truncated
2738 CurrentWindowName.Buffer = Child->strName.Buffer;
2739 CurrentWindowName.Length = (USHORT)min(Child->strName.Length, MAXUSHORT);
2740 CurrentWindowName.MaximumLength = (USHORT)min(Child->strName.MaximumLength, MAXUSHORT);
2741 if(!CheckWindowName ||
2742 (Child->strName.Length < 0xFFFF &&
2743 !RtlCompareUnicodeString(WindowName, &CurrentWindowName, TRUE)))
2744 {
2745 Ret = Child->head.h;
2746 break;
2747 }
2748 }
2749 }
2750 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2751 }
2752
2753 return Ret;
2754 }
2755
2756 /*
2757 * FUNCTION:
2758 * Searches a window's children for a window with the specified
2759 * class and name
2760 * ARGUMENTS:
2761 * hwndParent = The window whose childs are to be searched.
2762 * NULL = desktop
2763 * HWND_MESSAGE = message-only windows
2764 *
2765 * hwndChildAfter = Search starts after this child window.
2766 * NULL = start from beginning
2767 *
2768 * ucClassName = Class name to search for
2769 * Reguired parameter.
2770 *
2771 * ucWindowName = Window name
2772 * ->Buffer == NULL = don't care
2773 *
2774 * RETURNS:
2775 * The HWND of the window if it was found, otherwise NULL
2776 */
2777 /*
2778 * @implemented
2779 */
2780 HWND APIENTRY
2781 NtUserFindWindowEx(HWND hwndParent,
2782 HWND hwndChildAfter,
2783 PUNICODE_STRING ucClassName,
2784 PUNICODE_STRING ucWindowName,
2785 DWORD dwUnknown)
2786 {
2787 PWND Parent, ChildAfter;
2788 UNICODE_STRING ClassName = {0}, WindowName = {0};
2789 HWND Desktop, Ret = NULL;
2790 BOOL DoMessageWnd = FALSE;
2791 RTL_ATOM ClassAtom = (RTL_ATOM)0;
2792 DECLARE_RETURN(HWND);
2793
2794 TRACE("Enter NtUserFindWindowEx\n");
2795 UserEnterShared();
2796
2797 if (ucClassName != NULL || ucWindowName != NULL)
2798 {
2799 _SEH2_TRY
2800 {
2801 if (ucClassName != NULL)
2802 {
2803 ClassName = ProbeForReadUnicodeString(ucClassName);
2804 if (ClassName.Length != 0)
2805 {
2806 ProbeForRead(ClassName.Buffer,
2807 ClassName.Length,
2808 sizeof(WCHAR));
2809 }
2810 else if (!IS_ATOM(ClassName.Buffer))
2811 {
2812 EngSetLastError(ERROR_INVALID_PARAMETER);
2813 _SEH2_LEAVE;
2814 }
2815
2816 if (!IntGetAtomFromStringOrAtom(&ClassName,
2817 &ClassAtom))
2818 {
2819 _SEH2_LEAVE;
2820 }
2821 }
2822
2823 if (ucWindowName != NULL)
2824 {
2825 WindowName = ProbeForReadUnicodeString(ucWindowName);
2826 if (WindowName.Length != 0)
2827 {
2828 ProbeForRead(WindowName.Buffer,
2829 WindowName.Length,
2830 sizeof(WCHAR));
2831 }
2832 }
2833 }
2834 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2835 {
2836 SetLastNtError(_SEH2_GetExceptionCode());
2837 _SEH2_YIELD(RETURN(NULL));
2838 }
2839 _SEH2_END;
2840
2841 if (ucClassName != NULL)
2842 {
2843 if (ClassName.Length == 0 && ClassName.Buffer != NULL &&
2844 !IS_ATOM(ClassName.Buffer))
2845 {
2846 EngSetLastError(ERROR_INVALID_PARAMETER);
2847 RETURN(NULL);
2848 }
2849 else if (ClassAtom == (RTL_ATOM)0)
2850 {
2851 /* LastError code was set by IntGetAtomFromStringOrAtom */
2852 RETURN(NULL);
2853 }
2854 }
2855 }
2856
2857 Desktop = IntGetCurrentThreadDesktopWindow();
2858
2859 if(hwndParent == NULL)
2860 {
2861 hwndParent = Desktop;
2862 DoMessageWnd = TRUE;
2863 }
2864 else if(hwndParent == HWND_MESSAGE)
2865 {
2866 hwndParent = IntGetMessageWindow();
2867 }
2868
2869 if(!(Parent = UserGetWindowObject(hwndParent)))
2870 {
2871 RETURN( NULL);
2872 }
2873
2874 ChildAfter = NULL;
2875 if(hwndChildAfter && !(ChildAfter = UserGetWindowObject(hwndChildAfter)))
2876 {
2877 RETURN( NULL);
2878 }
2879
2880 _SEH2_TRY
2881 {
2882 if(Parent->head.h == Desktop)
2883 {
2884 HWND *List, *phWnd;
2885 PWND TopLevelWindow;
2886 BOOLEAN CheckWindowName;
2887 BOOLEAN WindowMatches;
2888 BOOLEAN ClassMatches;
2889
2890 /* windows searches through all top-level windows if the parent is the desktop
2891 window */
2892
2893 if((List = IntWinListChildren(Parent)))
2894 {
2895 phWnd = List;
2896
2897 if(ChildAfter)
2898 {
2899 /* skip handles before and including ChildAfter */
2900 while(*phWnd && (*(phWnd++) != ChildAfter->head.h))
2901 ;
2902 }
2903
2904 CheckWindowName = WindowName.Buffer != 0;
2905
2906 /* search children */
2907 while(*phWnd)
2908 {
2909 UNICODE_STRING ustr;
2910
2911 if(!(TopLevelWindow = UserGetWindowObject(*(phWnd++))))
2912 {
2913 continue;
2914 }
2915
2916 /* Do not send WM_GETTEXT messages in the kernel mode version!
2917 The user mode version however calls GetWindowText() which will
2918 send WM_GETTEXT messages to windows belonging to its processes */
2919 ustr.Buffer = TopLevelWindow->strName.Buffer;
2920 ustr.Length = (USHORT)min(TopLevelWindow->strName.Length, MAXUSHORT); // FIXME:LARGE_STRING truncated
2921 ustr.MaximumLength = (USHORT)min(TopLevelWindow->strName.MaximumLength, MAXUSHORT);
2922 WindowMatches = !CheckWindowName ||
2923 (TopLevelWindow->strName.Length < 0xFFFF &&
2924 !RtlCompareUnicodeString(&WindowName, &ustr, TRUE));
2925 ClassMatches = (ClassAtom == (RTL_ATOM)0) ||
2926 ClassAtom == TopLevelWindow->pcls->atomClassName;
2927
2928 if (WindowMatches && ClassMatches)
2929 {
2930 Ret = TopLevelWindow->head.h;
2931 break;
2932 }
2933
2934 if (IntFindWindow(TopLevelWindow, NULL, ClassAtom, &WindowName))
2935 {
2936 /* window returns the handle of the top-level window, in case it found
2937 the child window */
2938 Ret = TopLevelWindow->head.h;
2939 break;
2940 }
2941
2942 }
2943 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2944 }
2945 }
2946 else
2947 {
2948 ERR("FindWindowEx: Not Desktop Parent!\n");
2949 Ret = IntFindWindow(Parent, ChildAfter, ClassAtom, &WindowName);
2950 }
2951
2952 if (Ret == NULL && DoMessageWnd)
2953 {
2954 PWND MsgWindows;
2955
2956 if((MsgWindows = UserGetWindowObject(IntGetMessageWindow())))
2957 {
2958 Ret = IntFindWindow(MsgWindows, ChildAfter, ClassAtom, &WindowName);
2959 }
2960 }
2961 }
2962 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2963 {
2964 SetLastNtError(_SEH2_GetExceptionCode());
2965 Ret = NULL;
2966 }
2967 _SEH2_END;
2968
2969 RETURN( Ret);
2970
2971 CLEANUP:
2972 TRACE("Leave NtUserFindWindowEx, ret %p\n", _ret_);
2973 UserLeave();
2974 END_CLEANUP;
2975 }
2976
2977
2978 /*
2979 * @implemented
2980 */
2981 PWND FASTCALL UserGetAncestor(PWND Wnd, UINT Type)
2982 {
2983 PWND WndAncestor, Parent;
2984
2985 if (Wnd->head.h == IntGetDesktopWindow())
2986 {
2987 return NULL;
2988 }
2989
2990 switch (Type)
2991 {
2992 case GA_PARENT:
2993 {
2994 WndAncestor = Wnd->spwndParent;
2995 break;
2996 }
2997
2998 case GA_ROOT:
2999 {
3000 WndAncestor = Wnd;
3001 Parent = NULL;
3002
3003 for(;;)
3004 {
3005 if(!(Parent = WndAncestor->spwndParent))
3006 {
3007 break;
3008 }
3009 if(IntIsDesktopWindow(Parent))
3010 {
3011 break;
3012 }
3013
3014 WndAncestor = Parent;
3015 }
3016 break;
3017 }
3018
3019 case GA_ROOTOWNER:
3020 {
3021 WndAncestor = Wnd;
3022
3023 for (;;)
3024 {
3025 Parent = IntGetParent(WndAncestor);
3026
3027 if (!Parent)
3028 {
3029 break;
3030 }
3031
3032 WndAncestor = Parent;
3033 }
3034 break;
3035 }
3036
3037 default:
3038 {
3039 return NULL;
3040 }
3041 }
3042
3043 return WndAncestor;
3044 }
3045
3046 /*
3047 * @implemented
3048 */
3049 HWND APIENTRY
3050 NtUserGetAncestor(HWND hWnd, UINT Type)
3051 {
3052 PWND Window, Ancestor;
3053 DECLARE_RETURN(HWND);
3054
3055 TRACE("Enter NtUserGetAncestor\n");
3056 UserEnterExclusive();
3057
3058 if (!(Window = UserGetWindowObject(hWnd)))
3059 {
3060 RETURN(NULL);
3061 }
3062
3063 Ancestor = UserGetAncestor(Window, Type);
3064 /* faxme: can UserGetAncestor ever return NULL for a valid window? */
3065
3066 RETURN(Ancestor ? Ancestor->head.h : NULL);
3067
3068 CLEANUP:
3069 TRACE("Leave NtUserGetAncestor, ret=%p\n", _ret_);
3070 UserLeave();
3071 END_CLEANUP;
3072 }
3073
3074 ////
3075 //// ReactOS work around! Keep it the sames as in Combo.c and Controls.h
3076 ////
3077 /* combo state struct */
3078 typedef struct
3079 {
3080 HWND self;
3081 HWND owner;
3082 UINT dwStyle;
3083 HWND hWndEdit;
3084 HWND hWndLBox;
3085 UINT wState;
3086 HFONT hFont;
3087 RECT textRect;
3088 RECT buttonRect;
3089 RECT droppedRect;
3090 INT droppedIndex;
3091 INT fixedOwnerDrawHeight;
3092 INT droppedWidth; /* last two are not used unless set */
3093 INT editHeight; /* explicitly */
3094 LONG UIState;
3095 } HEADCOMBO,*LPHEADCOMBO;
3096
3097 // Window Extra data container.
3098 typedef struct _WND2CBOX
3099 {
3100 WND;
3101 LPHEADCOMBO pCBox;
3102 } WND2CBOX, *PWND2CBOX;
3103
3104 #define CBF_BUTTONDOWN 0x0002
3105 ////
3106 ////
3107 ////
3108 BOOL
3109 APIENTRY
3110 NtUserGetComboBoxInfo(
3111 HWND hWnd,
3112 PCOMBOBOXINFO pcbi)
3113 {
3114 PWND Wnd;
3115 PPROCESSINFO ppi;
3116 BOOL NotSameppi = FALSE;
3117 BOOL Ret = TRUE;
3118 DECLARE_RETURN(BOOL);
3119
3120 TRACE("Enter NtUserGetComboBoxInfo\n");
3121 UserEnterShared();
3122
3123 if (!(Wnd = UserGetWindowObject(hWnd)))
3124 {
3125 RETURN( FALSE );
3126 }
3127 _SEH2_TRY
3128 {
3129 ProbeForWrite(pcbi, sizeof(COMBOBOXINFO), 1);
3130 }
3131 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3132 {
3133 SetLastNtError(_SEH2_GetExceptionCode());
3134 _SEH2_YIELD(RETURN(FALSE));
3135 }
3136 _SEH2_END;
3137
3138 if (pcbi->cbSize < sizeof(COMBOBOXINFO))
3139 {
3140 EngSetLastError(ERROR_INVALID_PARAMETER);
3141 RETURN(FALSE);
3142 }
3143
3144 // Pass the user pointer, it was already probed.
3145 if ((Wnd->pcls->atomClassName != gpsi->atomSysClass[ICLS_COMBOBOX]) && Wnd->fnid != FNID_COMBOBOX)
3146 {
3147 RETURN( (BOOL) co_IntSendMessage( Wnd->head.h, CB_GETCOMBOBOXINFO, 0, (LPARAM)pcbi));
3148 }
3149
3150 ppi = PsGetCurrentProcessWin32Process();
3151 NotSameppi = ppi != Wnd->head.pti->ppi;
3152 if (NotSameppi)
3153 {
3154 KeAttachProcess(&Wnd->head.pti->ppi->peProcess->Pcb);
3155 }
3156
3157 _SEH2_TRY
3158 {
3159 LPHEADCOMBO lphc = ((PWND2CBOX)Wnd)->pCBox;
3160 pcbi->rcItem = lphc->textRect;
3161 pcbi->rcButton = lphc->buttonRect;
3162 pcbi->stateButton = 0;
3163 if (lphc->wState & CBF_BUTTONDOWN)
3164 pcbi->stateButton |= STATE_SYSTEM_PRESSED;
3165 if (RECTL_bIsEmptyRect(&lphc->buttonRect))
3166 pcbi->stateButton |= STATE_SYSTEM_INVISIBLE;
3167 pcbi->hwndCombo = lphc->self;
3168 pcbi->hwndItem = lphc->hWndEdit;
3169 pcbi->hwndList = lphc->hWndLBox;
3170 }
3171 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3172 {
3173 Ret = FALSE;
3174 SetLastNtError(_SEH2_GetExceptionCode());
3175 }
3176 _SEH2_END;
3177
3178 RETURN( Ret);
3179
3180 CLEANUP:
3181 if (NotSameppi) KeDetachProcess();
3182 TRACE("Leave NtUserGetComboBoxInfo, ret=%i\n",_ret_);
3183 UserLeave();
3184 END_CLEANUP;
3185 }
3186
3187 ////
3188 //// ReactOS work around! Keep it the sames as in Listbox.c
3189 ////
3190 /* Listbox structure */
3191 typedef struct
3192 {
3193 HWND self; /* Our own window handle */
3194 HWND owner; /* Owner window to send notifications to */
3195 UINT style; /* Window style */
3196 INT width; /* Window width */
3197 INT height; /* Window height */
3198 VOID *items; /* Array of items */
3199 INT nb_items; /* Number of items */
3200 INT top_item; /* Top visible item */
3201 INT selected_item; /* Selected item */
3202 INT focus_item; /* Item that has the focus */
3203 INT anchor_item; /* Anchor item for extended selection */
3204 INT item_height; /* Default item height */
3205 INT page_size; /* Items per listbox page */
3206 INT column_width; /* Column width for multi-column listboxes */
3207 } LB_DESCR;
3208
3209 // Window Extra data container.
3210 typedef struct _WND2LB
3211 {
3212 WND;
3213 LB_DESCR * pLBiv;
3214 } WND2LB, *PWND2LB;
3215 ////
3216 ////
3217 ////
3218 DWORD
3219 APIENTRY
3220 NtUserGetListBoxInfo(
3221 HWND hWnd)
3222 {
3223 PWND Wnd;
3224 PPROCESSINFO ppi;
3225 BOOL NotSameppi = FALSE;
3226 DWORD Ret = 0;
3227 DECLARE_RETURN(DWORD);
3228
3229 TRACE("Enter NtUserGetListBoxInfo\n");
3230 UserEnterShared();
3231
3232 if (!(Wnd = UserGetWindowObject(hWnd)))
3233 {
3234 RETURN( 0 );
3235 }
3236
3237 if ((Wnd->pcls->atomClassName != gpsi->atomSysClass[ICLS_LISTBOX]) && Wnd->fnid != FNID_LISTBOX)
3238 {
3239 RETURN( (DWORD) co_IntSendMessage( Wnd->head.h, LB_GETLISTBOXINFO, 0, 0 ));
3240 }
3241
3242 // wine lisbox:test_GetListBoxInfo lb_getlistboxinfo = 0, should not send a message!
3243 ppi = PsGetCurrentProcessWin32Process();
3244 NotSameppi = ppi != Wnd->head.pti->ppi;
3245 if (NotSameppi)
3246 {
3247 KeAttachProcess(&Wnd->head.pti->ppi->peProcess->Pcb);
3248 }
3249
3250 _SEH2_TRY
3251 {
3252 LB_DESCR *descr = ((PWND2LB)Wnd)->pLBiv;
3253 // See Controls ListBox.c:LB_GETLISTBOXINFO must match...
3254 if (descr->style & LBS_MULTICOLUMN) //// ReactOS
3255 Ret = descr->page_size * descr->column_width;
3256 else
3257 Ret = descr->page_size;
3258 }
3259 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3260 {
3261 Ret = 0;
3262 SetLastNtError(_SEH2_GetExceptionCode());
3263 }
3264 _SEH2_END;
3265
3266 RETURN( Ret);
3267
3268 CLEANUP:
3269 if (NotSameppi) KeDetachProcess();
3270 TRACE("Leave NtUserGetListBoxInfo, ret=%lu\n", _ret_);
3271 UserLeave();
3272 END_CLEANUP;
3273 }
3274
3275 /*
3276 * NtUserSetParent
3277 *
3278 * The NtUserSetParent function changes the parent window of the specified
3279 * child window.
3280 *
3281 * Remarks
3282 * The new parent window and the child window must belong to the same
3283 * application. If the window identified by the hWndChild parameter is
3284 * visible, the system performs the appropriate redrawing and repainting.
3285 * For compatibility reasons, NtUserSetParent does not modify the WS_CHILD
3286 * or WS_POPUP window styles of the window whose parent is being changed.
3287 *
3288 * Status
3289 * @implemented
3290 */
3291
3292 HWND APIENTRY
3293 NtUserSetParent(HWND hWndChild, HWND hWndNewParent)
3294 {
3295 DECLARE_RETURN(HWND);
3296
3297 TRACE("Enter NtUserSetParent\n");
3298 UserEnterExclusive();
3299
3300 /*
3301 Check Parent first from user space, set it here.
3302 */
3303 if (!hWndNewParent)
3304 {
3305 hWndNewParent = IntGetDesktopWindow();
3306 }
3307 else if (hWndNewParent == HWND_MESSAGE)
3308 {
3309 hWndNewParent = IntGetMessageWindow();
3310 }
3311
3312 RETURN( co_UserSetParent(hWndChild, hWndNewParent));
3313
3314 CLEANUP:
3315 TRACE("Leave NtUserSetParent, ret=%p\n", _ret_);
3316 UserLeave();
3317 END_CLEANUP;
3318 }
3319
3320 /*
3321 * UserGetShellWindow
3322 *
3323 * Returns a handle to shell window that was set by NtUserSetShellWindowEx.
3324 *
3325 * Status
3326 * @implemented
3327 */
3328 HWND FASTCALL UserGetShellWindow(VOID)
3329 {
3330 PWINSTATION_OBJECT WinStaObject;
3331 HWND Ret;
3332
3333 NTSTATUS Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
3334 KernelMode,
3335 0,
3336 &WinStaObject,
3337 0);
3338
3339 if (!NT_SUCCESS(Status))
3340 {
3341 SetLastNtError(Status);
3342 return( (HWND)0);
3343 }
3344
3345 Ret = (HWND)WinStaObject->ShellWindow;
3346
3347 ObDereferenceObject(WinStaObject);
3348 return( Ret);
3349 }
3350
3351 /*
3352 * NtUserSetShellWindowEx
3353 *
3354 * This is undocumented function to set global shell window. The global
3355 * shell window has special handling of window position.
3356 *
3357 * Status
3358 * @implemented
3359 */
3360 BOOL APIENTRY
3361 NtUserSetShellWindowEx(HWND hwndShell, HWND hwndListView)
3362 {
3363 PWINSTATION_OBJECT WinStaObject;
3364 PWND WndShell, WndListView;
3365 DECLARE_RETURN(BOOL);
3366 USER_REFERENCE_ENTRY Ref;
3367 NTSTATUS Status;
3368 PTHREADINFO ti;
3369
3370 TRACE("Enter NtUserSetShellWindowEx\n");
3371 UserEnterExclusive();
3372
3373 if (!(WndShell = UserGetWindowObject(hwndShell)))
3374 {
3375 RETURN(FALSE);
3376 }
3377
3378 if(!(WndListView = UserGetWindowObject(hwndListView)))
3379 {
3380 RETURN(FALSE);
3381 }
3382
3383 Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
3384 KernelMode,
3385 0,
3386 &WinStaObject,
3387 0);
3388
3389 if (!NT_SUCCESS(Status))
3390 {
3391 SetLastNtError(Status);
3392 RETURN( FALSE);
3393 }
3394
3395 /*
3396 * Test if we are permitted to change the shell window.
3397 */
3398 if (WinStaObject->ShellWindow)
3399 {
3400 ObDereferenceObject(WinStaObject);
3401 RETURN( FALSE);
3402 }
3403
3404 /*
3405 * Move shell window into background.
3406 */
3407 if (hwndListView && hwndListView != hwndShell)
3408 {
3409 /*
3410 * Disabled for now to get Explorer working.
3411 * -- Filip, 01/nov/2003
3412 */
3413 #if 0
3414 co_WinPosSetWindowPos(WndListView, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
3415 #endif
3416
3417 if (WndListView->ExStyle & WS_EX_TOPMOST)
3418 {
3419 ObDereferenceObject(WinStaObject);
3420 RETURN( FALSE);
3421 }
3422 }
3423
3424 if (WndShell->ExStyle & WS_EX_TOPMOST)
3425 {
3426 ObDereferenceObject(WinStaObject);
3427 RETURN( FALSE);
3428 }
3429
3430 UserRefObjectCo(WndShell, &Ref);
3431 WndShell->state2 |= WNDS2_BOTTOMMOST;
3432 co_WinPosSetWindowPos(WndShell, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
3433
3434 WinStaObject->ShellWindow = hwndShell;
3435 WinStaObject->ShellListView = hwndListView;
3436
3437 ti = GetW32ThreadInfo();
3438 if (ti->pDeskInfo)
3439 {
3440 ti->pDeskInfo->hShellWindow = hwndShell;
3441 ti->pDeskInfo->spwndShell = WndShell;
3442 ti->pDeskInfo->ppiShellProcess = ti->ppi;
3443 }
3444
3445 UserRegisterHotKey(WndShell, SC_TASKLIST, MOD_CONTROL, VK_ESCAPE);
3446
3447 UserDerefObjectCo(WndShell);
3448
3449 ObDereferenceObject(WinStaObject);
3450 RETURN( TRUE);
3451
3452 CLEANUP:
3453 TRACE("Leave NtUserSetShellWindowEx, ret=%i\n",_ret_);
3454 UserLeave();
3455 END_CLEANUP;
3456 }
3457
3458 // Fixes wine Win test_window_styles and todo tests...
3459 static BOOL FASTCALL
3460 IntCheckFrameEdge(ULONG Style, ULONG ExStyle)
3461 {
3462 if (ExStyle & WS_EX_DLGMODALFRAME)
3463 return TRUE;
3464 else if (!(ExStyle & WS_EX_STATICEDGE) && (Style & (WS_DLGFRAME | WS_THICKFRAME)))
3465 return TRUE;
3466 else
3467 return FALSE;
3468 }
3469
3470 static LONG
3471 co_IntSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi, BOOL bAlter)
3472 {
3473 PWND Window, Parent;
3474 PWINSTATION_OBJECT WindowStation;
3475 LONG OldValue;
3476 STYLESTRUCT Style;
3477
3478 if (!(Window = UserGetWindowObject(hWnd)))
3479 {
3480 return( 0);
3481 }
3482
3483 if ((INT)Index >= 0)
3484 {
3485 if ((Index + sizeof(LONG)) > Window->cbwndExtra)
3486 {
3487 EngSetLastError(ERROR_INVALID_INDEX);
3488 return( 0);
3489 }
3490
3491 OldValue = *((LONG *)((PCHAR)(Window + 1) + Index));
3492 /*
3493 if ( Index == DWLP_DLGPROC && Wnd->state & WNDS_DIALOGWINDOW)
3494 {
3495 OldValue = (LONG)IntSetWindowProc( Wnd,
3496 (WNDPROC)NewValue,
3497 Ansi);
3498 if (!OldValue) return 0;
3499 }
3500 */
3501 *((LONG *)((PCHAR)(Window + 1) + Index)) = NewValue;
3502 }
3503 else
3504 {
3505 switch (Index)
3506 {
3507 case GWL_EXSTYLE:
3508 OldValue = (LONG) Window->ExStyle;
3509 Style.styleOld = OldValue;
3510 Style.styleNew = NewValue;
3511
3512 co_IntSendMessage(hWnd, WM_STYLECHANGING, GWL_EXSTYLE, (LPARAM) &Style);
3513
3514 /*
3515 * Remove extended window style bit WS_EX_TOPMOST for shell windows.
3516 */
3517 WindowStation = Window->head.pti->rpdesk->rpwinstaParent;
3518 if(WindowStation)
3519 {
3520 if (hWnd == WindowStation->ShellWindow || hWnd == WindowStation->ShellListView)
3521 Style.styleNew &= ~WS_EX_TOPMOST;
3522 }
3523 /* WS_EX_WINDOWEDGE depends on some other styles */
3524 if (IntCheckFrameEdge(Window->style, NewValue))
3525 Style.styleNew |= WS_EX_WINDOWEDGE;
3526 else
3527 Style.styleNew &= ~WS_EX_WINDOWEDGE;
3528
3529 Window->ExStyle = (DWORD)Style.styleNew;
3530
3531 co_IntSendMessage(hWnd, WM_STYLECHANGED, GWL_EXSTYLE, (LPARAM) &Style);
3532 break;
3533
3534 case GWL_STYLE:
3535 OldValue = (LONG) Window->style;
3536 Style.styleOld = OldValue;
3537 Style.styleNew = NewValue;
3538
3539 if (!bAlter)
3540 co_IntSendMessage(hWnd, WM_STYLECHANGING, GWL_STYLE, (LPARAM) &Style);
3541
3542 /* WS_CLIPSIBLINGS can't be reset on top-level windows */
3543 if (Window->spwndParent == UserGetDesktopWindow()) Style.styleNew |= WS_CLIPSIBLINGS;
3544 /* Fixes wine FIXME: changing WS_DLGFRAME | WS_THICKFRAME is supposed to change WS_EX_WINDOWEDGE too */
3545 if (IntCheckFrameEdge(NewValue, Window->ExStyle))
3546 Window->ExStyle |= WS_EX_WINDOWEDGE;
3547 else
3548 Window->ExStyle &= ~WS_EX_WINDOWEDGE;
3549
3550 if ((Style.styleOld ^ Style.styleNew) & WS_VISIBLE)
3551 {
3552 if (Style.styleOld & WS_VISIBLE) Window->head.pti->cVisWindows--;
3553 if (Style.styleNew & WS_VISIBLE) Window->head.pti->cVisWindows++;
3554 DceResetActiveDCEs( Window );
3555 }
3556 Window->style = (DWORD)Style.styleNew;
3557
3558 if (!bAlter)
3559 co_IntSendMessage(hWnd, WM_STYLECHANGED, GWL_STYLE, (LPARAM) &Style);
3560 break;
3561
3562 case GWL_WNDPROC:
3563 {
3564 if ( Window->head.pti->ppi != PsGetCurrentProcessWin32Process() ||
3565 Window->fnid & FNID_FREED)
3566 {
3567 EngSetLastError(ERROR_ACCESS_DENIED);
3568 return( 0);
3569 }
3570 OldValue = (LONG)IntSetWindowProc(Window,
3571 (WNDPROC)NewValue,
3572 Ansi);
3573 break;
3574 }
3575
3576 case GWL_HINSTANCE:
3577 OldValue = (LONG) Window->hModule;
3578 Window->hModule = (HINSTANCE) NewValue;
3579 break;
3580
3581 case GWL_HWNDPARENT:
3582 Parent = Window->spwndParent;
3583 if (Parent && (Parent->head.h == IntGetDesktopWindow()))
3584 OldValue = (LONG) IntSetOwner(Window->head.h, (HWND) NewValue);
3585 else
3586 OldValue = (LONG) co_UserSetParent(Window->head.h, (HWND) NewValue);
3587 break;
3588
3589 case GWL_ID:
3590 OldValue = (LONG) Window->IDMenu;
3591 Window->IDMenu = (UINT) NewValue;
3592 break;
3593
3594 case GWL_USERDATA:
3595 OldValue = Window->dwUserData;
3596 Window->dwUserData = NewValue;
3597 break;
3598
3599 default:
3600 ERR("NtUserSetWindowLong(): Unsupported index %lu\n", Index);
3601 EngSetLastError(ERROR_INVALID_INDEX);
3602 OldValue = 0;
3603 break;
3604 }
3605 }
3606
3607 return( OldValue);
3608 }
3609
3610
3611 LONG FASTCALL
3612 co_UserSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi)
3613 {
3614 return co_IntSetWindowLong(hWnd, Index, NewValue, Ansi, FALSE);
3615 }
3616
3617 /*
3618 * NtUserSetWindowLong
3619 *
3620 * The NtUserSetWindowLong function changes an attribute of the specified
3621 * window. The function also sets the 32-bit (long) value at the specified
3622 * offset into the extra window memory.
3623 *
3624 * Status
3625 * @implemented
3626 */
3627
3628 LONG APIENTRY
3629 NtUserSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi)
3630 {
3631 LONG ret;
3632
3633 UserEnterExclusive();
3634
3635 if (hWnd == IntGetDesktopWindow())
3636 {
3637 EngSetLastError(STATUS_ACCESS_DENIED);
3638 UserLeave();
3639 return 0;
3640 }
3641
3642 ret = co_IntSetWindowLong(hWnd, Index, NewValue, Ansi, FALSE);
3643
3644 UserLeave();
3645
3646 return ret;
3647 }
3648
3649 DWORD APIENTRY
3650 NtUserAlterWindowStyle(HWND hWnd, DWORD Index, LONG NewValue)
3651 {
3652 LONG ret;
3653
3654 UserEnterExclusive();
3655
3656 if (hWnd == IntGetDesktopWindow())
3657 {
3658 EngSetLastError(STATUS_ACCESS_DENIED);
3659 UserLeave();
3660 return 0;
3661 }
3662
3663 ret = co_IntSetWindowLong(hWnd, Index, NewValue, FALSE, TRUE);
3664
3665 UserLeave();
3666
3667 return ret;
3668 }
3669
3670
3671 /*
3672 * NtUserSetWindowWord
3673 *
3674 * Legacy function similar to NtUserSetWindowLong.
3675 *
3676 * Status
3677 * @implemented
3678 */
3679
3680 WORD APIENTRY
3681 NtUserSetWindowWord(HWND hWnd, INT Index, WORD NewValue)
3682 {
3683 PWND Window;
3684 WORD OldValue;
3685 DECLARE_RETURN(WORD);
3686
3687 TRACE("Enter NtUserSetWindowWord\n");
3688 UserEnterExclusive();
3689
3690 if (hWnd == IntGetDesktopWindow())
3691 {
3692 EngSetLastError(STATUS_ACCESS_DENIED);
3693 RETURN( 0);
3694 }
3695
3696 if (!(Window = UserGetWindowObject(hWnd)))
3697 {
3698 RETURN( 0);
3699 }
3700
3701 switch (Index)
3702 {
3703 case GWL_ID:
3704 case GWL_HINSTANCE:
3705 case GWL_HWNDPARENT:
3706 RETURN( (WORD)co_UserSetWindowLong(UserHMGetHandle(Window), Index, (UINT)NewValue, TRUE));
3707 default:
3708 if (Index < 0)
3709 {
3710 EngSetLastError(ERROR_INVALID_INDEX);
3711 RETURN( 0);
3712 }
3713 }
3714
3715 if ((ULONG)Index > (Window->cbwndExtra - sizeof(WORD)))
3716 {
3717 EngSetLastError(ERROR_INVALID_PARAMETER);
3718 RETURN( 0);
3719 }
3720
3721 OldValue = *((WORD *)((PCHAR)(Window + 1) + Index));
3722 *((WORD *)((PCHAR)(Window + 1) + Index)) = NewValue;
3723
3724 RETURN( OldValue);
3725
3726 CLEANUP:
3727 TRACE("Leave NtUserSetWindowWord, ret=%u\n", _ret_);
3728 UserLeave();
3729 END_CLEANUP;
3730 }
3731
3732 /*
3733 QueryWindow based on KJK::Hyperion and James Tabor.
3734
3735 0 = QWUniqueProcessId
3736 1 = QWUniqueThreadId
3737 2 = QWActiveWindow
3738 3 = QWFocusWindow
3739 4 = QWIsHung Implements IsHungAppWindow found
3740 by KJK::Hyperion.
3741
3742 9 = QWKillWindow When I called this with hWnd ==
3743 DesktopWindow, it shutdown the system
3744 and rebooted.
3745 */
3746 /*
3747 * @implemented
3748 */
3749 DWORD APIENTRY
3750 NtUserQueryWindow(HWND hWnd, DWORD Index)
3751 {
3752 /* Console Leader Process CID Window offsets */
3753 #define GWLP_CONSOLE_LEADER_PID 0
3754 #define GWLP_CONSOLE_LEADER_TID 4
3755
3756 PWND pWnd;
3757 DWORD Result;
3758 DECLARE_RETURN(UINT);
3759
3760 TRACE("Enter NtUserQueryWindow\n");
3761 UserEnterShared();
3762
3763 if (!(pWnd = UserGetWindowObject(hWnd)))
3764 {
3765 RETURN( 0);
3766 }
3767
3768 switch(Index)
3769 {
3770 case QUERY_WINDOW_UNIQUE_PROCESS_ID:
3771 {
3772 if ( (pWnd->head.pti->TIF_flags & TIF_CSRSSTHREAD) &&
3773 (pWnd->pcls->atomClassName == gaGuiConsoleWndClass) )
3774 {
3775 // IntGetWindowLong(offset == GWLP_CONSOLE_LEADER_PID)
3776 Result = (DWORD)(*((LONG_PTR*)((PCHAR)(pWnd + 1) + GWLP_CONSOLE_LEADER_PID)));
3777 }
3778 else
3779 {
3780 Result = (DWORD)IntGetWndProcessId(pWnd);
3781 }
3782 break;
3783 }
3784
3785 case QUERY_WINDOW_UNIQUE_THREAD_ID:
3786 {
3787 if ( (pWnd->head.pti->TIF_flags & TIF_CSRSSTHREAD) &&
3788 (pWnd->pcls->atomClassName == gaGuiConsoleWndClass) )
3789 {
3790 // IntGetWindowLong(offset == GWLP_CONSOLE_LEADER_TID)
3791 Result = (DWORD)(*((LONG_PTR*)((PCHAR)(pWnd + 1) + GWLP_CONSOLE_LEADER_TID)));
3792 }
3793 else
3794 {
3795 Result = (DWORD)IntGetWndThreadId(pWnd);
3796 }
3797 break;
3798 }
3799
3800 case QUERY_WINDOW_ACTIVE:
3801 Result = (DWORD)(pWnd->head.pti->MessageQueue->spwndActive ? UserHMGetHandle(pWnd->head.pti->MessageQueue->spwndActive) : 0);
3802 break;
3803
3804 case QUERY_WINDOW_FOCUS:
3805 Result = (DWORD)(pWnd->head.pti->MessageQueue->spwndFocus ? UserHMGetHandle(pWnd->head.pti->MessageQueue->spwndFocus) : 0);
3806 break;
3807
3808 case QUERY_WINDOW_ISHUNG:
3809 Result = (DWORD)MsqIsHung(pWnd->head.pti);
3810 break;
3811
3812 case QUERY_WINDOW_REAL_ID:
3813 Result = (DWORD)pWnd->head.pti->pEThread->Cid.UniqueProcess;
3814 break;
3815
3816 case QUERY_WINDOW_FOREGROUND:
3817 Result = (pWnd->head.pti->MessageQueue == gpqForeground);
3818 break;
3819
3820 default:
3821 Result = (DWORD)NULL;
3822 break;
3823 }
3824
3825 RETURN( Result);
3826
3827 CLEANUP:
3828 TRACE("Leave NtUserQueryWindow, ret=%u\n", _ret_);
3829 UserLeave();
3830 END_CLEANUP;
3831 }
3832
3833 /*
3834 * @implemented
3835 */
3836 UINT APIENTRY
3837 NtUserRegisterWindowMessage(PUNICODE_STRING MessageNameUnsafe)
3838 {
3839 UNICODE_STRING SafeMessageName;
3840 NTSTATUS Status;
3841 UINT Ret;
3842 DECLARE_RETURN(UINT);
3843
3844 TRACE("Enter NtUserRegisterWindowMessage\n");
3845 UserEnterExclusive();
3846
3847 if(MessageNameUnsafe == NULL)
3848 {
3849 EngSetLastError(ERROR_INVALID_PARAMETER);
3850 RETURN( 0);
3851 }
3852
3853 Status = IntSafeCopyUnicodeStringTerminateNULL(&SafeMessageName, MessageNameUnsafe);
3854 if(!NT_SUCCESS(Status))
3855 {
3856 SetLastNtError(Status);
3857 RETURN( 0);
3858 }
3859
3860 Ret = (UINT)IntAddAtom(SafeMessageName.Buffer);
3861 if (SafeMessageName.Buffer)
3862 ExFreePoolWithTag(SafeMessageName.Buffer, TAG_STRING);
3863 RETURN( Ret);
3864
3865 CLEANUP:
3866 TRACE("Leave NtUserRegisterWindowMessage, ret=%u\n", _ret_);
3867 UserLeave();
3868 END_CLEANUP;
3869 }
3870
3871 /*
3872 * @implemented
3873 */
3874 BOOL APIENTRY
3875 NtUserSetWindowFNID(HWND hWnd,
3876 WORD fnID)
3877 {
3878 PWND Wnd;
3879 DECLARE_RETURN(BOOL);
3880
3881 TRACE("Enter NtUserSetWindowFNID\n");
3882 UserEnterExclusive();
3883
3884 if (!(Wnd = UserGetWindowObject(hWnd)))
3885 {
3886 RETURN( FALSE);
3887 }
3888
3889 if (Wnd->head.pti->ppi != PsGetCurrentProcessWin32Process())
3890 {
3891 EngSetLastError(ERROR_ACCESS_DENIED);
3892 RETURN( FALSE);
3893 }
3894
3895 // From user land we only set these.
3896 if (fnID != FNID_DESTROY)
3897 {
3898 /* HACK: The minimum should be FNID_BUTTON, but menu code relies on this */
3899 if (fnID < FNID_FIRST || fnID > FNID_GHOST ||
3900 Wnd->fnid != 0)
3901 {
3902 EngSetLastError(ERROR_INVALID_PARAMETER);
3903 RETURN( FALSE);
3904 }
3905 }
3906
3907 Wnd->fnid |= fnID;
3908 RETURN( TRUE);
3909
3910 CLEANUP:
3911 TRACE("Leave NtUserSetWindowFNID\n");
3912 UserLeave();
3913 END_CLEANUP;
3914 }
3915
3916 /*
3917 * NtUserDefSetText
3918 *
3919 * Undocumented function that is called from DefWindowProc to set
3920 * window text.
3921 *
3922 * Status
3923 * @implemented
3924 */
3925 BOOL APIENTRY
3926 NtUserDefSetText(HWND hWnd, PLARGE_STRING WindowText)
3927 {
3928 PWND Wnd;
3929 LARGE_STRING SafeText;
3930 UNICODE_STRING UnicodeString;
3931 BOOL Ret = TRUE;
3932
3933 TRACE("Enter NtUserDefSetText\n");
3934
3935 if (WindowText != NULL)
3936 {
3937 _SEH2_TRY
3938 {
3939 SafeText = ProbeForReadLargeString(WindowText);
3940 }
3941 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3942 {
3943 Ret = FALSE;
3944 SetLastNtError(_SEH2_GetExceptionCode());
3945 }
3946 _SEH2_END;
3947
3948 if (!Ret)
3949 return FALSE;
3950 }
3951 else
3952 return TRUE;
3953
3954 UserEnterExclusive();
3955
3956 if(!(Wnd = UserGetWindowObject(hWnd)))
3957 {
3958 UserLeave();
3959 return FALSE;
3960 }
3961
3962 // ReactOS uses Unicode and not mixed. Up/Down converting will take time.
3963 // Brought to you by: The Wine Project! Dysfunctional Thought Processes!
3964 // Now we know what the bAnsi is for.
3965 RtlInitUnicodeString(&UnicodeString, NULL);
3966 if (SafeText.Buffer)
3967 {
3968 _SEH2_TRY
3969 {
3970 if (SafeText.bAnsi)
3971 ProbeForRead(SafeText.Buffer, SafeText.Length, sizeof(CHAR));
3972 else
3973 ProbeForRead(SafeText.Buffer, SafeText.Length, sizeof(WCHAR));
3974 Ret = RtlLargeStringToUnicodeString(&UnicodeString, &SafeText);
3975 }
3976 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3977 {
3978 Ret = FALSE;
3979 SetLastNtError(_SEH2_GetExceptionCode());
3980 }
3981 _SEH2_END;
3982 if (!Ret) goto Exit;
3983 }
3984
3985 if (UnicodeString.Length != 0)
3986 {
3987 if (Wnd->strName.MaximumLength > 0 &&
3988 UnicodeString.Length <= Wnd->strName.MaximumLength - sizeof(UNICODE_NULL))
3989 {
3990 ASSERT(Wnd->strName.Buffer != NULL);
3991
3992 Wnd->strName.Length = UnicodeString.Length;
3993 Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0';
3994 RtlCopyMemory(Wnd->strName.Buffer,
3995 UnicodeString.Buffer,
3996 UnicodeString.Length);
3997 }
3998 else
3999 {
4000 PWCHAR buf;
4001 Wnd->strName.MaximumLength = Wnd->strName.Length = 0;
4002 buf = Wnd->strName.Buffer;
4003 Wnd->strName.Buffer = NULL;
4004 if (buf != NULL)
4005 {
4006 DesktopHeapFree(Wnd->head.rpdesk, buf);
4007 }
4008
4009 Wnd->strName.Buffer = DesktopHeapAlloc(Wnd->head.rpdesk,
4010 UnicodeString.Length + sizeof(UNICODE_NULL));
4011 if (Wnd->strName.Buffer != NULL)
4012 {
4013 Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0';
4014 RtlCopyMemory(Wnd->strName.Buffer,
4015 UnicodeString.Buffer,
4016 UnicodeString.Length);
4017 Wnd->strName.MaximumLength = UnicodeString.Length + sizeof(UNICODE_NULL);
4018 Wnd->strName.Length = UnicodeString.Length;
4019 }
4020 else
4021 {
4022 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
4023 Ret = FALSE;
4024 goto Exit;
4025 }
4026 }
4027 }
4028 else
4029 {
4030 Wnd->strName.Length = 0;
4031 if (Wnd->strName.Buffer != NULL)
4032 Wnd->strName.Buffer[0] = L'\0';
4033 }
4034
4035 // FIXME: HAX! Windows does not do this in here!
4036 // In User32, these are called after: NotifyWinEvent EVENT_OBJECT_NAMECHANGE than
4037 // RepaintButton, StaticRepaint, NtUserCallHwndLock HWNDLOCK_ROUTINE_REDRAWFRAMEANDHOOK, etc.
4038 /* Send shell notifications */
4039 if (!Wnd->spwndOwner && !IntGetParent(Wnd))
4040 {
4041 co_IntShellHookNotify(HSHELL_REDRAW, (WPARAM) hWnd, FALSE); // FIXME Flashing?
4042 }
4043
4044 Ret = TRUE;
4045 Exit:
4046 if (UnicodeString.Buffer) RtlFreeUnicodeString(&UnicodeString);
4047 TRACE("Leave NtUserDefSetText, ret=%i\n", Ret);
4048 UserLeave();
4049 return Ret;
4050 }
4051
4052 /*
4053 * NtUserInternalGetWindowText
4054 *
4055 * Status
4056 * @implemented
4057 */
4058
4059 INT APIENTRY
4060 NtUserInternalGetWindowText(HWND hWnd, LPWSTR lpString, INT nMaxCount)
4061 {
4062 PWND Wnd;
4063 NTSTATUS Status;
4064 INT Result;
4065 DECLARE_RETURN(INT);
4066
4067 TRACE("Enter NtUserInternalGetWindowText\n");
4068 UserEnterShared();
4069
4070 if(lpString && (nMaxCount <= 1))
4071 {
4072 EngSetLastError(ERROR_INVALID_PARAMETER);
4073 RETURN( 0);
4074 }
4075
4076 if(!(Wnd = UserGetWindowObject(hWnd)))
4077 {
4078 RETURN( 0);
4079 }
4080
4081 Result = Wnd->strName.Length / sizeof(WCHAR);
4082 if(lpString)
4083 {
4084 const WCHAR Terminator = L'\0';
4085 INT Copy;
4086 WCHAR *Buffer = (WCHAR*)lpString;
4087
4088 Copy = min(nMaxCount - 1, Result);
4089 if(Copy > 0)
4090 {
4091 Status = MmCopyToCaller(Buffer, Wnd->strName.Buffer, Copy * sizeof(WCHAR));
4092 if(!NT_SUCCESS(Status))
4093 {
4094 SetLastNtError(Status);
4095 RETURN( 0);
4096 }
4097 Buffer += Copy;
4098 }
4099
4100 Status = MmCopyToCaller(Buffer, &Terminator, sizeof(WCHAR));
4101 if(!NT_SUCCESS(Status))
4102 {
4103 SetLastNtError(Status);
4104 RETURN( 0);
4105 }
4106
4107 Result = Copy;
4108 }
4109
4110 RETURN( Result);
4111
4112 CLEANUP:
4113 TRACE("Leave NtUserInternalGetWindowText, ret=%i\n",_ret_);
4114 UserLeave();
4115 END_CLEANUP;
4116 }
4117
4118 /*
4119 API Call
4120 */
4121 BOOL
4122 FASTCALL
4123 IntShowOwnedPopups(PWND OwnerWnd, BOOL fShow )
4124 {
4125 int count = 0;
4126 PWND pWnd;
4127 HWND *win_array;
4128
4129 // ASSERT(OwnerWnd);
4130
4131 TRACE("Enter ShowOwnedPopups Show: %s\n", (fShow ? "TRUE" : "FALSE"));
4132 win_array = IntWinListChildren(OwnerWnd);
4133
4134 if (!win_array)
4135 return TRUE;
4136
4137 while (win_array[count])
4138 count++;
4139 while (--count >= 0)
4140 {
4141 if (!(pWnd = ValidateHwndNoErr( win_array[count] )))
4142 continue;
4143 if (pWnd->spwndOwner != OwnerWnd)
4144 continue;
4145
4146 if (fShow)
4147 {
4148 if (pWnd->state & WNDS_HIDDENPOPUP)
4149 {
4150 /* In Windows, ShowOwnedPopups(TRUE) generates
4151 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
4152 * regardless of the state of the owner
4153 */
4154 co_IntSendMessage(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
4155 continue;
4156 }
4157 }
4158 else
4159 {
4160 if (pWnd->style & WS_VISIBLE)
4161 {
4162 /* In Windows, ShowOwnedPopups(FALSE) generates
4163 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
4164 * regardless of the state of the owner
4165 */
4166 co_IntSendMessage(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
4167 continue;
4168 }
4169 }
4170
4171 }
4172 ExFreePoolWithTag(win_array, USERTAG_WINDOWLIST);
4173 TRACE("Leave ShowOwnedPopups\n");
4174 return TRUE;
4175 }
4176
4177 /* EOF */