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