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