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