23619566a705ffdd6b023c8014e4d68dbf0e85f8
[reactos.git] / reactos / win32ss / user / ntuser / window.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Win32k subsystem
4 * PURPOSE: Windows
5 * FILE: win32ss/user/ntuser/window.c
6 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 */
8
9 #include <win32k.h>
10 DBG_DEFAULT_CHANNEL(UserWnd);
11
12 INT gNestedWindowLimit = 50;
13
14 /* HELPER FUNCTIONS ***********************************************************/
15
16 BOOL FASTCALL UserUpdateUiState(PWND Wnd, WPARAM wParam)
17 {
18 WORD Action = LOWORD(wParam);
19 WORD Flags = HIWORD(wParam);
20
21 if (Flags & ~(UISF_HIDEFOCUS | UISF_HIDEACCEL | UISF_ACTIVE))
22 {
23 EngSetLastError(ERROR_INVALID_PARAMETER);
24 return FALSE;
25 }
26
27 switch (Action)
28 {
29 case UIS_INITIALIZE:
30 EngSetLastError(ERROR_INVALID_PARAMETER);
31 return FALSE;
32
33 case UIS_SET:
34 if (Flags & UISF_HIDEFOCUS)
35 Wnd->HideFocus = TRUE;
36 if (Flags & UISF_HIDEACCEL)
37 Wnd->HideAccel = TRUE;
38 break;
39
40 case UIS_CLEAR:
41 if (Flags & UISF_HIDEFOCUS)
42 Wnd->HideFocus = FALSE;
43 if (Flags & UISF_HIDEACCEL)
44 Wnd->HideAccel = FALSE;
45 break;
46 }
47
48 return TRUE;
49 }
50
51 PWND FASTCALL IntGetWindowObject(HWND hWnd)
52 {
53 PWND Window;
54
55 if (!hWnd) return NULL;
56
57 Window = UserGetWindowObject(hWnd);
58 if (Window)
59 Window->head.cLockObj++;
60
61 return Window;
62 }
63
64 PWND FASTCALL VerifyWnd(PWND pWnd)
65 {
66 HWND hWnd;
67 UINT State, State2;
68 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 EngSetLastError(ERROR_CANNOT_FIND_WND_CLASS);
1925 ERR("Failed to find class %wZ\n", ClassName);
1926 goto cleanup;
1927 }
1928
1929 /* Now find the parent and the owner window */
1930 hWndParent = pti->rpdesk->pDeskInfo->spwnd->head.h;
1931 hWndOwner = NULL;
1932
1933 if (Cs->hwndParent == HWND_MESSAGE)
1934 {
1935 Cs->hwndParent = hWndParent = pti->rpdesk->spwndMessage->head.h;
1936 }
1937 else if (Cs->hwndParent)
1938 {
1939 if ((Cs->style & (WS_CHILD|WS_POPUP)) != WS_CHILD)
1940 hWndOwner = Cs->hwndParent;
1941 else
1942 hWndParent = Cs->hwndParent;
1943 }
1944 else if ((Cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
1945 {
1946 ERR("Cannot create a child window without a parrent!\n");
1947 EngSetLastError(ERROR_TLW_WITH_WSCHILD);
1948 goto cleanup; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
1949 }
1950
1951 ParentWindow = hWndParent ? UserGetWindowObject(hWndParent): NULL;
1952 OwnerWindow = hWndOwner ? UserGetWindowObject(hWndOwner): NULL;
1953
1954 if (hWndParent && !ParentWindow)
1955 {
1956 ERR("Got invalid parent window handle\n");
1957 goto cleanup;
1958 }
1959
1960 if(OwnerWindow)
1961 {
1962 if (IntIsDesktopWindow(OwnerWindow)) OwnerWindow = NULL;
1963 else if (ParentWindow && !IntIsDesktopWindow(ParentWindow))
1964 {
1965 ERR("an owned window must be created as top-level\n");
1966 EngSetLastError( STATUS_ACCESS_DENIED );
1967 goto cleanup;
1968 }
1969 else /* owner must be a top-level window */
1970 {
1971 while ((OwnerWindow->style & (WS_POPUP|WS_CHILD)) == WS_CHILD && !IntIsDesktopWindow(OwnerWindow->spwndParent))
1972 OwnerWindow = OwnerWindow->spwndParent;
1973 }
1974 }
1975
1976 /* Fix the position and the size of the window */
1977 if (ParentWindow)
1978 {
1979 UserRefObjectCo(ParentWindow, &ParentRef);
1980 IntFixWindowCoordinates(Cs, ParentWindow, &dwShowMode);
1981 }
1982
1983 /* Allocate and initialize the new window */
1984 Window = IntCreateWindow(Cs,
1985 WindowName,
1986 Class,
1987 ParentWindow,
1988 OwnerWindow,
1989 acbiBuffer,
1990 NULL);
1991 if(!Window)
1992 {
1993 ERR("IntCreateWindow failed!\n");
1994 goto cleanup;
1995 }
1996
1997 hWnd = UserHMGetHandle(Window);
1998 hwndInsertAfter = HWND_TOP;
1999
2000 UserRefObjectCo(Window, &Ref);
2001 UserDereferenceObject(Window);
2002 ObDereferenceObject(WinSta);
2003
2004 //// Check for a hook to eliminate overhead. ////
2005 if ( ISITHOOKED(WH_CBT) || (pti->rpdesk->pDeskInfo->fsHooks & HOOKID_TO_FLAG(WH_CBT)) )
2006 {
2007 // Allocate the calling structures Justin Case this goes Global.
2008 pCsw = ExAllocatePoolWithTag(NonPagedPool, sizeof(CREATESTRUCTW), TAG_HOOK);
2009 pCbtCreate = ExAllocatePoolWithTag(NonPagedPool, sizeof(CBT_CREATEWNDW), TAG_HOOK);
2010 if (!pCsw || !pCbtCreate)
2011 {
2012 ERR("UserHeapAlloc() failed!\n");
2013 goto cleanup;
2014 }
2015
2016 /* Fill the new CREATESTRUCTW */
2017 RtlCopyMemory(pCsw, Cs, sizeof(CREATESTRUCTW));
2018 pCsw->style = Window->style; /* HCBT_CREATEWND needs the real window style */
2019
2020 // Based on the assumption this is from "unicode source" user32, ReactOS, answer is yes.
2021 if (!IS_ATOM(ClassName->Buffer))
2022 {
2023 if (Window->state & WNDS_ANSICREATOR)
2024 {
2025 ANSI_STRING AnsiString;
2026 AnsiString.MaximumLength = (USHORT)RtlUnicodeStringToAnsiSize(ClassName)+sizeof(CHAR);
2027 pszClass = UserHeapAlloc(AnsiString.MaximumLength);
2028 if (!pszClass)
2029 {
2030 ERR("UserHeapAlloc() failed!\n");
2031 goto cleanup;
2032 }
2033 RtlZeroMemory(pszClass, AnsiString.MaximumLength);
2034 AnsiString.Buffer = (PCHAR)pszClass;
2035 RtlUnicodeStringToAnsiString(&AnsiString, ClassName, FALSE);
2036 }
2037 else
2038 {
2039 UNICODE_STRING UnicodeString;
2040 UnicodeString.MaximumLength = ClassName->Length + sizeof(UNICODE_NULL);
2041 pszClass = UserHeapAlloc(UnicodeString.MaximumLength);
2042 if (!pszClass)
2043 {
2044 ERR("UserHeapAlloc() failed!\n");
2045 goto cleanup;
2046 }
2047 RtlZeroMemory(pszClass, UnicodeString.MaximumLength);
2048 UnicodeString.Buffer = (PWSTR)pszClass;
2049 RtlCopyUnicodeString(&UnicodeString, ClassName);
2050 }
2051 pCsw->lpszClass = UserHeapAddressToUser(pszClass);
2052 }
2053 if (WindowName->Length)
2054 {
2055 UNICODE_STRING Name;
2056 Name.Buffer = WindowName->Buffer;
2057 Name.Length = (USHORT)min(WindowName->Length, MAXUSHORT); // FIXME: LARGE_STRING truncated
2058 Name.MaximumLength = (USHORT)min(WindowName->MaximumLength, MAXUSHORT);
2059
2060 if (Window->state & WNDS_ANSICREATOR)
2061 {
2062 ANSI_STRING AnsiString;
2063 AnsiString.MaximumLength = (USHORT)RtlUnicodeStringToAnsiSize(&Name) + sizeof(CHAR);
2064 pszName = UserHeapAlloc(AnsiString.MaximumLength);
2065 if (!pszName)
2066 {
2067 ERR("UserHeapAlloc() failed!\n");
2068 goto cleanup;
2069 }
2070 RtlZeroMemory(pszName, AnsiString.MaximumLength);
2071 AnsiString.Buffer = (PCHAR)pszName;
2072 RtlUnicodeStringToAnsiString(&AnsiString, &Name, FALSE);
2073 }
2074 else
2075 {
2076 UNICODE_STRING UnicodeString;
2077 UnicodeString.MaximumLength = Name.Length + sizeof(UNICODE_NULL);
2078 pszName = UserHeapAlloc(UnicodeString.MaximumLength);
2079 if (!pszName)
2080 {
2081 ERR("UserHeapAlloc() failed!\n");
2082 goto cleanup;
2083 }
2084 RtlZeroMemory(pszName, UnicodeString.MaximumLength);
2085 UnicodeString.Buffer = (PWSTR)pszName;
2086 RtlCopyUnicodeString(&UnicodeString, &Name);
2087 }
2088 pCsw->lpszName = UserHeapAddressToUser(pszName);
2089 }
2090
2091 pCbtCreate->lpcs = pCsw;
2092 pCbtCreate->hwndInsertAfter = hwndInsertAfter;
2093
2094 //// Call the WH_CBT hook ////
2095 Result = co_HOOK_CallHooks(WH_CBT, HCBT_CREATEWND, (WPARAM) hWnd, (LPARAM) pCbtCreate);
2096 if (Result != 0)
2097 {
2098 ERR("WH_CBT HCBT_CREATEWND hook failed! 0x%x\n", Result);
2099 goto cleanup;
2100 }
2101 // Write back changes.
2102 Cs->cx = pCsw->cx;
2103 Cs->cy = pCsw->cy;
2104 Cs->x = pCsw->x;
2105 Cs->y = pCsw->y;
2106 hwndInsertAfter = pCbtCreate->hwndInsertAfter;
2107 }
2108
2109 /* NCCREATE and WM_NCCALCSIZE need the original values */
2110 Cs->lpszName = (LPCWSTR) WindowName;
2111 Cs->lpszClass = (LPCWSTR) ClassName;
2112
2113 if ((Cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
2114 {
2115 if (ParentWindow != co_GetDesktopWindow(Window))
2116 {
2117 Cs->x += ParentWindow->rcClient.left;
2118 Cs->y += ParentWindow->rcClient.top;
2119 }
2120 }
2121
2122 /* Send the WM_GETMINMAXINFO message */
2123 Size.cx = Cs->cx;
2124 Size.cy = Cs->cy;
2125
2126 if ((Cs->style & WS_THICKFRAME) || !(Cs->style & (WS_POPUP | WS_CHILD)))
2127 {
2128 co_WinPosGetMinMaxInfo(Window, &MaxSize, &MaxPos, &MinTrack, &MaxTrack);
2129 if (Size.cx > MaxTrack.x) Size.cx = MaxTrack.x;
2130 if (Size.cy > MaxTrack.y) Size.cy = MaxTrack.y;
2131 if (Size.cx < MinTrack.x) Size.cx = MinTrack.x;
2132 if (Size.cy < MinTrack.y) Size.cy = MinTrack.y;
2133 }
2134
2135 Window->rcWindow.left = Cs->x;
2136 Window->rcWindow.top = Cs->y;
2137 Window->rcWindow.right = Cs->x + Size.cx;
2138 Window->rcWindow.bottom = Cs->y + Size.cy;
2139 /*
2140 if (0 != (Window->style & WS_CHILD) && ParentWindow)
2141 {
2142 ERR("co_UserCreateWindowEx(): Offset rcWindow\n");
2143 RECTL_vOffsetRect(&Window->rcWindow,
2144 ParentWindow->rcClient.left,
2145 ParentWindow->rcClient.top);
2146 }
2147 */
2148 /* correct child window coordinates if mirroring on parent is enabled */
2149 if (ParentWindow != NULL)
2150 {
2151 if ( ((Cs->style & WS_CHILD) == WS_CHILD) &&
2152 ((ParentWindow->ExStyle & WS_EX_LAYOUTRTL) == WS_EX_LAYOUTRTL))
2153 {
2154 Window->rcWindow.right = ParentWindow->rcClient.right - (Window->rcWindow.left - ParentWindow->rcClient.left);
2155 Window->rcWindow.left = Window->rcWindow.right - Size.cx;
2156 }
2157 }
2158
2159 Window->rcClient = Window->rcWindow;
2160
2161 /* Link the window */
2162 if (NULL != ParentWindow)
2163 {
2164 /* Link the window into the siblings list */
2165 if ((Cs->style & (WS_CHILD|WS_MAXIMIZE)) == WS_CHILD)
2166 IntLinkHwnd(Window, HWND_BOTTOM);
2167 else
2168 IntLinkHwnd(Window, hwndInsertAfter);
2169 }
2170
2171 if (!(Window->state2 & WNDS2_WIN31COMPAT))
2172 {
2173 if (Class->style & CS_PARENTDC && !(ParentWindow->style & WS_CLIPCHILDREN))
2174 Window->style &= ~(WS_CLIPSIBLINGS | WS_CLIPCHILDREN);
2175 }
2176
2177 if ((Window->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
2178 {
2179 if ( !IntIsTopLevelWindow(Window) )
2180 {
2181 if (pti != Window->spwndParent->head.pti)
2182 {
2183 //ERR("CreateWindow Parent in.\n");
2184 UserAttachThreadInput(pti, Window->spwndParent->head.pti, TRUE);
2185 }
2186 }
2187 }
2188
2189 /* Send the NCCREATE message */
2190 Result = co_IntSendMessage(UserHMGetHandle(Window), WM_NCCREATE, 0, (LPARAM) Cs);
2191 if (!Result)
2192 {
2193 ERR("co_UserCreateWindowEx(): NCCREATE message failed\n");
2194 goto cleanup;
2195 }
2196
2197 /* Send the WM_NCCALCSIZE message */
2198 {
2199 // RECT rc;
2200 MaxPos.x = Window->rcWindow.left;
2201 MaxPos.y = Window->rcWindow.top;
2202
2203 Result = co_WinPosGetNonClientSize(Window, &Window->rcWindow, &Window->rcClient);
2204 //rc = Window->rcWindow;
2205 //Result = co_IntSendMessageNoWait(Window->head.h, WM_NCCALCSIZE, FALSE, (LPARAM)&rc);
2206 //Window->rcClient = rc;
2207
2208 RECTL_vOffsetRect(&Window->rcWindow, MaxPos.x - Window->rcWindow.left,
2209 MaxPos.y - Window->rcWindow.top);
2210 }
2211
2212 /* Send the WM_CREATE message. */
2213 Result = co_IntSendMessage(UserHMGetHandle(Window), WM_CREATE, 0, (LPARAM) Cs);
2214 if (Result == (LRESULT)-1)
2215 {
2216 ERR("co_UserCreateWindowEx(): WM_CREATE message failed\n");
2217 goto cleanup;
2218 }
2219
2220 /* Send the EVENT_OBJECT_CREATE event */
2221 IntNotifyWinEvent(EVENT_OBJECT_CREATE, Window, OBJID_WINDOW, CHILDID_SELF, 0);
2222
2223 /* By setting the flag below it can be examined to determine if the window
2224 was created successfully and a valid pwnd was passed back to caller since
2225 from here the function has to succeed. */
2226 Window->state2 |= WNDS2_WMCREATEMSGPROCESSED;
2227
2228 /* Send the WM_SIZE and WM_MOVE messages. */
2229 if (!(Window->state & WNDS_SENDSIZEMOVEMSGS))
2230 {
2231 co_WinPosSendSizeMove(Window);
2232 }
2233
2234 /* Show or maybe minimize or maximize the window. */
2235
2236 style = IntSetStyle( Window, 0, WS_MAXIMIZE | WS_MINIMIZE );
2237 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
2238 {
2239 RECTL NewPos;
2240 UINT SwFlag = (style & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;
2241
2242 SwFlag = co_WinPosMinMaximize(Window, SwFlag, &NewPos);
2243 SwFlag |= SWP_NOZORDER|SWP_FRAMECHANGED; /* Frame always gets changed */
2244 if (!(style & WS_VISIBLE) || (style & WS_CHILD) || UserGetActiveWindow()) SwFlag |= SWP_NOACTIVATE;
2245 co_WinPosSetWindowPos(Window, 0, NewPos.left, NewPos.top,
2246 NewPos.right, NewPos.bottom, SwFlag);
2247 }
2248
2249 /* Send the WM_PARENTNOTIFY message */
2250 IntSendParentNotify(Window, WM_CREATE);
2251
2252 /* Notify the shell that a new window was created */
2253 if (Window->spwndParent == UserGetDesktopWindow() &&
2254 Window->spwndOwner == NULL &&
2255 (Window->style & WS_VISIBLE) &&
2256 (!(Window->ExStyle & WS_EX_TOOLWINDOW) ||
2257 (Window->ExStyle & WS_EX_APPWINDOW)))
2258 {
2259 co_IntShellHookNotify(HSHELL_WINDOWCREATED, (WPARAM)hWnd, 0);
2260 }
2261
2262 /* Initialize and show the window's scrollbars */
2263 if (Window->style & WS_VSCROLL)
2264 {
2265 co_UserShowScrollBar(Window, SB_VERT, FALSE, TRUE);
2266 }
2267 if (Window->style & WS_HSCROLL)
2268 {
2269 co_UserShowScrollBar(Window, SB_HORZ, TRUE, FALSE);
2270 }
2271
2272 /* Show the new window */
2273 if (Cs->style & WS_VISIBLE)
2274 {
2275 if (Window->style & WS_MAXIMIZE)
2276 dwShowMode = SW_SHOW;
2277 else if (Window->style & WS_MINIMIZE)
2278 dwShowMode = SW_SHOWMINIMIZED;
2279
2280 co_WinPosShowWindow(Window, dwShowMode);
2281
2282 if (Window->ExStyle & WS_EX_MDICHILD)
2283 {
2284 ASSERT(ParentWindow);
2285 if(!ParentWindow)
2286 goto cleanup;
2287 co_IntSendMessage(UserHMGetHandle(ParentWindow), WM_MDIREFRESHMENU, 0, 0);
2288 /* ShowWindow won't activate child windows */
2289 co_WinPosSetWindowPos(Window, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
2290 }
2291 }
2292
2293 if (Class->atomClassName == gaGuiConsoleWndClass)
2294 {
2295 /* Count only console windows manually */
2296 co_IntUserManualGuiCheck(TRUE);
2297 }
2298
2299 TRACE("co_UserCreateWindowEx(): Created window %p\n", hWnd);
2300 ret = Window;
2301
2302 cleanup:
2303 if (!ret)
2304 {
2305 TRACE("co_UserCreateWindowEx(): Error Created window!\n");
2306 /* If the window was created, the class will be dereferenced by co_UserDestroyWindow */
2307 if (Window)
2308 co_UserDestroyWindow(Window);
2309 else if (Class)
2310 IntDereferenceClass(Class, pti->pDeskInfo, pti->ppi);
2311 }
2312
2313 if (pCsw) ExFreePoolWithTag(pCsw, TAG_HOOK);
2314 if (pCbtCreate) ExFreePoolWithTag(pCbtCreate, TAG_HOOK);
2315 if (pszName) UserHeapFree(pszName);
2316 if (pszClass) UserHeapFree(pszClass);
2317
2318 if (Window)
2319 {
2320 UserDerefObjectCo(Window);
2321 }
2322 if (ParentWindow) UserDerefObjectCo(ParentWindow);
2323
2324 return ret;
2325 }
2326
2327 NTSTATUS
2328 NTAPI
2329 ProbeAndCaptureLargeString(
2330 OUT PLARGE_STRING plstrSafe,
2331 IN PLARGE_STRING plstrUnsafe)
2332 {
2333 LARGE_STRING lstrTemp;
2334 PVOID pvBuffer = NULL;
2335
2336 _SEH2_TRY
2337 {
2338 /* Probe and copy the string */
2339 ProbeForRead(plstrUnsafe, sizeof(LARGE_STRING), sizeof(ULONG));
2340 lstrTemp = *plstrUnsafe;
2341 }
2342 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2343 {
2344 /* Fail */
2345 _SEH2_YIELD(return _SEH2_GetExceptionCode();)
2346 }
2347 _SEH2_END
2348
2349 if (lstrTemp.Length != 0)
2350 {
2351 /* Allocate a buffer from paged pool */
2352 pvBuffer = ExAllocatePoolWithTag(PagedPool, lstrTemp.Length, TAG_STRING);
2353 if (!pvBuffer)
2354 {
2355 return STATUS_NO_MEMORY;
2356 }
2357
2358 _SEH2_TRY
2359 {
2360 /* Probe and copy the buffer */
2361 ProbeForRead(lstrTemp.Buffer, lstrTemp.Length, sizeof(WCHAR));
2362 RtlCopyMemory(pvBuffer, lstrTemp.Buffer, lstrTemp.Length);
2363 }
2364 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2365 {
2366 /* Cleanup and fail */
2367 ExFreePoolWithTag(pvBuffer, TAG_STRING);
2368 _SEH2_YIELD(return _SEH2_GetExceptionCode();)
2369 }
2370 _SEH2_END
2371 }
2372
2373 /* Set the output string */
2374 plstrSafe->Buffer = pvBuffer;
2375 plstrSafe->Length = lstrTemp.Length;
2376 plstrSafe->MaximumLength = lstrTemp.Length;
2377
2378 return STATUS_SUCCESS;
2379 }
2380
2381 /**
2382 * \todo Allow passing plstrClassName as ANSI.
2383 */
2384 HWND
2385 NTAPI
2386 NtUserCreateWindowEx(
2387 DWORD dwExStyle,
2388 PLARGE_STRING plstrClassName,
2389 PLARGE_STRING plstrClsVersion,
2390 PLARGE_STRING plstrWindowName,
2391 DWORD dwStyle,
2392 int x,
2393 int y,
2394 int nWidth,
2395 int nHeight,
2396 HWND hWndParent,
2397 HMENU hMenu,
2398 HINSTANCE hInstance,
2399 LPVOID lpParam,
2400 DWORD dwFlags,
2401 PVOID acbiBuffer)
2402 {
2403 NTSTATUS Status;
2404 LARGE_STRING lstrWindowName;
2405 LARGE_STRING lstrClassName;
2406 UNICODE_STRING ustrClassName;
2407 CREATESTRUCTW Cs;
2408 HWND hwnd = NULL;
2409 PWND pwnd;
2410
2411 lstrWindowName.Buffer = NULL;
2412 lstrClassName.Buffer = NULL;
2413
2414 ASSERT(plstrWindowName);
2415
2416 if ( (dwStyle & (WS_POPUP|WS_CHILD)) != WS_CHILD)
2417 {
2418 /* check hMenu is valid handle */
2419 if (hMenu && !UserGetMenuObject(hMenu))
2420 {
2421 ERR("NtUserCreateWindowEx: Got an invalid menu handle!\n");
2422 EngSetLastError(ERROR_INVALID_MENU_HANDLE);
2423 return NULL;
2424 }
2425 }
2426
2427 /* Copy the window name to kernel mode */
2428 Status = ProbeAndCaptureLargeString(&lstrWindowName, plstrWindowName);
2429 if (!NT_SUCCESS(Status))
2430 {
2431 ERR("NtUserCreateWindowEx: failed to capture plstrWindowName\n");
2432 SetLastNtError(Status);
2433 return NULL;
2434 }
2435
2436 plstrWindowName = &lstrWindowName;
2437
2438 /* Check if the class is an atom */
2439 if (IS_ATOM(plstrClassName))
2440 {
2441 /* It is, pass the atom in the UNICODE_STRING */
2442 ustrClassName.Buffer = (PVOID)plstrClassName;
2443 ustrClassName.Length = 0;
2444 ustrClassName.MaximumLength = 0;
2445 }
2446 else
2447 {
2448 /* It's not, capture the class name */
2449 Status = ProbeAndCaptureLargeString(&lstrClassName, plstrClassName);
2450 if (!NT_SUCCESS(Status))
2451 {
2452 ERR("NtUserCreateWindowEx: failed to capture plstrClassName\n");
2453 /* Set last error, cleanup and return */
2454 SetLastNtError(Status);
2455 goto cleanup;
2456 }
2457
2458 /* We pass it on as a UNICODE_STRING */
2459 ustrClassName.Buffer = lstrClassName.Buffer;
2460 ustrClassName.Length = (USHORT)min(lstrClassName.Length, MAXUSHORT); // FIXME: LARGE_STRING truncated
2461 ustrClassName.MaximumLength = (USHORT)min(lstrClassName.MaximumLength, MAXUSHORT);
2462 }
2463
2464 /* Fill the CREATESTRUCTW */
2465 /* we will keep here the original parameters */
2466 Cs.style = dwStyle;
2467 Cs.lpCreateParams = lpParam;
2468 Cs.hInstance = hInstance;
2469 Cs.hMenu = hMenu;
2470 Cs.hwndParent = hWndParent;
2471 Cs.cx = nWidth;
2472 Cs.cy = nHeight;
2473 Cs.x = x;
2474 Cs.y = y;
2475 Cs.lpszName = (LPCWSTR) plstrWindowName->Buffer;
2476 Cs.lpszClass = ustrClassName.Buffer;
2477 Cs.dwExStyle = dwExStyle;
2478
2479 UserEnterExclusive();
2480
2481 /* Call the internal function */
2482 pwnd = co_UserCreateWindowEx(&Cs, &ustrClassName, plstrWindowName, acbiBuffer);
2483
2484 if(!pwnd)
2485 {
2486 ERR("co_UserCreateWindowEx failed!\n");
2487 }
2488 hwnd = pwnd ? UserHMGetHandle(pwnd) : NULL;
2489
2490 UserLeave();
2491
2492 cleanup:
2493 if (lstrWindowName.Buffer)
2494 {
2495 ExFreePoolWithTag(lstrWindowName.Buffer, TAG_STRING);
2496 }
2497 if (lstrClassName.Buffer)
2498 {
2499 ExFreePoolWithTag(lstrClassName.Buffer, TAG_STRING);
2500 }
2501
2502 return hwnd;
2503 }
2504
2505
2506 BOOLEAN co_UserDestroyWindow(PVOID Object)
2507 {
2508 HWND hWnd;
2509 PWND pwndTemp;
2510 PTHREADINFO ti;
2511 MSG msg;
2512 PWND Window = Object;
2513
2514 ASSERT_REFS_CO(Window); // FIXME: Temp HACK?
2515
2516 hWnd = Window->head.h;
2517 ti = PsGetCurrentThreadWin32Thread();
2518
2519 TRACE("co_UserDestroyWindow \n");
2520
2521 /* Check for owner thread */
2522 if ( Window->head.pti != PsGetCurrentThreadWin32Thread())
2523 {
2524 /* Check if we are destroying the desktop window */
2525 if (! ((Window->head.rpdesk->dwDTFlags & DF_DESTROYED) && Window == Window->head.rpdesk->pDeskInfo->spwnd))
2526 {
2527 EngSetLastError(ERROR_ACCESS_DENIED);
2528 return FALSE;
2529 }
2530 }
2531
2532 /* If window was created successfully and it is hooked */
2533 if ((Window->state2 & WNDS2_WMCREATEMSGPROCESSED))
2534 {
2535 if (co_HOOK_CallHooks(WH_CBT, HCBT_DESTROYWND, (WPARAM) hWnd, 0))
2536 {
2537 ERR("Destroy Window WH_CBT Call Hook return!\n");
2538 return FALSE;
2539 }
2540 }
2541
2542 if (Window->pcls->atomClassName != gpsi->atomSysClass[ICLS_IME])
2543 {
2544 if ((Window->style & (WS_POPUP|WS_CHILD)) != WS_CHILD)
2545 {
2546 if (Window->spwndOwner)
2547 {
2548 //ERR("DestroyWindow Owner out.\n");
2549 UserAttachThreadInput(Window->head.pti, Window->spwndOwner->head.pti, FALSE);
2550 }
2551 }
2552 }
2553
2554 /* Inform the parent */
2555 if (Window->style & WS_CHILD)
2556 {
2557 IntSendParentNotify(Window, WM_DESTROY);
2558 }
2559
2560 if (!Window->spwndOwner && !IntGetParent(Window))
2561 {
2562 co_IntShellHookNotify(HSHELL_WINDOWDESTROYED, (WPARAM) hWnd, 0);
2563 }
2564
2565 /* Hide the window */
2566 if (Window->style & WS_VISIBLE)
2567 {
2568 if (Window->style & WS_CHILD)
2569 {
2570 /* Only child windows receive WM_SHOWWINDOW in DestroyWindow() */
2571 co_WinPosShowWindow(Window, SW_HIDE);
2572 }
2573 else
2574 {
2575 co_WinPosSetWindowPos(Window, 0, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_HIDEWINDOW );
2576 }
2577 }
2578
2579 // Adjust last active.
2580 if ((pwndTemp = Window->spwndOwner))
2581 {
2582 while (pwndTemp->spwndOwner)
2583 pwndTemp = pwndTemp->spwndOwner;
2584
2585 if (pwndTemp->spwndLastActive == Window)
2586 pwndTemp->spwndLastActive = Window->spwndOwner;
2587 }
2588
2589 if (Window->spwndParent && IntIsWindow(UserHMGetHandle(Window)))
2590 {
2591 if ((Window->style & (WS_POPUP | WS_CHILD)) == WS_CHILD)
2592 {
2593 if (!IntIsTopLevelWindow(Window))
2594 {
2595 //ERR("DestroyWindow Parent out.\n");
2596 UserAttachThreadInput(Window->head.pti, Window->spwndParent->head.pti, FALSE);
2597 }
2598 }
2599 }
2600
2601 if (Window->head.pti->MessageQueue->spwndActive == Window)
2602 Window->head.pti->MessageQueue->spwndActive = NULL;
2603 if (Window->head.pti->MessageQueue->spwndFocus == Window)
2604 Window->head.pti->MessageQueue->spwndFocus = NULL;
2605 if (Window->head.pti->MessageQueue->spwndActivePrev == Window)
2606 Window->head.pti->MessageQueue->spwndActivePrev = NULL;
2607 if (Window->head.pti->MessageQueue->spwndCapture == Window)
2608 Window->head.pti->MessageQueue->spwndCapture = NULL;
2609
2610 /*
2611 * Check if this window is the Shell's Desktop Window. If so set hShellWindow to NULL
2612 */
2613
2614 if ((ti != NULL) && (ti->pDeskInfo != NULL))
2615 {
2616 if (ti->pDeskInfo->hShellWindow == hWnd)
2617 {
2618 ERR("Destroying the ShellWindow!\n");
2619 ti->pDeskInfo->hShellWindow = NULL;
2620 }
2621 }
2622
2623 IntEngWindowChanged(Window, WOC_DELETE);
2624
2625 if (!IntIsWindow(UserHMGetHandle(Window)))
2626 {
2627 return TRUE;
2628 }
2629
2630 /* Recursively destroy owned windows */
2631
2632 if (! (Window->style & WS_CHILD))
2633 {
2634 for (;;)
2635 {
2636 BOOL GotOne = FALSE;
2637 HWND *Children;
2638 HWND *ChildHandle;
2639 PWND Child, Desktop;
2640
2641 Desktop = IntIsDesktopWindow(Window) ? Window :
2642 UserGetWindowObject(IntGetDesktopWindow());
2643 Children = IntWinListChildren(Desktop);
2644
2645 if (Children)
2646 {
2647 for (ChildHandle = Children; *ChildHandle; ++ChildHandle)
2648 {
2649 Child = UserGetWindowObject(*ChildHandle);
2650 if (Child == NULL)
2651 continue;
2652 if (Child->spwndOwner != Window)
2653 {
2654 continue;
2655 }
2656
2657 if (IntWndBelongsToThread(Child, PsGetCurrentThreadWin32Thread()))
2658 {
2659 USER_REFERENCE_ENTRY ChildRef;
2660 UserRefObjectCo(Child, &ChildRef); // Temp HACK?
2661 co_UserDestroyWindow(Child);
2662 UserDerefObjectCo(Child); // Temp HACK?
2663
2664 GotOne = TRUE;
2665 continue;
2666 }
2667
2668 if (Child->spwndOwner != NULL)
2669 {
2670 Child->spwndOwner = NULL;
2671 }
2672
2673 }
2674 ExFreePoolWithTag(Children, USERTAG_WINDOWLIST);
2675 }
2676 if (! GotOne)
2677 {
2678 break;
2679 }
2680 }
2681 }
2682
2683 /* Generate mouse move message for the next window */
2684 msg.message = WM_MOUSEMOVE;
2685 msg.wParam = UserGetMouseButtonsState();
2686 msg.lParam = MAKELPARAM(gpsi->ptCursor.x, gpsi->ptCursor.y);
2687 msg.pt = gpsi->ptCursor;
2688 co_MsqInsertMouseMessage(&msg, 0, 0, TRUE);
2689
2690 IntNotifyWinEvent(EVENT_OBJECT_DESTROY, Window, OBJID_WINDOW, CHILDID_SELF, 0);
2691
2692 /* Send destroy messages */
2693 IntSendDestroyMsg(UserHMGetHandle(Window));
2694
2695 if (!IntIsWindow(UserHMGetHandle(Window)))
2696 {
2697 return TRUE;
2698 }
2699
2700 /* Destroy the window storage */
2701 co_UserFreeWindow(Window, PsGetCurrentProcessWin32Process(), PsGetCurrentThreadWin32Thread(), TRUE);
2702
2703 return TRUE;
2704 }
2705
2706
2707 /*
2708 * @implemented
2709 */
2710 BOOLEAN APIENTRY
2711 NtUserDestroyWindow(HWND Wnd)
2712 {
2713 PWND Window;
2714 DECLARE_RETURN(BOOLEAN);
2715 BOOLEAN ret;
2716 USER_REFERENCE_ENTRY Ref;
2717
2718 TRACE("Enter NtUserDestroyWindow\n");
2719 UserEnterExclusive();
2720
2721 if (!(Window = UserGetWindowObject(Wnd)))
2722 {
2723 RETURN(FALSE);
2724 }
2725
2726 UserRefObjectCo(Window, &Ref); // FIXME: Dunno if win should be reffed during destroy...
2727 ret = co_UserDestroyWindow(Window);
2728 UserDerefObjectCo(Window); // FIXME: Dunno if win should be reffed during destroy...
2729
2730 RETURN(ret);
2731
2732 CLEANUP:
2733 TRACE("Leave NtUserDestroyWindow, ret=%u\n", _ret_);
2734 UserLeave();
2735 END_CLEANUP;
2736 }
2737
2738
2739 static HWND FASTCALL
2740 IntFindWindow(PWND Parent,
2741 PWND ChildAfter,
2742 RTL_ATOM ClassAtom,
2743 PUNICODE_STRING WindowName)
2744 {
2745 BOOL CheckWindowName;
2746 HWND *List, *phWnd;
2747 HWND Ret = NULL;
2748 UNICODE_STRING CurrentWindowName;
2749
2750 ASSERT(Parent);
2751
2752 CheckWindowName = WindowName->Buffer != 0;
2753
2754 if((List = IntWinListChildren(Parent)))
2755 {
2756 phWnd = List;
2757 if(ChildAfter)
2758 {
2759 /* skip handles before and including ChildAfter */
2760 while(*phWnd && (*(phWnd++) != ChildAfter->head.h))
2761 ;
2762 }
2763
2764 /* search children */
2765 while(*phWnd)
2766 {
2767 PWND Child;
2768 if(!(Child = UserGetWindowObject(*(phWnd++))))
2769 {
2770 continue;
2771 }
2772
2773 /* Do not send WM_GETTEXT messages in the kernel mode version!
2774 The user mode version however calls GetWindowText() which will
2775 send WM_GETTEXT messages to windows belonging to its processes */
2776 if (!ClassAtom || Child->pcls->atomClassName == ClassAtom)
2777 {
2778 // FIXME: LARGE_STRING truncated
2779 CurrentWindowName.Buffer = Child->strName.Buffer;
2780 CurrentWindowName.Length = (USHORT)min(Child->strName.Length, MAXUSHORT);
2781 CurrentWindowName.MaximumLength = (USHORT)min(Child->strName.MaximumLength, MAXUSHORT);
2782 if(!CheckWindowName ||
2783 (Child->strName.Length < 0xFFFF &&
2784 !RtlCompareUnicodeString(WindowName, &CurrentWindowName, TRUE)))
2785 {
2786 Ret = Child->head.h;
2787 break;
2788 }
2789 }
2790 }
2791 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2792 }
2793
2794 return Ret;
2795 }
2796
2797 /*
2798 * FUNCTION:
2799 * Searches a window's children for a window with the specified
2800 * class and name
2801 * ARGUMENTS:
2802 * hwndParent = The window whose childs are to be searched.
2803 * NULL = desktop
2804 * HWND_MESSAGE = message-only windows
2805 *
2806 * hwndChildAfter = Search starts after this child window.
2807 * NULL = start from beginning
2808 *
2809 * ucClassName = Class name to search for
2810 * Reguired parameter.
2811 *
2812 * ucWindowName = Window name
2813 * ->Buffer == NULL = don't care
2814 *
2815 * RETURNS:
2816 * The HWND of the window if it was found, otherwise NULL
2817 */
2818 /*
2819 * @implemented
2820 */
2821 HWND APIENTRY
2822 NtUserFindWindowEx(HWND hwndParent,
2823 HWND hwndChildAfter,
2824 PUNICODE_STRING ucClassName,
2825 PUNICODE_STRING ucWindowName,
2826 DWORD dwUnknown)
2827 {
2828 PWND Parent, ChildAfter;
2829 UNICODE_STRING ClassName = {0}, WindowName = {0};
2830 HWND Desktop, Ret = NULL;
2831 BOOL DoMessageWnd = FALSE;
2832 RTL_ATOM ClassAtom = (RTL_ATOM)0;
2833 DECLARE_RETURN(HWND);
2834
2835 TRACE("Enter NtUserFindWindowEx\n");
2836 UserEnterShared();
2837
2838 if (ucClassName != NULL || ucWindowName != NULL)
2839 {
2840 _SEH2_TRY
2841 {
2842 if (ucClassName != NULL)
2843 {
2844 ClassName = ProbeForReadUnicodeString(ucClassName);
2845 if (ClassName.Length != 0)
2846 {
2847 ProbeForRead(ClassName.Buffer,
2848 ClassName.Length,
2849 sizeof(WCHAR));
2850 }
2851 else if (!IS_ATOM(ClassName.Buffer))
2852 {
2853 EngSetLastError(ERROR_INVALID_PARAMETER);
2854 _SEH2_LEAVE;
2855 }
2856
2857 if (!IntGetAtomFromStringOrAtom(&ClassName,
2858 &ClassAtom))
2859 {
2860 EngSetLastError(ERROR_CANNOT_FIND_WND_CLASS);
2861 _SEH2_LEAVE;
2862 }
2863 }
2864
2865 if (ucWindowName != NULL)
2866 {
2867 WindowName = ProbeForReadUnicodeString(ucWindowName);
2868 if (WindowName.Length != 0)
2869 {
2870 ProbeForRead(WindowName.Buffer,
2871 WindowName.Length,
2872 sizeof(WCHAR));
2873 }
2874 }
2875 }
2876 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2877 {
2878 SetLastNtError(_SEH2_GetExceptionCode());
2879 _SEH2_YIELD(RETURN(NULL));
2880 }
2881 _SEH2_END;
2882
2883 if (ucClassName != NULL)
2884 {
2885 if (ClassName.Length == 0 && ClassName.Buffer != NULL &&
2886 !IS_ATOM(ClassName.Buffer))
2887 {
2888 EngSetLastError(ERROR_INVALID_PARAMETER);
2889 RETURN(NULL);
2890 }
2891 else if (ClassAtom == (RTL_ATOM)0)
2892 {
2893 /* LastError code was set by IntGetAtomFromStringOrAtom */
2894 RETURN(NULL);
2895 }
2896 }
2897 }
2898
2899 Desktop = IntGetCurrentThreadDesktopWindow();
2900
2901 if(hwndParent == NULL)
2902 {
2903 hwndParent = Desktop;
2904 DoMessageWnd = TRUE;
2905 }
2906 else if(hwndParent == HWND_MESSAGE)
2907 {
2908 hwndParent = IntGetMessageWindow();
2909 }
2910
2911 if(!(Parent = UserGetWindowObject(hwndParent)))
2912 {
2913 RETURN( NULL);
2914 }
2915
2916 ChildAfter = NULL;
2917 if(hwndChildAfter && !(ChildAfter = UserGetWindowObject(hwndChildAfter)))
2918 {
2919 RETURN( NULL);
2920 }
2921
2922 _SEH2_TRY
2923 {
2924 if(Parent->head.h == Desktop)
2925 {
2926 HWND *List, *phWnd;
2927 PWND TopLevelWindow;
2928 BOOLEAN CheckWindowName;
2929 BOOLEAN WindowMatches;
2930 BOOLEAN ClassMatches;
2931
2932 /* windows searches through all top-level windows if the parent is the desktop
2933 window */
2934
2935 if((List = IntWinListChildren(Parent)))
2936 {
2937 phWnd = List;
2938
2939 if(ChildAfter)
2940 {
2941 /* skip handles before and including ChildAfter */
2942 while(*phWnd && (*(phWnd++) != ChildAfter->head.h))
2943 ;
2944 }
2945
2946 CheckWindowName = WindowName.Buffer != 0;
2947
2948 /* search children */
2949 while(*phWnd)
2950 {
2951 UNICODE_STRING ustr;
2952
2953 if(!(TopLevelWindow = UserGetWindowObject(*(phWnd++))))
2954 {
2955 continue;
2956 }
2957
2958 /* Do not send WM_GETTEXT messages in the kernel mode version!
2959 The user mode version however calls GetWindowText() which will
2960 send WM_GETTEXT messages to windows belonging to its processes */
2961 ustr.Buffer = TopLevelWindow->strName.Buffer;
2962 ustr.Length = (USHORT)min(TopLevelWindow->strName.Length, MAXUSHORT); // FIXME:LARGE_STRING truncated
2963 ustr.MaximumLength = (USHORT)min(TopLevelWindow->strName.MaximumLength, MAXUSHORT);
2964 WindowMatches = !CheckWindowName ||
2965 (TopLevelWindow->strName.Length < 0xFFFF &&
2966 !RtlCompareUnicodeString(&WindowName, &ustr, TRUE));
2967 ClassMatches = (ClassAtom == (RTL_ATOM)0) ||
2968 ClassAtom == TopLevelWindow->pcls->atomClassName;
2969
2970 if (WindowMatches && ClassMatches)
2971 {
2972 Ret = TopLevelWindow->head.h;
2973 break;
2974 }
2975
2976 if (IntFindWindow(TopLevelWindow, NULL, ClassAtom, &WindowName))
2977 {
2978 /* window returns the handle of the top-level window, in case it found
2979 the child window */
2980 Ret = TopLevelWindow->head.h;
2981 break;
2982 }
2983
2984 }
2985 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2986 }
2987 }
2988 else
2989 {
2990 ERR("FindWindowEx: Not Desktop Parent!\n");
2991 Ret = IntFindWindow(Parent, ChildAfter, ClassAtom, &WindowName);
2992 }
2993
2994 if (Ret == NULL && DoMessageWnd)
2995 {
2996 PWND MsgWindows;
2997
2998 if((MsgWindows = UserGetWindowObject(IntGetMessageWindow())))
2999 {
3000 Ret = IntFindWindow(MsgWindows, ChildAfter, ClassAtom, &WindowName);
3001 }
3002 }
3003 }
3004 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3005 {
3006 SetLastNtError(_SEH2_GetExceptionCode());
3007 Ret = NULL;
3008 }
3009 _SEH2_END;
3010
3011 RETURN( Ret);
3012
3013 CLEANUP:
3014 TRACE("Leave NtUserFindWindowEx, ret %p\n", _ret_);
3015 UserLeave();
3016 END_CLEANUP;
3017 }
3018
3019
3020 /*
3021 * @implemented
3022 */
3023 PWND FASTCALL UserGetAncestor(PWND Wnd, UINT Type)
3024 {
3025 PWND WndAncestor, Parent;
3026
3027 if (Wnd->head.h == IntGetDesktopWindow())
3028 {
3029 return NULL;
3030 }
3031
3032 switch (Type)
3033 {
3034 case GA_PARENT:
3035 {
3036 WndAncestor = Wnd->spwndParent;
3037 break;
3038 }
3039
3040 case GA_ROOT:
3041 {
3042 WndAncestor = Wnd;
3043 Parent = NULL;
3044
3045 for(;;)
3046 {
3047 if(!(Parent = WndAncestor->spwndParent))
3048 {
3049 break;
3050 }
3051 if(IntIsDesktopWindow(Parent))
3052 {
3053 break;
3054 }
3055
3056 WndAncestor = Parent;
3057 }
3058 break;
3059 }
3060
3061 case GA_ROOTOWNER:
3062 {
3063 WndAncestor = Wnd;
3064
3065 for (;;)
3066 {
3067 Parent = IntGetParent(WndAncestor);
3068
3069 if (!Parent)
3070 {
3071 break;
3072 }
3073
3074 WndAncestor = Parent;
3075 }
3076 break;
3077 }
3078
3079 default:
3080 {
3081 return NULL;
3082 }
3083 }
3084
3085 return WndAncestor;
3086 }
3087
3088 /*
3089 * @implemented
3090 */
3091 HWND APIENTRY
3092 NtUserGetAncestor(HWND hWnd, UINT Type)
3093 {
3094 PWND Window, Ancestor;
3095 DECLARE_RETURN(HWND);
3096
3097 TRACE("Enter NtUserGetAncestor\n");
3098 UserEnterExclusive();
3099
3100 if (!(Window = UserGetWindowObject(hWnd)))
3101 {
3102 RETURN(NULL);
3103 }
3104
3105 Ancestor = UserGetAncestor(Window, Type);
3106 /* faxme: can UserGetAncestor ever return NULL for a valid window? */
3107
3108 RETURN(Ancestor ? Ancestor->head.h : NULL);
3109
3110 CLEANUP:
3111 TRACE("Leave NtUserGetAncestor, ret=%p\n", _ret_);
3112 UserLeave();
3113 END_CLEANUP;
3114 }
3115
3116 ////
3117 //// ReactOS work around! Keep it the sames as in Combo.c and Controls.h
3118 ////
3119 /* combo state struct */
3120 typedef struct
3121 {
3122 HWND self;
3123 HWND owner;
3124 UINT dwStyle;
3125 HWND hWndEdit;
3126 HWND hWndLBox;
3127 UINT wState;
3128 HFONT hFont;
3129 RECT textRect;
3130 RECT buttonRect;
3131 RECT droppedRect;
3132 INT droppedIndex;
3133 INT fixedOwnerDrawHeight;
3134 INT droppedWidth; /* last two are not used unless set */
3135 INT editHeight; /* explicitly */
3136 LONG UIState;
3137 } HEADCOMBO,*LPHEADCOMBO;
3138
3139 // Window Extra data container.
3140 typedef struct _WND2CBOX
3141 {
3142 WND;
3143 LPHEADCOMBO pCBox;
3144 } WND2CBOX, *PWND2CBOX;
3145
3146 #define CBF_BUTTONDOWN 0x0002
3147 ////
3148 ////
3149 ////
3150 BOOL
3151 APIENTRY
3152 NtUserGetComboBoxInfo(
3153 HWND hWnd,
3154 PCOMBOBOXINFO pcbi)
3155 {
3156 PWND Wnd;
3157 PPROCESSINFO ppi;
3158 BOOL NotSameppi = FALSE;
3159 BOOL Ret = TRUE;
3160 DECLARE_RETURN(BOOL);
3161
3162 TRACE("Enter NtUserGetComboBoxInfo\n");
3163 UserEnterShared();
3164
3165 if (!(Wnd = UserGetWindowObject(hWnd)))
3166 {
3167 RETURN( FALSE );
3168 }
3169 _SEH2_TRY
3170 {
3171 ProbeForWrite(pcbi, sizeof(COMBOBOXINFO), 1);
3172 }
3173 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3174 {
3175 SetLastNtError(_SEH2_GetExceptionCode());
3176 _SEH2_YIELD(RETURN(FALSE));
3177 }
3178 _SEH2_END;
3179
3180 if (pcbi->cbSize < sizeof(COMBOBOXINFO))
3181 {
3182 EngSetLastError(ERROR_INVALID_PARAMETER);
3183 RETURN(FALSE);
3184 }
3185
3186 // Pass the user pointer, it was already probed.
3187 if ((Wnd->pcls->atomClassName != gpsi->atomSysClass[ICLS_COMBOBOX]) && Wnd->fnid != FNID_COMBOBOX)
3188 {
3189 RETURN( (BOOL) co_IntSendMessage( Wnd->head.h, CB_GETCOMBOBOXINFO, 0, (LPARAM)pcbi));
3190 }
3191
3192 ppi = PsGetCurrentProcessWin32Process();
3193 NotSameppi = ppi != Wnd->head.pti->ppi;
3194 if (NotSameppi)
3195 {
3196 KeAttachProcess(&Wnd->head.pti->ppi->peProcess->Pcb);
3197 }
3198
3199 _SEH2_TRY
3200 {
3201 LPHEADCOMBO lphc = ((PWND2CBOX)Wnd)->pCBox;
3202 pcbi->rcItem = lphc->textRect;
3203 pcbi->rcButton = lphc->buttonRect;
3204 pcbi->stateButton = 0;
3205 if (lphc->wState & CBF_BUTTONDOWN)
3206 pcbi->stateButton |= STATE_SYSTEM_PRESSED;
3207 if (RECTL_bIsEmptyRect(&lphc->buttonRect))
3208 pcbi->stateButton |= STATE_SYSTEM_INVISIBLE;
3209 pcbi->hwndCombo = lphc->self;
3210 pcbi->hwndItem = lphc->hWndEdit;
3211 pcbi->hwndList = lphc->hWndLBox;
3212 }
3213 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3214 {
3215 Ret = FALSE;
3216 SetLastNtError(_SEH2_GetExceptionCode());
3217 }
3218 _SEH2_END;
3219
3220 RETURN( Ret);
3221
3222 CLEANUP:
3223 if (NotSameppi) KeDetachProcess();
3224 TRACE("Leave NtUserGetComboBoxInfo, ret=%i\n",_ret_);
3225 UserLeave();
3226 END_CLEANUP;
3227 }
3228
3229 ////
3230 //// ReactOS work around! Keep it the sames as in Listbox.c
3231 ////
3232 /* Listbox structure */
3233 typedef struct
3234 {
3235 HWND self; /* Our own window handle */
3236 HWND owner; /* Owner window to send notifications to */
3237 UINT style; /* Window style */
3238 INT width; /* Window width */
3239 INT height; /* Window height */
3240 VOID *items; /* Array of items */
3241 INT nb_items; /* Number of items */
3242 INT top_item; /* Top visible item */
3243 INT selected_item; /* Selected item */
3244 INT focus_item; /* Item that has the focus */
3245 INT anchor_item; /* Anchor item for extended selection */
3246 INT item_height; /* Default item height */
3247 INT page_size; /* Items per listbox page */
3248 INT column_width; /* Column width for multi-column listboxes */
3249 } LB_DESCR;
3250
3251 // Window Extra data container.
3252 typedef struct _WND2LB
3253 {
3254 WND;
3255 LB_DESCR * pLBiv;
3256 } WND2LB, *PWND2LB;
3257 ////
3258 ////
3259 ////
3260 DWORD
3261 APIENTRY
3262 NtUserGetListBoxInfo(
3263 HWND hWnd)
3264 {
3265 PWND Wnd;
3266 PPROCESSINFO ppi;
3267 BOOL NotSameppi = FALSE;
3268 DWORD Ret = 0;
3269 DECLARE_RETURN(DWORD);
3270
3271 TRACE("Enter NtUserGetListBoxInfo\n");
3272 UserEnterShared();
3273
3274 if (!(Wnd = UserGetWindowObject(hWnd)))
3275 {
3276 RETURN( 0 );
3277 }
3278
3279 if ((Wnd->pcls->atomClassName != gpsi->atomSysClass[ICLS_LISTBOX]) && Wnd->fnid != FNID_LISTBOX)
3280 {
3281 RETURN( (DWORD) co_IntSendMessage( Wnd->head.h, LB_GETLISTBOXINFO, 0, 0 ));
3282 }
3283
3284 // wine lisbox:test_GetListBoxInfo lb_getlistboxinfo = 0, should not send a message!
3285 ppi = PsGetCurrentProcessWin32Process();
3286 NotSameppi = ppi != Wnd->head.pti->ppi;
3287 if (NotSameppi)
3288 {
3289 KeAttachProcess(&Wnd->head.pti->ppi->peProcess->Pcb);
3290 }
3291
3292 _SEH2_TRY
3293 {
3294 LB_DESCR *descr = ((PWND2LB)Wnd)->pLBiv;
3295 // See Controls ListBox.c:LB_GETLISTBOXINFO must match...
3296 if (descr->style & LBS_MULTICOLUMN) //// ReactOS
3297 Ret = descr->page_size * descr->column_width;
3298 else
3299 Ret = descr->page_size;
3300 }
3301 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3302 {
3303 Ret = 0;
3304 SetLastNtError(_SEH2_GetExceptionCode());
3305 }
3306 _SEH2_END;
3307
3308 RETURN( Ret);
3309
3310 CLEANUP:
3311 if (NotSameppi) KeDetachProcess();
3312 TRACE("Leave NtUserGetListBoxInfo, ret=%lu\n", _ret_);
3313 UserLeave();
3314 END_CLEANUP;
3315 }
3316
3317 /*
3318 * NtUserSetParent
3319 *
3320 * The NtUserSetParent function changes the parent window of the specified
3321 * child window.
3322 *
3323 * Remarks
3324 * The new parent window and the child window must belong to the same
3325 * application. If the window identified by the hWndChild parameter is
3326 * visible, the system performs the appropriate redrawing and repainting.
3327 * For compatibility reasons, NtUserSetParent does not modify the WS_CHILD
3328 * or WS_POPUP window styles of the window whose parent is being changed.
3329 *
3330 * Status
3331 * @implemented
3332 */
3333
3334 HWND APIENTRY
3335 NtUserSetParent(HWND hWndChild, HWND hWndNewParent)
3336 {
3337 DECLARE_RETURN(HWND);
3338
3339 TRACE("Enter NtUserSetParent\n");
3340 UserEnterExclusive();
3341
3342 /*
3343 Check Parent first from user space, set it here.
3344 */
3345 if (!hWndNewParent)
3346 {
3347 hWndNewParent = IntGetDesktopWindow();
3348 }
3349 else if (hWndNewParent == HWND_MESSAGE)
3350 {
3351 hWndNewParent = IntGetMessageWindow();
3352 }
3353
3354 RETURN( co_UserSetParent(hWndChild, hWndNewParent));
3355
3356 CLEANUP:
3357 TRACE("Leave NtUserSetParent, ret=%p\n", _ret_);
3358 UserLeave();
3359 END_CLEANUP;
3360 }
3361
3362 /*
3363 * UserGetShellWindow
3364 *
3365 * Returns a handle to shell window that was set by NtUserSetShellWindowEx.
3366 *
3367 * Status
3368 * @implemented
3369 */
3370 HWND FASTCALL UserGetShellWindow(VOID)
3371 {
3372 PWINSTATION_OBJECT WinStaObject;
3373 HWND Ret;
3374
3375 NTSTATUS Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
3376 UserMode,
3377 0,
3378 &WinStaObject,
3379 0);
3380
3381 if (!NT_SUCCESS(Status))
3382 {
3383 SetLastNtError(Status);
3384 return( (HWND)0);
3385 }
3386
3387 Ret = (HWND)WinStaObject->ShellWindow;
3388
3389 ObDereferenceObject(WinStaObject);
3390 return( Ret);
3391 }
3392
3393 /*
3394 * NtUserSetShellWindowEx
3395 *
3396 * This is undocumented function to set global shell window. The global
3397 * shell window has special handling of window position.
3398 *
3399 * Status
3400 * @implemented
3401 */
3402 BOOL APIENTRY
3403 NtUserSetShellWindowEx(HWND hwndShell, HWND hwndListView)
3404 {
3405 PWINSTATION_OBJECT WinStaObject;
3406 PWND WndShell, WndListView;
3407 DECLARE_RETURN(BOOL);
3408 USER_REFERENCE_ENTRY Ref;
3409 NTSTATUS Status;
3410 PTHREADINFO ti;
3411
3412 TRACE("Enter NtUserSetShellWindowEx\n");
3413 UserEnterExclusive();
3414
3415 if (!(WndShell = UserGetWindowObject(hwndShell)))
3416 {
3417 RETURN(FALSE);
3418 }
3419
3420 if(!(WndListView = UserGetWindowObject(hwndListView)))
3421 {
3422 RETURN(FALSE);
3423 }
3424
3425 Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
3426 UserMode,
3427 0,
3428 &WinStaObject,
3429 0);
3430
3431 if (!NT_SUCCESS(Status))
3432 {
3433 SetLastNtError(Status);
3434 RETURN( FALSE);
3435 }
3436
3437 /*
3438 * Test if we are permitted to change the shell window.
3439 */
3440 if (WinStaObject->ShellWindow)
3441 {
3442 ObDereferenceObject(WinStaObject);
3443 RETURN( FALSE);
3444 }
3445
3446 /*
3447 * Move shell window into background.
3448 */
3449 if (hwndListView && hwndListView != hwndShell)
3450 {
3451 /*
3452 * Disabled for now to get Explorer working.
3453 * -- Filip, 01/nov/2003
3454 */
3455 #if 0
3456 co_WinPosSetWindowPos(WndListView, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
3457 #endif
3458
3459 if (WndListView->ExStyle & WS_EX_TOPMOST)
3460 {
3461 ObDereferenceObject(WinStaObject);
3462 RETURN( FALSE);
3463 }
3464 }
3465
3466 if (WndShell->ExStyle & WS_EX_TOPMOST)
3467 {
3468 ObDereferenceObject(WinStaObject);
3469 RETURN( FALSE);
3470 }
3471
3472 UserRefObjectCo(WndShell, &Ref);
3473 WndShell->state2 |= WNDS2_BOTTOMMOST;
3474 co_WinPosSetWindowPos(WndShell, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
3475
3476 WinStaObject->ShellWindow = hwndShell;
3477 WinStaObject->ShellListView = hwndListView;
3478
3479 ti = GetW32ThreadInfo();
3480 if (ti->pDeskInfo)
3481 {
3482 ti->pDeskInfo->hShellWindow = hwndShell;
3483 ti->pDeskInfo->spwndShell = WndShell;
3484 ti->pDeskInfo->spwndBkGnd = WndListView;
3485 ti->pDeskInfo->ppiShellProcess = ti->ppi;
3486 }
3487
3488 UserRegisterHotKey(WndShell, SC_TASKLIST, MOD_CONTROL, VK_ESCAPE);
3489
3490 UserDerefObjectCo(WndShell);
3491
3492 ObDereferenceObject(WinStaObject);
3493 RETURN( TRUE);
3494
3495 CLEANUP:
3496 TRACE("Leave NtUserSetShellWindowEx, ret=%i\n",_ret_);
3497 UserLeave();
3498 END_CLEANUP;
3499 }
3500
3501 // Fixes wine Win test_window_styles and todo tests...
3502 static BOOL FASTCALL
3503 IntCheckFrameEdge(ULONG Style, ULONG ExStyle)
3504 {
3505 if (ExStyle & WS_EX_DLGMODALFRAME)
3506 return TRUE;
3507 else if (!(ExStyle & WS_EX_STATICEDGE) && (Style & (WS_DLGFRAME | WS_THICKFRAME)))
3508 return TRUE;
3509 else
3510 return FALSE;
3511 }
3512
3513 static LONG
3514 co_IntSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi, BOOL bAlter)
3515 {
3516 PWND Window, Parent;
3517 PWINSTATION_OBJECT WindowStation;
3518 LONG OldValue;
3519 STYLESTRUCT Style;
3520
3521 if (!(Window = UserGetWindowObject(hWnd)))
3522 {
3523 return( 0);
3524 }
3525
3526 if ((INT)Index >= 0)
3527 {
3528 if ((Index + sizeof(LONG)) > Window->cbwndExtra)
3529 {
3530 EngSetLastError(ERROR_INVALID_INDEX);
3531 return( 0);
3532 }
3533
3534 OldValue = *((LONG *)((PCHAR)(Window + 1) + Index));
3535 /*
3536 if ( Index == DWLP_DLGPROC && Wnd->state & WNDS_DIALOGWINDOW)
3537 {
3538 OldValue = (LONG)IntSetWindowProc( Wnd,
3539 (WNDPROC)NewValue,
3540 Ansi);
3541 if (!OldValue) return 0;
3542 }
3543 */
3544 *((LONG *)((PCHAR)(Window + 1) + Index)) = NewValue;
3545 }
3546 else
3547 {
3548 switch (Index)
3549 {
3550 case GWL_EXSTYLE:
3551 OldValue = (LONG) Window->ExStyle;
3552 Style.styleOld = OldValue;
3553 Style.styleNew = NewValue;
3554
3555 co_IntSendMessage(hWnd, WM_STYLECHANGING, GWL_EXSTYLE, (LPARAM) &Style);
3556
3557 /*
3558 * Remove extended window style bit WS_EX_TOPMOST for shell windows.
3559 */
3560 WindowStation = Window->head.pti->rpdesk->rpwinstaParent;
3561 if(WindowStation)
3562 {
3563 if (hWnd == WindowStation->ShellWindow || hWnd == WindowStation->ShellListView)
3564 Style.styleNew &= ~WS_EX_TOPMOST;
3565 }
3566 /* WS_EX_WINDOWEDGE depends on some other styles */
3567 if (IntCheckFrameEdge(Window->style, NewValue))
3568 Style.styleNew |= WS_EX_WINDOWEDGE;
3569 else
3570 Style.styleNew &= ~WS_EX_WINDOWEDGE;
3571
3572 if (!(Window->ExStyle & WS_EX_LAYERED))
3573 {
3574 SetLayeredStatus(Window, 0);
3575 }
3576
3577 Window->ExStyle = (DWORD)Style.styleNew;
3578
3579 co_IntSendMessage(hWnd, WM_STYLECHANGED, GWL_EXSTYLE, (LPARAM) &Style);
3580 break;
3581
3582 case GWL_STYLE:
3583 OldValue = (LONG) Window->style;
3584 Style.styleOld = OldValue;
3585 Style.styleNew = NewValue;
3586
3587 if (!bAlter)
3588 co_IntSendMessage(hWnd, WM_STYLECHANGING, GWL_STYLE, (LPARAM) &Style);
3589
3590 /* WS_CLIPSIBLINGS can't be reset on top-level windows */
3591 if (Window->spwndParent == UserGetDesktopWindow()) Style.styleNew |= WS_CLIPSIBLINGS;
3592 /* WS_MINIMIZE can't be reset */
3593 if (OldValue & WS_MINIMIZE) Style.styleNew |= WS_MINIMIZE;
3594 /* Fixes wine FIXME: changing WS_DLGFRAME | WS_THICKFRAME is supposed to change WS_EX_WINDOWEDGE too */
3595 if (IntCheckFrameEdge(NewValue, Window->ExStyle))
3596 Window->ExStyle |= WS_EX_WINDOWEDGE;
3597 else
3598 Window->ExStyle &= ~WS_EX_WINDOWEDGE;
3599
3600 if ((OldValue & (WS_CHILD | WS_POPUP)) == WS_CHILD)
3601 {
3602 if ((NewValue & (WS_CHILD | WS_POPUP)) != WS_CHILD)
3603 {
3604 //// From child to non-child it should be null already.
3605 ERR("IDMenu going null! %d\n",Window->IDMenu);
3606 Window->IDMenu = 0; // Window->spmenu = 0;
3607 }
3608 }
3609 else
3610 {
3611 if ((NewValue & (WS_CHILD | WS_POPUP)) == WS_CHILD)
3612 {
3613 PMENU pMenu = UserGetMenuObject(UlongToHandle(Window->IDMenu));
3614 Window->state &= ~WNDS_HASMENU;
3615 if (pMenu)
3616 {
3617 ERR("IDMenu released 0x%p\n",pMenu);
3618 // ROS may not hold a lock after setting menu to window. But it should!
3619 //IntReleaseMenuObject(pMenu);
3620 }
3621 }
3622 }
3623
3624 if ((Style.styleOld ^ Style.styleNew) & WS_VISIBLE)
3625 {
3626 if (Style.styleOld & WS_VISIBLE) Window->head.pti->cVisWindows--;
3627 if (Style.styleNew & WS_VISIBLE) Window->head.pti->cVisWindows++;
3628 DceResetActiveDCEs( Window );
3629 }
3630 Window->style = (DWORD)Style.styleNew;
3631
3632 if (!bAlter)
3633 co_IntSendMessage(hWnd, WM_STYLECHANGED, GWL_STYLE, (LPARAM) &Style);
3634 break;
3635
3636 case GWL_WNDPROC:
3637 {
3638 if ( Window->head.pti->ppi != PsGetCurrentProcessWin32Process() ||
3639 Window->fnid & FNID_FREED)
3640 {
3641 EngSetLastError(ERROR_ACCESS_DENIED);
3642 return( 0);
3643 }
3644 OldValue = (LONG)IntSetWindowProc(Window,
3645 (WNDPROC)NewValue,
3646 Ansi);
3647 break;
3648 }
3649
3650 case GWL_HINSTANCE:
3651 OldValue = (LONG) Window->hModule;
3652 Window->hModule = (HINSTANCE) NewValue;
3653 break;
3654
3655 case GWL_HWNDPARENT:
3656 Parent = Window->spwndParent;
3657 if (Parent && (Parent->head.h == IntGetDesktopWindow()))
3658 OldValue = (LONG) IntSetOwner(Window->head.h, (HWND) NewValue);
3659 else
3660 OldValue = (LONG) co_UserSetParent(Window->head.h, (HWND) NewValue);
3661 break;
3662
3663 case GWL_ID:
3664 OldValue = (LONG) Window->IDMenu;
3665 Window->IDMenu = (UINT) NewValue;
3666 break;
3667
3668 case GWL_USERDATA:
3669 OldValue = Window->dwUserData;
3670 Window->dwUserData = NewValue;
3671 break;
3672
3673 default:
3674 ERR("NtUserSetWindowLong(): Unsupported index %lu\n", Index);
3675 EngSetLastError(ERROR_INVALID_INDEX);
3676 OldValue = 0;
3677 break;
3678 }
3679 }
3680
3681 return( OldValue);
3682 }
3683
3684
3685 LONG FASTCALL
3686 co_UserSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi)
3687 {
3688 return co_IntSetWindowLong(hWnd, Index, NewValue, Ansi, FALSE);
3689 }
3690
3691 /*
3692 * NtUserSetWindowLong
3693 *
3694 * The NtUserSetWindowLong function changes an attribute of the specified
3695 * window. The function also sets the 32-bit (long) value at the specified
3696 * offset into the extra window memory.
3697 *
3698 * Status
3699 * @implemented
3700 */
3701
3702 LONG APIENTRY
3703 NtUserSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi)
3704 {
3705 LONG ret;
3706
3707 UserEnterExclusive();
3708
3709 if (hWnd == IntGetDesktopWindow())
3710 {
3711 EngSetLastError(STATUS_ACCESS_DENIED);
3712 UserLeave();
3713 return 0;
3714 }
3715
3716 ret = co_IntSetWindowLong(hWnd, Index, NewValue, Ansi, FALSE);
3717
3718 UserLeave();
3719
3720 return ret;
3721 }
3722
3723 DWORD APIENTRY
3724 NtUserAlterWindowStyle(HWND hWnd, DWORD Index, LONG NewValue)
3725 {
3726 LONG ret;
3727
3728 UserEnterExclusive();
3729
3730 if (hWnd == IntGetDesktopWindow())
3731 {
3732 EngSetLastError(STATUS_ACCESS_DENIED);
3733 UserLeave();
3734 return 0;
3735 }
3736
3737 ret = co_IntSetWindowLong(hWnd, Index, NewValue, FALSE, TRUE);
3738
3739 UserLeave();
3740
3741 return ret;
3742 }
3743
3744
3745 /*
3746 * NtUserSetWindowWord
3747 *
3748 * Legacy function similar to NtUserSetWindowLong.
3749 *
3750 * Status
3751 * @implemented
3752 */
3753
3754 WORD APIENTRY
3755 NtUserSetWindowWord(HWND hWnd, INT Index, WORD NewValue)
3756 {
3757 PWND Window;
3758 WORD OldValue;
3759 DECLARE_RETURN(WORD);
3760
3761 TRACE("Enter NtUserSetWindowWord\n");
3762 UserEnterExclusive();
3763
3764 if (hWnd == IntGetDesktopWindow())
3765 {
3766 EngSetLastError(STATUS_ACCESS_DENIED);
3767 RETURN( 0);
3768 }
3769
3770 if (!(Window = UserGetWindowObject(hWnd)))
3771 {
3772 RETURN( 0);
3773 }
3774
3775 switch (Index)
3776 {
3777 case GWL_ID:
3778 case GWL_HINSTANCE:
3779 case GWL_HWNDPARENT:
3780 RETURN( (WORD)co_UserSetWindowLong(UserHMGetHandle(Window), Index, (UINT)NewValue, TRUE));
3781 default:
3782 if (Index < 0)
3783 {
3784 EngSetLastError(ERROR_INVALID_INDEX);
3785 RETURN( 0);
3786 }
3787 }
3788
3789 if ((ULONG)Index > (Window->cbwndExtra - sizeof(WORD)))
3790 {
3791 EngSetLastError(ERROR_INVALID_PARAMETER);
3792 RETURN( 0);
3793 }
3794
3795 OldValue = *((WORD *)((PCHAR)(Window + 1) + Index));
3796 *((WORD *)((PCHAR)(Window + 1) + Index)) = NewValue;
3797
3798 RETURN( OldValue);
3799
3800 CLEANUP:
3801 TRACE("Leave NtUserSetWindowWord, ret=%u\n", _ret_);
3802 UserLeave();
3803 END_CLEANUP;
3804 }
3805
3806 /*
3807 QueryWindow based on KJK::Hyperion and James Tabor.
3808
3809 0 = QWUniqueProcessId
3810 1 = QWUniqueThreadId
3811 2 = QWActiveWindow
3812 3 = QWFocusWindow
3813 4 = QWIsHung Implements IsHungAppWindow found
3814 by KJK::Hyperion.
3815
3816 9 = QWKillWindow When I called this with hWnd ==
3817 DesktopWindow, it shutdown the system
3818 and rebooted.
3819 */
3820 /*
3821 * @implemented
3822 */
3823 DWORD APIENTRY
3824 NtUserQueryWindow(HWND hWnd, DWORD Index)
3825 {
3826 /* Console Leader Process CID Window offsets */
3827 #define GWLP_CONSOLE_LEADER_PID 0
3828 #define GWLP_CONSOLE_LEADER_TID 4
3829
3830 PWND pWnd;
3831 DWORD Result;
3832 DECLARE_RETURN(UINT);
3833
3834 TRACE("Enter NtUserQueryWindow\n");
3835 UserEnterShared();
3836
3837 if (!(pWnd = UserGetWindowObject(hWnd)))
3838 {
3839 RETURN( 0);
3840 }
3841
3842 switch(Index)
3843 {
3844 case QUERY_WINDOW_UNIQUE_PROCESS_ID:
3845 {
3846 if ( (pWnd->head.pti->TIF_flags & TIF_CSRSSTHREAD) &&
3847 (pWnd->pcls->atomClassName == gaGuiConsoleWndClass) )
3848 {
3849 // IntGetWindowLong(offset == GWLP_CONSOLE_LEADER_PID)
3850 Result = (DWORD)(*((LONG_PTR*)((PCHAR)(pWnd + 1) + GWLP_CONSOLE_LEADER_PID)));
3851 }
3852 else
3853 {
3854 Result = (DWORD)IntGetWndProcessId(pWnd);
3855 }
3856 break;
3857 }
3858
3859 case QUERY_WINDOW_UNIQUE_THREAD_ID:
3860 {
3861 if ( (pWnd->head.pti->TIF_flags & TIF_CSRSSTHREAD) &&
3862 (pWnd->pcls->atomClassName == gaGuiConsoleWndClass) )
3863 {
3864 // IntGetWindowLong(offset == GWLP_CONSOLE_LEADER_TID)
3865 Result = (DWORD)(*((LONG_PTR*)((PCHAR)(pWnd + 1) + GWLP_CONSOLE_LEADER_TID)));
3866 }
3867 else
3868 {
3869 Result = (DWORD)IntGetWndThreadId(pWnd);
3870 }
3871 break;
3872 }
3873
3874 case QUERY_WINDOW_ACTIVE:
3875 Result = (DWORD)(pWnd->head.pti->MessageQueue->spwndActive ? UserHMGetHandle(pWnd->head.pti->MessageQueue->spwndActive) : 0);
3876 break;
3877
3878 case QUERY_WINDOW_FOCUS:
3879 Result = (DWORD)(pWnd->head.pti->MessageQueue->spwndFocus ? UserHMGetHandle(pWnd->head.pti->MessageQueue->spwndFocus) : 0);
3880 break;
3881
3882 case QUERY_WINDOW_ISHUNG:
3883 Result = (DWORD)MsqIsHung(pWnd->head.pti);
3884 break;
3885
3886 case QUERY_WINDOW_REAL_ID:
3887 Result = (DWORD)pWnd->head.pti->pEThread->Cid.UniqueProcess;
3888 break;
3889
3890 case QUERY_WINDOW_FOREGROUND:
3891 Result = (pWnd->head.pti->MessageQueue == gpqForeground);
3892 break;
3893
3894 default:
3895 Result = (DWORD)NULL;
3896 break;
3897 }
3898
3899 RETURN( Result);
3900
3901 CLEANUP:
3902 TRACE("Leave NtUserQueryWindow, ret=%u\n", _ret_);
3903 UserLeave();
3904 END_CLEANUP;
3905 }
3906
3907 /*
3908 * @implemented
3909 */
3910 UINT APIENTRY
3911 NtUserRegisterWindowMessage(PUNICODE_STRING MessageNameUnsafe)
3912 {
3913 UNICODE_STRING SafeMessageName;
3914 NTSTATUS Status;
3915 UINT Ret;
3916 DECLARE_RETURN(UINT);
3917
3918 TRACE("Enter NtUserRegisterWindowMessage\n");
3919 UserEnterExclusive();
3920
3921 if(MessageNameUnsafe == NULL)
3922 {
3923 EngSetLastError(ERROR_INVALID_PARAMETER);
3924 RETURN( 0);
3925 }
3926
3927 Status = IntSafeCopyUnicodeStringTerminateNULL(&SafeMessageName, MessageNameUnsafe);
3928 if(!NT_SUCCESS(Status))
3929 {
3930 SetLastNtError(Status);
3931 RETURN( 0);
3932 }
3933
3934 Ret = (UINT)IntAddAtom(SafeMessageName.Buffer);
3935 if (SafeMessageName.Buffer)
3936 ExFreePoolWithTag(SafeMessageName.Buffer, TAG_STRING);
3937 RETURN( Ret);
3938
3939 CLEANUP:
3940 TRACE("Leave NtUserRegisterWindowMessage, ret=%u\n", _ret_);
3941 UserLeave();
3942 END_CLEANUP;
3943 }
3944
3945 /*
3946 * @implemented
3947 */
3948 BOOL APIENTRY
3949 NtUserSetWindowFNID(HWND hWnd,
3950 WORD fnID)
3951 {
3952 PWND Wnd;
3953 DECLARE_RETURN(BOOL);
3954
3955 TRACE("Enter NtUserSetWindowFNID\n");
3956 UserEnterExclusive();
3957
3958 if (!(Wnd = UserGetWindowObject(hWnd)))
3959 {
3960 RETURN( FALSE);
3961 }
3962
3963 if (Wnd->head.pti->ppi != PsGetCurrentProcessWin32Process())
3964 {
3965 EngSetLastError(ERROR_ACCESS_DENIED);
3966 RETURN( FALSE);
3967 }
3968
3969 // From user land we only set these.
3970 if (fnID != FNID_DESTROY)
3971 {
3972 /* HACK: The minimum should be FNID_BUTTON, but menu code relies on this */
3973 if (fnID < FNID_FIRST || fnID > FNID_GHOST ||
3974 Wnd->fnid != 0)
3975 {
3976 EngSetLastError(ERROR_INVALID_PARAMETER);
3977 RETURN( FALSE);
3978 }
3979 }
3980
3981 Wnd->fnid |= fnID;
3982 RETURN( TRUE);
3983
3984 CLEANUP:
3985 TRACE("Leave NtUserSetWindowFNID\n");
3986 UserLeave();
3987 END_CLEANUP;
3988 }
3989
3990 BOOL APIENTRY
3991 DefSetText(PWND Wnd, PCWSTR WindowText)
3992 {
3993 UNICODE_STRING UnicodeString;
3994 BOOL Ret = FALSE;
3995
3996 RtlInitUnicodeString(&UnicodeString, WindowText);
3997
3998 if (UnicodeString.Length != 0)
3999 {
4000 if (Wnd->strName.MaximumLength > 0 &&
4001 UnicodeString.Length <= Wnd->strName.MaximumLength - sizeof(UNICODE_NULL))
4002 {
4003 ASSERT(Wnd->strName.Buffer != NULL);
4004
4005 Wnd->strName.Length = UnicodeString.Length;
4006 Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0';
4007 RtlCopyMemory(Wnd->strName.Buffer,
4008 UnicodeString.Buffer,
4009 UnicodeString.Length);
4010 }
4011 else
4012 {
4013 PWCHAR buf;
4014 Wnd->strName.MaximumLength = Wnd->strName.Length = 0;
4015 buf = Wnd->strName.Buffer;
4016 Wnd->strName.Buffer = NULL;
4017 if (buf != NULL)
4018 {
4019 DesktopHeapFree(Wnd->head.rpdesk, buf);
4020 }
4021
4022 Wnd->strName.Buffer = DesktopHeapAlloc(Wnd->head.rpdesk,
4023 UnicodeString.Length + sizeof(UNICODE_NULL));
4024 if (Wnd->strName.Buffer != NULL)
4025 {
4026 Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0';
4027 RtlCopyMemory(Wnd->strName.Buffer,
4028 UnicodeString.Buffer,
4029 UnicodeString.Length);
4030 Wnd->strName.MaximumLength = UnicodeString.Length + sizeof(UNICODE_NULL);
4031 Wnd->strName.Length = UnicodeString.Length;
4032 }
4033 else
4034 {
4035 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
4036 goto Exit;
4037 }
4038 }
4039 }
4040 else
4041 {
4042 Wnd->strName.Length = 0;
4043 if (Wnd->strName.Buffer != NULL)
4044 Wnd->strName.Buffer[0] = L'\0';
4045 }
4046
4047 // FIXME: HAX! Windows does not do this in here!
4048 // In User32, these are called after: NotifyWinEvent EVENT_OBJECT_NAMECHANGE than
4049 // RepaintButton, StaticRepaint, NtUserCallHwndLock HWNDLOCK_ROUTINE_REDRAWFRAMEANDHOOK, etc.
4050 /* Send shell notifications */
4051 if (!Wnd->spwndOwner && !IntGetParent(Wnd))
4052 {
4053 co_IntShellHookNotify(HSHELL_REDRAW, (WPARAM) UserHMGetHandle(Wnd), FALSE); // FIXME Flashing?
4054 }
4055
4056 Ret = TRUE;
4057 Exit:
4058 if (UnicodeString.Buffer) RtlFreeUnicodeString(&UnicodeString);
4059 return Ret;
4060 }
4061
4062 /*
4063 * NtUserDefSetText
4064 *
4065 * Undocumented function that is called from DefWindowProc to set
4066 * window text.
4067 *
4068 * Status
4069 * @implemented
4070 */
4071 BOOL APIENTRY
4072 NtUserDefSetText(HWND hWnd, PLARGE_STRING WindowText)
4073 {
4074 PWND Wnd;
4075 LARGE_STRING SafeText;
4076 UNICODE_STRING UnicodeString;
4077 BOOL Ret = TRUE;
4078
4079 TRACE("Enter NtUserDefSetText\n");
4080
4081 if (WindowText != NULL)
4082 {
4083 _SEH2_TRY
4084 {
4085 SafeText = ProbeForReadLargeString(WindowText);
4086 }
4087 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4088 {
4089 Ret = FALSE;
4090 SetLastNtError(_SEH2_GetExceptionCode());
4091 }
4092 _SEH2_END;
4093
4094 if (!Ret)
4095 return FALSE;
4096 }
4097 else
4098 return TRUE;
4099
4100 UserEnterExclusive();
4101
4102 if(!(Wnd = UserGetWindowObject(hWnd)))
4103 {
4104 UserLeave();
4105 return FALSE;
4106 }
4107
4108 // ReactOS uses Unicode and not mixed. Up/Down converting will take time.
4109 // Brought to you by: The Wine Project! Dysfunctional Thought Processes!
4110 // Now we know what the bAnsi is for.
4111 RtlInitUnicodeString(&UnicodeString, NULL);
4112 if (SafeText.Buffer)
4113 {
4114 _SEH2_TRY
4115 {
4116 if (SafeText.bAnsi)
4117 ProbeForRead(SafeText.Buffer, SafeText.Length, sizeof(CHAR));
4118 else
4119 ProbeForRead(SafeText.Buffer, SafeText.Length, sizeof(WCHAR));
4120 Ret = RtlLargeStringToUnicodeString(&UnicodeString, &SafeText);
4121 }
4122 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4123 {
4124 Ret = FALSE;
4125 SetLastNtError(_SEH2_GetExceptionCode());
4126 }
4127 _SEH2_END;
4128 if (!Ret) goto Exit;
4129 }
4130
4131 if (UnicodeString.Length != 0)
4132 {
4133 if (Wnd->strName.MaximumLength > 0 &&
4134 UnicodeString.Length <= Wnd->strName.MaximumLength - sizeof(UNICODE_NULL))
4135 {
4136 ASSERT(Wnd->strName.Buffer != NULL);
4137
4138 Wnd->strName.Length = UnicodeString.Length;
4139 Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0';
4140 RtlCopyMemory(Wnd->strName.Buffer,
4141 UnicodeString.Buffer,
4142 UnicodeString.Length);
4143 }
4144 else
4145 {
4146 PWCHAR buf;
4147 Wnd->strName.MaximumLength = Wnd->strName.Length = 0;
4148 buf = Wnd->strName.Buffer;
4149 Wnd->strName.Buffer = NULL;
4150 if (buf != NULL)
4151 {
4152 DesktopHeapFree(Wnd->head.rpdesk, buf);
4153 }
4154
4155 Wnd->strName.Buffer = DesktopHeapAlloc(Wnd->head.rpdesk,
4156 UnicodeString.Length + sizeof(UNICODE_NULL));
4157 if (Wnd->strName.Buffer != NULL)
4158 {
4159 Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0';
4160 RtlCopyMemory(Wnd->strName.Buffer,
4161 UnicodeString.Buffer,
4162 UnicodeString.Length);
4163 Wnd->strName.MaximumLength = UnicodeString.Length + sizeof(UNICODE_NULL);
4164 Wnd->strName.Length = UnicodeString.Length;
4165 }
4166 else
4167 {
4168 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
4169 Ret = FALSE;
4170 goto Exit;
4171 }
4172 }
4173 }
4174 else
4175 {
4176 Wnd->strName.Length = 0;
4177 if (Wnd->strName.Buffer != NULL)
4178 Wnd->strName.Buffer[0] = L'\0';
4179 }
4180
4181 // FIXME: HAX! Windows does not do this in here!
4182 // In User32, these are called after: NotifyWinEvent EVENT_OBJECT_NAMECHANGE than
4183 // RepaintButton, StaticRepaint, NtUserCallHwndLock HWNDLOCK_ROUTINE_REDRAWFRAMEANDHOOK, etc.
4184 /* Send shell notifications */
4185 if (!Wnd->spwndOwner && !IntGetParent(Wnd))
4186 {
4187 co_IntShellHookNotify(HSHELL_REDRAW, (WPARAM) hWnd, FALSE); // FIXME Flashing?
4188 }
4189
4190 Ret = TRUE;
4191 Exit:
4192 if (UnicodeString.Buffer) RtlFreeUnicodeString(&UnicodeString);
4193 TRACE("Leave NtUserDefSetText, ret=%i\n", Ret);
4194 UserLeave();
4195 return Ret;
4196 }
4197
4198 /*
4199 * NtUserInternalGetWindowText
4200 *
4201 * Status
4202 * @implemented
4203 */
4204
4205 INT APIENTRY
4206 NtUserInternalGetWindowText(HWND hWnd, LPWSTR lpString, INT nMaxCount)
4207 {
4208 PWND Wnd;
4209 NTSTATUS Status;
4210 INT Result;
4211 DECLARE_RETURN(INT);
4212
4213 TRACE("Enter NtUserInternalGetWindowText\n");
4214 UserEnterShared();
4215
4216 if(lpString && (nMaxCount <= 1))
4217 {
4218 EngSetLastError(ERROR_INVALID_PARAMETER);
4219 RETURN( 0);
4220 }
4221
4222 if(!(Wnd = UserGetWindowObject(hWnd)))
4223 {
4224 RETURN( 0);
4225 }
4226
4227 Result = Wnd->strName.Length / sizeof(WCHAR);
4228 if(lpString)
4229 {
4230 const WCHAR Terminator = L'\0';
4231 INT Copy;
4232 WCHAR *Buffer = (WCHAR*)lpString;
4233
4234 Copy = min(nMaxCount - 1, Result);
4235 if(Copy > 0)
4236 {
4237 Status = MmCopyToCaller(Buffer, Wnd->strName.Buffer, Copy * sizeof(WCHAR));
4238 if(!NT_SUCCESS(Status))
4239 {
4240 SetLastNtError(Status);
4241 RETURN( 0);
4242 }
4243 Buffer += Copy;
4244 }
4245
4246 Status = MmCopyToCaller(Buffer, &Terminator, sizeof(WCHAR));
4247 if(!NT_SUCCESS(Status))
4248 {
4249 SetLastNtError(Status);
4250 RETURN( 0);
4251 }
4252
4253 Result = Copy;
4254 }
4255
4256 RETURN( Result);
4257
4258 CLEANUP:
4259 TRACE("Leave NtUserInternalGetWindowText, ret=%i\n",_ret_);
4260 UserLeave();
4261 END_CLEANUP;
4262 }
4263
4264 /*
4265 API Call
4266 */
4267 BOOL
4268 FASTCALL
4269 IntShowOwnedPopups(PWND OwnerWnd, BOOL fShow )
4270 {
4271 int count = 0;
4272 PWND pWnd;
4273 HWND *win_array;
4274
4275 // ASSERT(OwnerWnd);
4276
4277 TRACE("Enter ShowOwnedPopups Show: %s\n", (fShow ? "TRUE" : "FALSE"));
4278 win_array = IntWinListChildren(OwnerWnd);
4279
4280 if (!win_array)
4281 return TRUE;
4282
4283 while (win_array[count])
4284 count++;
4285 while (--count >= 0)
4286 {
4287 if (!(pWnd = ValidateHwndNoErr( win_array[count] )))
4288 continue;
4289 if (pWnd->spwndOwner != OwnerWnd)
4290 continue;
4291
4292 if (fShow)
4293 {
4294 if (pWnd->state & WNDS_HIDDENPOPUP)
4295 {
4296 /* In Windows, ShowOwnedPopups(TRUE) generates
4297 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
4298 * regardless of the state of the owner
4299 */
4300 co_IntSendMessage(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
4301 continue;
4302 }
4303 }
4304 else
4305 {
4306 if (pWnd->style & WS_VISIBLE)
4307 {
4308 /* In Windows, ShowOwnedPopups(FALSE) generates
4309 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
4310 * regardless of the state of the owner
4311 */
4312 co_IntSendMessage(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
4313 continue;
4314 }
4315 }
4316
4317 }
4318 ExFreePoolWithTag(win_array, USERTAG_WINDOWLIST);
4319 TRACE("Leave ShowOwnedPopups\n");
4320 return TRUE;
4321 }
4322
4323 /* EOF */