update for HEAD-2003091401
[reactos.git] / subsys / win32k / ntuser / window.c
1 /*
2  *  ReactOS W32 Subsystem
3  *  Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19 /* $Id$
20  *
21  * COPYRIGHT:        See COPYING in the top level directory
22  * PROJECT:          ReactOS kernel
23  * PURPOSE:          Windows
24  * FILE:             subsys/win32k/ntuser/window.c
25  * PROGRAMER:        Casper S. Hornstrup (chorns@users.sourceforge.net)
26  * REVISION HISTORY:
27  *       06-06-2001  CSH  Created
28  */
29 /* INCLUDES ******************************************************************/
30
31 #include <ddk/ntddk.h>
32 #include <internal/safe.h>
33 #include <win32k/win32k.h>
34 #include <include/object.h>
35 #include <include/guicheck.h>
36 #include <include/window.h>
37 #include <include/class.h>
38 #include <include/error.h>
39 #include <include/winsta.h>
40 #include <include/winpos.h>
41 #include <include/callback.h>
42 #include <include/msgqueue.h>
43 #include <include/rect.h>
44 #include <include/dce.h>
45 #include <include/paint.h>
46 #include <include/painting.h>
47 #include <include/scroll.h>
48 #include <include/vis.h>
49 #include <include/menu.h>
50
51 #define NDEBUG
52 #include <win32k/debug1.h>
53 #include <debug.h>
54
55 #define TAG_WNAM  TAG('W', 'N', 'A', 'M')
56
57 typedef struct _REGISTERED_MESSAGE
58 {
59   LIST_ENTRY ListEntry;
60   WCHAR MessageName[1];
61 } REGISTERED_MESSAGE, *PREGISTERED_MESSAGE;
62
63 static LIST_ENTRY RegisteredMessageListHead;
64
65 #define REGISTERED_MESSAGE_MIN 0xc000
66 #define REGISTERED_MESSAGE_MAX 0xffff
67
68
69  /* globally stored handles to the shell windows */
70 HWND hwndShellWindow = 0;
71 HWND hwndShellListView = 0;
72 DWORD pidShellWindow = 0;
73
74
75 NTSTATUS FASTCALL
76 InitWindowImpl(VOID)
77 {
78   InitializeListHead(&RegisteredMessageListHead);
79
80   return(STATUS_SUCCESS);
81 }
82
83 NTSTATUS FASTCALL
84 CleanupWindowImpl(VOID)
85 {
86   return(STATUS_SUCCESS);
87 }
88
89
90 /* HELPER FUNCTIONS ***********************************************************/
91
92 /* check if hwnd is a broadcast magic handle */
93 inline BOOL IntIsBroadcastHwnd( HWND hwnd )
94 {
95     return (hwnd == HWND_BROADCAST || hwnd == HWND_TOPMOST);
96 }
97
98
99 inline BOOL IntIsDesktopWindow(PWINDOW_OBJECT Wnd)
100 {
101   return Wnd->Parent == NULL;
102 }
103
104
105 static BOOL BuildChildWindowArray(PWINDOW_OBJECT Window, HWND **Children, unsigned *NumChildren)
106 {
107   unsigned Index;
108   PWINDOW_OBJECT Child;
109
110   *Children = NULL;
111   *NumChildren = 0;
112
113   ExAcquireFastMutexUnsafe(&Window->ChildrenListLock);
114   Child = Window->FirstChild;
115   while (Child)
116   {
117     (*NumChildren)++;
118     Child = Child->NextSibling;
119   }
120   
121   if (0 != *NumChildren)
122   {
123     *Children = ExAllocatePoolWithTag(PagedPool, *NumChildren * sizeof(HWND), TAG_WNAM);
124     if (NULL != *Children)
125     {
126       Child = Window->FirstChild;
127       Index = 0;
128       while (Child)
129       {
130         (*Children)[Index] = Child->Self;
131         Child = Child->NextSibling;
132         Index++;
133       }
134       assert(Index == *NumChildren);
135     }
136     else
137     {
138       DPRINT1("Failed to allocate memory for children array\n");
139     }
140   }
141   ExReleaseFastMutexUnsafe(&Window->ChildrenListLock);
142
143
144   return 0 == *NumChildren || NULL != *Children;
145 }
146
147
148 /***********************************************************************
149  *           IntDestroyWindow
150  *
151  * Destroy storage associated to a window. "Internals" p.358
152  */
153 static LRESULT IntDestroyWindow(PWINDOW_OBJECT Window,
154                                  PW32PROCESS ProcessData,
155                                  PW32THREAD ThreadData,
156                                  BOOLEAN SendMessages)
157 {
158   HWND *Children;
159   unsigned NumChildren;
160   unsigned Index;
161   PWINDOW_OBJECT Child;
162
163   if (! IntWndBelongsToThread(Window, ThreadData))
164     {
165       DPRINT1("Window doesn't belong to current thread\n");
166       return 0;
167     }
168
169   /* free child windows */
170   if (! BuildChildWindowArray(Window, &Children, &NumChildren))
171     {
172       return 0;
173     }
174   for (Index = NumChildren; 0 < Index; Index--)
175     {
176       Child = IntGetWindowObject(Children[Index - 1]);
177       if (NULL != Child)
178         {
179           if (IntWndBelongsToThread(Child, ThreadData))
180             {
181               IntDestroyWindow(Child, ProcessData, ThreadData, SendMessages);
182             }
183 #if 0 /* FIXME */
184           else
185             {
186               SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
187             }
188 #endif
189         }
190     }
191   if (0 != NumChildren)
192     {
193       ExFreePool(Children);
194     }
195
196   if (SendMessages)
197     {
198       /*
199        * Clear the update region to make sure no WM_PAINT messages will be
200        * generated for this window while processing the WM_NCDESTROY.
201        */
202       PaintRedrawWindow(Window, NULL, 0,
203                         RDW_VALIDATE | RDW_NOFRAME | RDW_NOERASE | RDW_NOINTERNALPAINT | RDW_NOCHILDREN,
204                         0);
205
206       /*
207        * Send the WM_NCDESTROY to the window being destroyed.
208        */
209       NtUserSendMessage(Window->Self, WM_NCDESTROY, 0, 0);
210     }
211
212   /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
213
214 #if 0 /* FIXME */
215   WinPosCheckInternalPos(Window->Self);
216   if (Window->Self == GetCapture())
217     {
218       ReleaseCapture();
219     }
220
221   /* free resources associated with the window */
222   TIMER_RemoveWindowTimers(Window->Self);
223 #endif
224
225 #if 0 /* FIXME */
226   if (0 == (Window->Style & WS_CHILD))
227     {
228       HMENU Menu = (HMENU) NtUserSetWindowLongW(Window->Self, GWL_ID, 0);
229       if (NULL != Menu)
230         {
231           DestroyMenu(Menu);
232         }
233     }
234   if (Window->hSysMenu)
235     {
236       DestroyMenu(Window->hSysMenu);
237       Window->hSysMenu = 0;
238     }
239   DCE_FreeWindowDCE(Window->Self);    /* Always do this to catch orphaned DCs */
240   WINPROC_FreeProc(Window->winproc, WIN_PROC_WINDOW);
241   CLASS_RemoveWindow(Window->Class);
242 #endif
243
244   ExAcquireFastMutexUnsafe(&Window->Parent->ChildrenListLock);
245   IntUnlinkWindow(Window);
246   ExReleaseFastMutexUnsafe(&Window->Parent->ChildrenListLock);
247
248   ExAcquireFastMutexUnsafe (&ThreadData->WindowListLock);
249   RemoveEntryList(&Window->ThreadListEntry);
250   ExReleaseFastMutexUnsafe (&ThreadData->WindowListLock);
251   
252   IntDestroyScrollBar(Window, SB_VERT);
253   IntDestroyScrollBar(Window, SB_HORZ);
254
255   Window->Class = NULL;
256   ObmCloseHandle(ProcessData->WindowStation->HandleTable, Window->Self);
257
258   IntGraphicsCheck(FALSE);
259
260   return 0;
261 }
262
263
264 /* INTERNAL ******************************************************************/
265
266
267 VOID FASTCALL
268 DestroyThreadWindows(struct _ETHREAD *Thread)
269 {
270   PLIST_ENTRY LastHead;
271   PW32PROCESS Win32Process;
272   PW32THREAD Win32Thread;
273   PWINDOW_OBJECT Window;
274
275   Win32Thread = Thread->Win32Thread;
276   Win32Process = Thread->ThreadsProcess->Win32Process;
277   ExAcquireFastMutexUnsafe(&Win32Thread->WindowListLock);
278   LastHead = NULL;
279   while (Win32Thread->WindowListHead.Flink != &(Win32Thread->WindowListHead) &&
280          Win32Thread->WindowListHead.Flink != LastHead)
281     {
282       LastHead = Win32Thread->WindowListHead.Flink;
283       Window = CONTAINING_RECORD(Win32Thread->WindowListHead.Flink, WINDOW_OBJECT, ThreadListEntry);
284       ExReleaseFastMutexUnsafe(&Win32Thread->WindowListLock);
285       IntDestroyWindow(Window, Win32Process, Win32Thread, FALSE);
286       ExAcquireFastMutexUnsafe(&Win32Thread->WindowListLock);
287     }
288   if (Win32Thread->WindowListHead.Flink == LastHead)
289     {
290       /* Window at head of list was not removed, should never happen, infinite loop */
291       KEBUGCHECK(0);
292     }
293   ExReleaseFastMutexUnsafe(&Win32Thread->WindowListLock);
294 }
295
296
297 HWND STDCALL
298 IntCreateDesktopWindow(PWINSTATION_OBJECT WindowStation,
299                         PWNDCLASS_OBJECT DesktopClass,
300                         ULONG Width, ULONG Height)
301 {
302   PWSTR WindowName;
303   HWND Handle;
304   PWINDOW_OBJECT WindowObject;
305
306   /* Create the window object. */
307   WindowObject = (PWINDOW_OBJECT)ObmCreateObject(WindowStation->HandleTable, 
308                                                  &Handle, 
309                                                  otWindow,
310                                                  sizeof(WINDOW_OBJECT));
311   if (!WindowObject) 
312     {
313       return((HWND)0);
314     }
315
316   /*
317    * Fill out the structure describing it.
318    */
319   WindowObject->Class = DesktopClass;
320   WindowObject->ExStyle = 0;
321   WindowObject->Style = WS_VISIBLE;
322   WindowObject->x = 0;
323   WindowObject->y = 0;
324   WindowObject->Width = Width;
325   WindowObject->Height = Height;
326   WindowObject->ParentHandle = NULL;
327   WindowObject->Parent = NULL;
328   WindowObject->IDMenu = 0;
329   WindowObject->Instance = NULL;
330   WindowObject->Parameters = NULL;
331   WindowObject->Self = Handle;
332   WindowObject->MessageQueue = NULL;
333   WindowObject->ExtraData = NULL;
334   WindowObject->ExtraDataSize = 0;
335   WindowObject->WindowRect.left = 0;
336   WindowObject->WindowRect.top = 0;
337   WindowObject->WindowRect.right = Width;
338   WindowObject->WindowRect.bottom = Height;
339   WindowObject->ClientRect = WindowObject->WindowRect;
340   WindowObject->UserData = 0;
341   /*FIXME: figure out what the correct strange value is and what to do with it (and how to set the wndproc values correctly) */
342   WindowObject->WndProcA = DesktopClass->lpfnWndProcA;
343   WindowObject->WndProcW = DesktopClass->lpfnWndProcW;
344   WindowObject->OwnerThread = PsGetCurrentThread();
345   WindowObject->FirstChild = NULL;
346   WindowObject->LastChild = NULL;
347   WindowObject->PrevSibling = NULL;
348   WindowObject->NextSibling = NULL;
349
350   ExInitializeFastMutex(&WindowObject->ChildrenListLock);
351
352   WindowName = ExAllocatePool(NonPagedPool, sizeof(L"DESKTOP"));
353   wcscpy(WindowName, L"DESKTOP");
354   RtlInitUnicodeString(&WindowObject->WindowName, WindowName);
355
356   return(Handle);
357 }
358
359
360 HWND FASTCALL
361 IntGetActiveWindow(VOID)
362 {
363   PUSER_MESSAGE_QUEUE Queue;
364   Queue = (PUSER_MESSAGE_QUEUE)IntGetActiveDesktop()->ActiveMessageQueue;
365   if (Queue == NULL)
366     {
367       return(NULL);
368     }
369   else
370     {
371       return(Queue->ActiveWindow);
372     }
373 }
374
375
376 PWINDOW_OBJECT FASTCALL
377 IntGetAncestor(PWINDOW_OBJECT Wnd, UINT Type)
378 {
379   if (IntIsDesktopWindow(Wnd)) return NULL;
380
381   switch (Type)
382   {
383     case GA_PARENT:
384       return Wnd->Parent;
385
386     case GA_ROOT:
387       while(!IntIsDesktopWindow(Wnd->Parent))
388       {
389         Wnd = Wnd->Parent;
390       }
391       return Wnd;
392     
393     case GA_ROOTOWNER:
394       while ((Wnd = IntGetParent(Wnd)));
395       return Wnd;
396   }
397
398   return NULL;
399 }
400
401
402 /*!
403  * Internal function.
404  * Returns client window rectangle relative to the upper-left corner of client area.
405  *
406  * \note Does not check the validity of the parameters
407 */
408 VOID FASTCALL
409 IntGetClientRect(PWINDOW_OBJECT WindowObject, PRECT Rect)
410 {
411   ASSERT( WindowObject );
412   ASSERT( Rect );
413
414   Rect->left = Rect->top = 0;
415   Rect->right = WindowObject->ClientRect.right - WindowObject->ClientRect.left;
416   Rect->bottom = 
417     WindowObject->ClientRect.bottom - WindowObject->ClientRect.top;
418 }
419
420
421 HWND FASTCALL IntGetDesktopWindow(VOID)
422 {
423   return IntGetActiveDesktop()->DesktopWindow;
424 }
425
426
427 HWND FASTCALL
428 IntGetFocusWindow(VOID)
429 {
430   PUSER_MESSAGE_QUEUE Queue;
431   PDESKTOP_OBJECT pdo = IntGetActiveDesktop();
432
433   if( !pdo )
434         return NULL;
435
436   Queue = (PUSER_MESSAGE_QUEUE)pdo->ActiveMessageQueue;
437
438   if (Queue == NULL)
439       return(NULL);
440   else
441       return(Queue->FocusWindow);
442 }
443
444
445 PWINDOW_OBJECT FASTCALL
446 IntGetParent(PWINDOW_OBJECT Wnd)
447 {
448   if (Wnd->Style & WS_POPUP)
449   {
450     return IntGetWindowObject(Wnd->ParentHandle); /* wine use HWND for owner window (unknown reason) */
451   }
452   else if (Wnd->Style & WS_CHILD) 
453   {
454     return Wnd->Parent;
455   }
456
457   return NULL;
458 }
459
460
461 HMENU FASTCALL
462 IntGetSystemMenu(PWINDOW_OBJECT WindowObject, BOOL bRevert, BOOL RetMenu)
463 {
464   PMENU_OBJECT MenuObject, NewMenuObject;
465   PW32PROCESS W32Process;
466   HMENU NewMenu, ret = (HMENU)0;
467
468   if(bRevert)
469   {
470     W32Process = PsGetWin32Process();
471     
472     if(!W32Process->WindowStation)
473       return (HMENU)0;
474       
475     if(WindowObject->SystemMenu)
476     {
477       MenuObject = IntGetMenuObject(WindowObject->SystemMenu);
478       if(MenuObject)
479       {
480         IntDestroyMenuObject(MenuObject, FALSE, TRUE);
481       }
482     }
483       
484     if(W32Process->WindowStation->SystemMenuTemplate)
485     {
486       /* clone system menu */
487       MenuObject = IntGetMenuObject(W32Process->WindowStation->SystemMenuTemplate);
488       if(!MenuObject)
489         return (HMENU)0;
490
491       NewMenuObject = IntCloneMenu(MenuObject);
492       if(NewMenuObject)
493       {
494         WindowObject->SystemMenu = NewMenuObject->Self;
495         NewMenuObject->IsSystemMenu = TRUE;
496         ret = NewMenuObject->Self;
497         IntReleaseMenuObject(NewMenuObject);
498       }
499       IntReleaseMenuObject(MenuObject);
500     }
501     else
502     {
503       NewMenu = IntLoadSysMenuTemplate();
504       if(!NewMenu)
505         return (HMENU)0;
506       MenuObject = IntGetMenuObject(NewMenu);
507       if(!MenuObject)
508         return (HMENU)0;
509       
510       NewMenuObject = IntCloneMenu(MenuObject);
511       if(NewMenuObject)
512       {
513         WindowObject->SystemMenu = NewMenuObject->Self;
514         NewMenuObject->IsSystemMenu = TRUE;
515         ret = NewMenuObject->Self;
516         IntReleaseMenuObject(NewMenuObject);
517       }
518       IntDestroyMenuObject(MenuObject, FALSE, TRUE);
519     }
520     if(RetMenu)
521       return ret;
522     else
523       return (HMENU)0;
524   }
525   else
526   {
527     return WindowObject->SystemMenu;
528   }
529 }
530
531
532 PWINDOW_OBJECT FASTCALL
533 IntGetWindowObject(HWND hWnd)
534 {
535   PWINDOW_OBJECT WindowObject;
536   NTSTATUS Status;
537   Status = 
538     ObmReferenceObjectByHandle(PsGetWin32Process()->WindowStation->
539                                HandleTable,
540                                hWnd,
541                                otWindow,
542                                (PVOID*)&WindowObject);
543   if (!NT_SUCCESS(Status))
544     {
545       return(NULL);
546     }
547   return(WindowObject);
548 }
549
550
551 DWORD FASTCALL
552 IntGetWindowThreadProcessId(PWINDOW_OBJECT Wnd, PDWORD pid)
553 {
554    if (pid) *pid = (DWORD) Wnd->OwnerThread->ThreadsProcess->UniqueProcessId;
555    return (DWORD) Wnd->OwnerThread->Cid.UniqueThread;
556 }
557
558
559 VOID FASTCALL
560 IntInitDesktopWindow(ULONG Width, ULONG Height)
561 {
562   PWINDOW_OBJECT DesktopWindow;
563   HRGN DesktopRgn;
564   
565   DesktopWindow = IntGetWindowObject(PsGetWin32Thread()->Desktop->DesktopWindow);
566   if (NULL == DesktopWindow)
567     {
568       return;
569     }
570   DesktopWindow->WindowRect.right = Width;
571   DesktopWindow->WindowRect.bottom = Height;
572   DesktopWindow->ClientRect = DesktopWindow->WindowRect;
573
574   DesktopRgn = UnsafeIntCreateRectRgnIndirect(&(DesktopWindow->WindowRect));
575   VIS_WindowLayoutChanged(PsGetWin32Thread()->Desktop, DesktopWindow, DesktopRgn);
576   NtGdiDeleteObject(DesktopRgn);
577   IntReleaseWindowObject(DesktopWindow);
578 }
579
580
581 BOOL FASTCALL
582 IntIsChildWindow(HWND Parent, HWND Child)
583 {
584   PWINDOW_OBJECT BaseWindow = IntGetWindowObject(Child);
585   PWINDOW_OBJECT Window = BaseWindow;
586   while (Window != NULL && Window->Style & WS_CHILD)
587     {
588       if (Window->Self == Parent)
589         {
590           IntReleaseWindowObject(BaseWindow);
591           return(TRUE);
592         }
593       Window = Window->Parent;
594     }
595   IntReleaseWindowObject(BaseWindow);
596   return(FALSE);  
597 }
598
599
600 BOOL FASTCALL
601 IntIsWindowVisible(HWND Wnd)
602 {
603   PWINDOW_OBJECT BaseWindow = IntGetWindowObject(Wnd);
604   PWINDOW_OBJECT Window = BaseWindow;
605   BOOLEAN Result = FALSE;
606   while (Window != NULL && Window->Style & WS_CHILD)
607     {
608       if (!(Window->Style & WS_VISIBLE))
609         {
610           IntReleaseWindowObject(BaseWindow);
611           return(FALSE);
612         }
613       Window = Window->Parent;
614     }
615   if (Window != NULL && Window->Style & WS_VISIBLE)
616     {
617       Result = TRUE;
618     }
619   IntReleaseWindowObject(BaseWindow);
620   return(Result);
621 }
622
623
624 /* link the window into siblings and parent. children are kept in place. */
625 VOID FASTCALL
626 IntLinkWindow(
627   PWINDOW_OBJECT Wnd, 
628   PWINDOW_OBJECT WndParent,
629   PWINDOW_OBJECT WndPrevSibling /* set to NULL if top sibling */
630   )
631 {
632   Wnd->Parent = WndParent; 
633
634   if ((Wnd->PrevSibling = WndPrevSibling))
635   {
636     /* link after WndPrevSibling */
637     if ((Wnd->NextSibling = WndPrevSibling->NextSibling)) Wnd->NextSibling->PrevSibling = Wnd;
638     else if (Wnd->Parent->LastChild == WndPrevSibling) Wnd->Parent->LastChild = Wnd;
639     Wnd->PrevSibling->NextSibling = Wnd;
640   }
641   else
642   {
643     /* link at top */
644     if ((Wnd->NextSibling = WndParent->FirstChild)) Wnd->NextSibling->PrevSibling = Wnd;
645     else Wnd->Parent->LastChild = Wnd;
646     WndParent->FirstChild = Wnd;
647   }
648
649 }
650
651
652 HWND FASTCALL
653 IntSetFocusWindow(HWND hWnd)
654 {
655   PUSER_MESSAGE_QUEUE OldMessageQueue;
656   PDESKTOP_OBJECT DesktopObject;
657   PWINDOW_OBJECT WindowObject;
658   HWND hWndOldFocus;
659
660   DPRINT("IntSetFocusWindow(hWnd 0x%x)\n", hWnd);
661
662   if (hWnd != (HWND)0)
663     {
664       WindowObject = IntGetWindowObject(hWnd);
665       if (!WindowObject)
666         {
667           DPRINT("Bad window handle 0x%x\n", hWnd);
668           SetLastWin32Error(ERROR_INVALID_HANDLE);
669           return (HWND)0;
670         }
671     }
672   else
673   {
674     WindowObject = NULL;
675   }
676
677   DesktopObject = IntGetActiveDesktop();
678   if (!DesktopObject)
679     {
680       DPRINT("No active desktop\n");
681       if (WindowObject != NULL)
682         {
683             IntReleaseWindowObject(WindowObject);
684         }
685       SetLastWin32Error(ERROR_INVALID_HANDLE);
686           return (HWND)0;
687     }
688
689   hWndOldFocus = (HWND)0;
690   OldMessageQueue = (PUSER_MESSAGE_QUEUE)DesktopObject->ActiveMessageQueue;
691   if (OldMessageQueue != NULL)
692     {
693       hWndOldFocus = OldMessageQueue->FocusWindow;
694     }
695
696   if (WindowObject != NULL)
697     {
698       WindowObject->MessageQueue->FocusWindow = hWnd;
699       (PUSER_MESSAGE_QUEUE)DesktopObject->ActiveMessageQueue =
700         WindowObject->MessageQueue;
701       IntReleaseWindowObject(WindowObject);
702     }
703   else
704     {
705       (PUSER_MESSAGE_QUEUE)DesktopObject->ActiveMessageQueue = NULL;
706     }
707
708   DPRINT("hWndOldFocus = 0x%x\n", hWndOldFocus);
709
710   return hWndOldFocus;
711 }
712
713
714 PWINDOW_OBJECT FASTCALL
715 IntSetParent(PWINDOW_OBJECT Wnd, PWINDOW_OBJECT WndNewParent)
716 {
717   PWINDOW_OBJECT WndOldParent;
718   BOOL was_visible;
719   HWND hWnd, hWndNewParent, hWndOldParent;
720
721   if (!WndNewParent) WndNewParent = IntGetWindowObject(IntGetDesktopWindow());
722
723   hWnd = Wnd;
724   hWndNewParent = WndNewParent;
725
726 #if 0
727   if (!(full_handle = WIN_IsCurrentThread( hwnd )))
728     return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
729
730   if (USER_Driver.pSetParent)
731     return USER_Driver.pSetParent( hwnd, parent );
732 #endif
733
734   /* Windows hides the window first, then shows it again
735    * including the WM_SHOWWINDOW messages and all */
736   was_visible = WinPosShowWindow( hWnd, SW_HIDE );
737
738   /* validate that window and parent still exist */
739   if (!IntGetWindowObject(hWnd) || !IntGetWindowObject(hWndNewParent)) return NULL;
740
741   /* window must belong to current process */
742   if (Wnd->OwnerThread->ThreadsProcess != PsGetCurrentProcess()) return NULL;
743
744   WndOldParent = Wnd->Parent;
745   hWndOldParent =  WndOldParent->Self;
746
747   if (WndNewParent != WndOldParent)
748   {
749     IntUnlinkWindow(Wnd);
750     IntLinkWindow(Wnd, WndNewParent, NULL /*prev sibling*/);
751
752     if (WndNewParent->Self != IntGetDesktopWindow()) /* a child window */
753     {
754       if (!(Wnd->Style & WS_CHILD))
755       {
756         //if ( Wnd->Menu ) DestroyMenu ( Wnd->menu );
757         Wnd->IDMenu = 0;
758       }
759     }
760   }
761
762   /* SetParent additionally needs to make hwnd the topmost window
763        in the x-order and send the expected WM_WINDOWPOSCHANGING and
764        WM_WINDOWPOSCHANGED notification messages.
765    */
766   WinPosSetWindowPos( hWnd, HWND_TOPMOST, 0, 0, 0, 0,
767                   SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | (was_visible ? SWP_SHOWWINDOW : 0) );
768   /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
769    * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
770   
771   /* validate that the old parent still exist, since it migth have been destroyed
772      during the last callbacks to user-mode 
773    */
774   return (IntGetWindowObject(hWndOldParent) ? WndOldParent : NULL);
775 }
776
777
778 VOID FASTCALL
779 IntReleaseWindowObject(PWINDOW_OBJECT Window)
780 {
781   ObmDereferenceObject(Window);
782 }
783
784
785 /***********************************************************************
786  *           IntSendDestroyMsg
787  */
788 static void IntSendDestroyMsg(HWND Wnd)
789 {
790 #if 0 /* FIXME */
791   GUITHREADINFO info;
792
793   if (GetGUIThreadInfo(GetCurrentThreadId(), &info))
794     {
795       if (Wnd == info.hwndCaret)
796         {
797           DestroyCaret();
798         }
799     }
800 #endif
801
802   /*
803    * Send the WM_DESTROY to the window.
804    */
805   NtUserSendMessage(Wnd, WM_DESTROY, 0, 0);
806
807   /*
808    * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
809    * make sure that the window still exists when we come back.
810    */
811 #if 0 /* FIXME */
812   if (IsWindow(Wnd))
813     {
814       HWND* pWndArray;
815       int i;
816
817       if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
818
819       /* start from the end (FIXME: is this needed?) */
820       for (i = 0; pWndArray[i]; i++) ;
821
822       while (--i >= 0)
823         {
824           if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
825         }
826       HeapFree(GetProcessHeap(), 0, pWndArray);
827     }
828   else
829     {
830       DPRINT("destroyed itself while in WM_DESTROY!\n");
831     }
832 #endif
833 }
834
835
836 BOOL FASTCALL
837 IntSetSystemMenu(PWINDOW_OBJECT WindowObject, PMENU_OBJECT MenuObject)
838 {
839   PMENU_OBJECT OldMenuObject;
840   if(WindowObject->SystemMenu)
841   {
842     OldMenuObject = IntGetMenuObject(WindowObject->SystemMenu);
843     if(OldMenuObject)
844     {
845       OldMenuObject->IsSystemMenu = FALSE;
846       IntReleaseMenuObject(OldMenuObject);
847     }
848   }
849   
850   WindowObject->SystemMenu = MenuObject->Self;
851   if(MenuObject) /* FIXME check window style, propably return FALSE ? */
852     MenuObject->IsSystemMenu = TRUE;
853   
854   return TRUE;
855 }
856
857
858 /* unlink the window from siblings and parent. children are kept in place. */
859 VOID FASTCALL
860 IntUnlinkWindow(PWINDOW_OBJECT Wnd)
861 {
862   PWINDOW_OBJECT WndParent = Wnd->Parent; 
863  
864   if (Wnd->NextSibling) Wnd->NextSibling->PrevSibling = Wnd->PrevSibling;
865   else if (WndParent->LastChild == Wnd) WndParent->LastChild = Wnd->PrevSibling;
866  
867   if (Wnd->PrevSibling) Wnd->PrevSibling->NextSibling = Wnd->NextSibling;
868   else if (WndParent->FirstChild == Wnd) WndParent->FirstChild = Wnd->NextSibling;
869   //else if (parent->first_unlinked == win) parent->first_unlinked = Wnd->NextSibling;
870 }
871
872
873 BOOLEAN FASTCALL
874 IntWndBelongsToThread(PWINDOW_OBJECT Window, PW32THREAD ThreadData)
875 {
876   if (Window->OwnerThread && Window->OwnerThread->Win32Thread)
877   {
878     return (Window->OwnerThread->Win32Thread == ThreadData);
879   }
880
881   return FALSE;
882 }
883
884
885 /* FUNCTIONS *****************************************************************/
886
887
888 /*
889  * @unimplemented
890  */
891 DWORD STDCALL
892 NtUserAlterWindowStyle(DWORD Unknown0,
893                        DWORD Unknown1,
894                        DWORD Unknown2)
895 {
896   UNIMPLEMENTED
897
898   return(0);
899 }
900
901
902 /*
903  * As best as I can figure, this function is used by EnumWindows,
904  * EnumChildWindows, EnumDesktopWindows, & EnumThreadWindows.
905  *
906  * It's supposed to build a list of HWNDs to return to the caller.
907  * We can figure out what kind of list by what parameters are
908  * passed to us.
909  */
910 /*
911  * @implemented
912  */
913 ULONG
914 STDCALL
915 NtUserBuildHwndList(
916   HDESK hDesktop,
917   HWND hwndParent,
918   BOOLEAN bChildren,
919   ULONG dwThreadId,
920   ULONG lParam,
921   HWND* pWnd,
922   ULONG nBufSize)
923 {
924   ULONG dwCount = 0;
925
926   /* FIXME handle bChildren */
927   if ( hwndParent )
928     {
929       PWINDOW_OBJECT WindowObject = NULL;
930       PWINDOW_OBJECT Child;
931
932       WindowObject = IntGetWindowObject ( hwndParent );
933       if ( !WindowObject )
934         {
935           DPRINT("Bad window handle 0x%x\n", hwndParent);
936           SetLastWin32Error(ERROR_INVALID_HANDLE);
937           return 0;
938         }
939
940       ExAcquireFastMutex ( &WindowObject->ChildrenListLock );
941       Child = WindowObject->FirstChild;
942       while (Child)
943         {
944           if ( pWnd && dwCount < nBufSize )
945             pWnd[dwCount] = Child->Self;
946           dwCount++;
947     Child = Child->NextSibling;
948         }
949       ExReleaseFastMutex ( &WindowObject->ChildrenListLock );
950       IntReleaseWindowObject ( WindowObject );
951     }
952   else if ( dwThreadId )
953     {
954       NTSTATUS Status;
955       struct _ETHREAD* Thread;
956       struct _EPROCESS* ThreadsProcess;
957       struct _W32PROCESS*   Win32Process;
958       struct _WINSTATION_OBJECT* WindowStation;
959       PUSER_HANDLE_TABLE HandleTable;
960       PLIST_ENTRY Current;
961       PUSER_HANDLE_BLOCK Block = NULL;
962       ULONG i;
963
964       Status = PsLookupThreadByThreadId ( (PVOID)dwThreadId, &Thread );
965       if ( !NT_SUCCESS(Status) || !Thread )
966         {
967           DPRINT("Bad ThreadId 0x%x\n", dwThreadId );
968           SetLastWin32Error(ERROR_INVALID_HANDLE);
969           return 0;
970         }
971       ThreadsProcess = Thread->ThreadsProcess;
972       ASSERT(ThreadsProcess);
973       Win32Process = ThreadsProcess->Win32Process;
974       ASSERT(Win32Process);
975       WindowStation = Win32Process->WindowStation;
976       ASSERT(WindowStation);
977       HandleTable = (PUSER_HANDLE_TABLE)(WindowStation->HandleTable);
978       ASSERT(HandleTable);
979
980       ExAcquireFastMutex(&HandleTable->ListLock);
981
982       Current = HandleTable->ListHead.Flink;
983       while ( Current != &HandleTable->ListHead )
984         {
985           Block = CONTAINING_RECORD(Current, USER_HANDLE_BLOCK, ListEntry);
986           for ( i = 0; i < HANDLE_BLOCK_ENTRIES; i++ )
987             {
988               PVOID ObjectBody = Block->Handles[i].ObjectBody;
989               if ( ObjectBody )
990               {
991                 if ( pWnd && dwCount < nBufSize )
992                   {
993                     pWnd[dwCount] =
994                       (HWND)ObmReferenceObjectByPointer ( ObjectBody, otWindow );
995                   }
996                 dwCount++;
997               }
998             }
999           Current = Current->Flink;
1000         }
1001
1002       ExReleaseFastMutex(&HandleTable->ListLock);
1003     }
1004   else
1005     {
1006       PDESKTOP_OBJECT DesktopObject = NULL;
1007       KIRQL OldIrql;
1008       PWINDOW_OBJECT Child, WndDesktop;
1009
1010       if ( hDesktop )
1011         DesktopObject = IntGetDesktopObject ( hDesktop );
1012       else
1013         DesktopObject = IntGetActiveDesktop();
1014       if (!DesktopObject)
1015         {
1016           DPRINT("Bad desktop handle 0x%x\n", hDesktop );
1017           SetLastWin32Error(ERROR_INVALID_HANDLE);
1018           return 0;
1019         }
1020
1021       KeAcquireSpinLock ( &DesktopObject->Lock, &OldIrql );
1022
1023       WndDesktop = IntGetWindowObject(DesktopObject->DesktopWindow);
1024       Child = (WndDesktop ? WndDesktop->FirstChild : NULL);
1025       while (Child)
1026         {
1027           if ( pWnd && dwCount < nBufSize )
1028             pWnd[dwCount] = Child->Self;
1029           dwCount++;
1030     Child = Child->NextSibling;
1031         }
1032       KeReleaseSpinLock ( &DesktopObject->Lock, OldIrql );
1033     }
1034
1035   return dwCount;
1036 }
1037
1038
1039 /*
1040  * @unimplemented
1041  */
1042 BOOL
1043 STDCALL
1044 NtUserCallHwndLock(
1045   HWND hWnd,
1046   DWORD Unknown1)
1047 {
1048   UNIMPLEMENTED
1049   /* DrawMenuBar() calls it with Unknown1==0x55 */
1050   return 0;
1051 }
1052
1053
1054 /*
1055  * @unimplemented
1056  */
1057 DWORD STDCALL
1058 NtUserChildWindowFromPointEx(HWND Parent,
1059                              LONG x,
1060                              LONG y,
1061                              UINT Flags)
1062 {
1063   UNIMPLEMENTED
1064
1065   return(0);
1066 }
1067
1068
1069 /*
1070  * @implemented
1071  */
1072 HWND STDCALL
1073 NtUserCreateWindowEx(DWORD dwExStyle,
1074                      PUNICODE_STRING lpClassName,
1075                      PUNICODE_STRING lpWindowName,
1076                      DWORD dwStyle,
1077                      LONG x,
1078                      LONG y,
1079                      LONG nWidth,
1080                      LONG nHeight,
1081                      HWND hWndParent,
1082                      HMENU hMenu,
1083                      HINSTANCE hInstance,
1084                      LPVOID lpParam,
1085                      DWORD dwShowMode)
1086 {
1087   PWINSTATION_OBJECT WinStaObject;
1088   PWNDCLASS_OBJECT ClassObject;
1089   PWINDOW_OBJECT WindowObject;
1090   PWINDOW_OBJECT ParentWindow;
1091   PMENU_OBJECT SystemMenu;
1092   UNICODE_STRING WindowName;
1093   NTSTATUS Status;
1094   HANDLE Handle;
1095   POINT MaxSize, MaxPos, MinTrack, MaxTrack;
1096   CREATESTRUCTW Cs;
1097   LRESULT Result;
1098   DPRINT("NtUserCreateWindowEx\n");
1099
1100   /* Initialize gui state if necessary. */
1101   IntGraphicsCheck(TRUE);
1102
1103   if (!RtlCreateUnicodeString(&WindowName,
1104                               NULL == lpWindowName->Buffer ?
1105                               L"" : lpWindowName->Buffer))
1106     {
1107       SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
1108       return((HWND)0);
1109     }
1110
1111   /* FIXME: parent must belong to the current process */
1112
1113   if (hWndParent != NULL)
1114     {
1115       ParentWindow = IntGetWindowObject(hWndParent);
1116     }
1117   else
1118     {
1119       hWndParent = PsGetWin32Thread()->Desktop->DesktopWindow;
1120       ParentWindow = IntGetWindowObject(hWndParent);
1121     }
1122
1123   /* Check the class. */
1124   Status = ClassReferenceClassByNameOrAtom(&ClassObject, lpClassName->Buffer);
1125   if (!NT_SUCCESS(Status))
1126     {
1127       RtlFreeUnicodeString(&WindowName);
1128       IntReleaseWindowObject(ParentWindow);
1129       return((HWND)0);
1130     }
1131
1132   /* Check the window station. */
1133   DPRINT("IoGetCurrentProcess() %X\n", IoGetCurrentProcess());
1134   DPRINT("PROCESS_WINDOW_STATION %X\n", PROCESS_WINDOW_STATION());
1135   Status = ValidateWindowStationHandle(PROCESS_WINDOW_STATION(),
1136                                        KernelMode,
1137                                        0,
1138                                        &WinStaObject);
1139   if (!NT_SUCCESS(Status))
1140     {
1141       RtlFreeUnicodeString(&WindowName);
1142       ObmDereferenceObject(ClassObject);
1143       IntReleaseWindowObject(ParentWindow);
1144       DPRINT("Validation of window station handle (0x%X) failed\n",
1145              PROCESS_WINDOW_STATION());
1146       return (HWND)0;
1147     }
1148
1149   /* Create the window object. */
1150   WindowObject = (PWINDOW_OBJECT)
1151     ObmCreateObject(PsGetWin32Process()->WindowStation->HandleTable, &Handle,
1152         otWindow, sizeof(WINDOW_OBJECT) + ClassObject->cbWndExtra
1153         );
1154
1155   DPRINT("Created object with handle %X\n", Handle);
1156   if (!WindowObject)
1157     {
1158       ObDereferenceObject(WinStaObject);
1159       ObmDereferenceObject(ClassObject);
1160       RtlFreeUnicodeString(&WindowName);
1161       IntReleaseWindowObject(ParentWindow);
1162       SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
1163       return (HWND)0;
1164     }
1165   ObDereferenceObject(WinStaObject);
1166
1167   /*
1168    * Fill out the structure describing it.
1169    */
1170   WindowObject->Class = ClassObject;
1171   WindowObject->ExStyle = dwExStyle;
1172   WindowObject->Style = dwStyle & ~WS_VISIBLE;
1173   DPRINT("1: Style is now %d\n", WindowObject->Style);
1174   
1175   SystemMenu = IntGetSystemMenu(WindowObject, TRUE, TRUE);
1176   
1177   WindowObject->x = x;
1178   WindowObject->y = y;
1179   WindowObject->Width = nWidth;
1180   WindowObject->Height = nHeight;
1181   WindowObject->ContextHelpId = 0;
1182   WindowObject->ParentHandle = hWndParent;
1183   WindowObject->IDMenu = (UINT)hMenu;
1184   if(SystemMenu)
1185     WindowObject->SystemMenu = SystemMenu->Self;
1186   else
1187     WindowObject->SystemMenu = (HMENU)0;
1188   WindowObject->Instance = hInstance;
1189   WindowObject->Parameters = lpParam;
1190   WindowObject->Self = Handle;
1191   WindowObject->MessageQueue = PsGetWin32Thread()->MessageQueue;
1192   WindowObject->Parent = ParentWindow;
1193   WindowObject->UserData = 0;
1194   WindowObject->Unicode = ClassObject->Unicode;
1195   WindowObject->WndProcA = ClassObject->lpfnWndProcA;
1196   WindowObject->WndProcW = ClassObject->lpfnWndProcW;
1197   WindowObject->OwnerThread = PsGetCurrentThread();
1198   WindowObject->FirstChild = NULL;
1199   WindowObject->LastChild = NULL;
1200   WindowObject->PrevSibling = NULL;
1201   WindowObject->NextSibling = NULL;
1202
1203   /* extra window data */
1204   if (ClassObject->cbWndExtra != 0)
1205     {
1206       WindowObject->ExtraData = (PULONG)(WindowObject + 1);
1207       WindowObject->ExtraDataSize = ClassObject->cbWndExtra;
1208       RtlZeroMemory(WindowObject->ExtraData, WindowObject->ExtraDataSize);
1209     }
1210   else
1211     {
1212       WindowObject->ExtraData = NULL;
1213       WindowObject->ExtraDataSize = 0;
1214     }
1215
1216   InitializeListHead(&WindowObject->PropListHead);
1217   ExInitializeFastMutex(&WindowObject->ChildrenListLock);
1218
1219   RtlInitUnicodeString(&WindowObject->WindowName, WindowName.Buffer);
1220   RtlFreeUnicodeString(&WindowName);
1221
1222
1223   /* Correct the window style. */
1224   if (!(dwStyle & WS_CHILD))
1225     {
1226       WindowObject->Style |= WS_CLIPSIBLINGS;
1227       DPRINT("3: Style is now %d\n", WindowObject->Style);
1228       if (!(dwStyle & WS_POPUP))
1229         {
1230           WindowObject->Style |= WS_CAPTION;
1231       WindowObject->Flags |= WINDOWOBJECT_NEED_SIZE;
1232       DPRINT("4: Style is now %d\n", WindowObject->Style);
1233           /* FIXME: Note the window needs a size. */ 
1234         }
1235     }
1236
1237   /* Insert the window into the thread's window list. */
1238   ExAcquireFastMutexUnsafe (&PsGetWin32Thread()->WindowListLock);
1239   InsertTailList (&PsGetWin32Thread()->WindowListHead, 
1240                   &WindowObject->ThreadListEntry);
1241   ExReleaseFastMutexUnsafe (&PsGetWin32Thread()->WindowListLock);
1242
1243   /* Allocate a DCE for this window. */
1244   if (dwStyle & CS_OWNDC) WindowObject->Dce = DceAllocDCE(WindowObject->Self,DCE_WINDOW_DC);
1245   /* FIXME:  Handle "CS_CLASSDC" */
1246
1247   /* Initialize the window dimensions. */
1248   WindowObject->WindowRect.left = x;
1249   WindowObject->WindowRect.top = y;
1250   WindowObject->WindowRect.right = x + nWidth;
1251   WindowObject->WindowRect.bottom = y + nHeight;
1252   WindowObject->ClientRect = WindowObject->WindowRect;
1253
1254   /*
1255    * Get the size and position of the window.
1256    */
1257   if ((dwStyle & WS_THICKFRAME) || !(dwStyle & (WS_POPUP | WS_CHILD)))
1258     {
1259       /* WinPosGetMinMaxInfo sends the WM_GETMINMAXINFO message */
1260       WinPosGetMinMaxInfo(WindowObject, &MaxSize, &MaxPos, &MinTrack,
1261                           &MaxTrack);
1262       x = min(MaxSize.x, y);
1263       y = min(MaxSize.y, y);
1264       x = max(MinTrack.x, x);
1265       y = max(MinTrack.y, y);
1266     }
1267
1268   WindowObject->WindowRect.left = x;
1269   WindowObject->WindowRect.top = y;
1270   WindowObject->WindowRect.right = x + nWidth;
1271   WindowObject->WindowRect.bottom = y + nHeight;
1272   WindowObject->ClientRect = WindowObject->WindowRect;
1273
1274   /* FIXME: Initialize the window menu. */
1275   
1276   /* Initialize the window's scrollbars */
1277   if (dwStyle & WS_VSCROLL)
1278       IntCreateScrollBar(WindowObject, SB_VERT);
1279   if (dwStyle & WS_HSCROLL)
1280       IntCreateScrollBar(WindowObject, SB_HORZ);
1281
1282   /* Send a NCCREATE message. */
1283   Cs.lpCreateParams = lpParam;
1284   Cs.hInstance = hInstance;
1285   Cs.hMenu = hMenu;
1286   Cs.hwndParent = hWndParent;
1287   Cs.cx = nWidth;
1288   Cs.cy = nHeight;
1289   Cs.x = x;
1290   Cs.y = y;
1291   Cs.style = dwStyle;
1292   Cs.lpszName = lpWindowName->Buffer;
1293   Cs.lpszClass = lpClassName->Buffer;
1294   Cs.dwExStyle = dwExStyle;
1295
1296     // AG: For some reason these don't get set already. This might need moving
1297     // elsewhere... What is actually done with WindowObject anyway, to retain
1298     // its data?
1299   DPRINT("[win32k.window] NtUserCreateWindowEx style %d, exstyle %d, parent %d\n", Cs.style, Cs.dwExStyle, Cs.hwndParent);
1300 //  NtUserSetWindowLong(Handle, GWL_STYLE, WindowObject->Style, TRUE);
1301 //  NtUserSetWindowLong(Handle, GWL_EXSTYLE, WindowObject->ExStyle, TRUE);
1302   // Any more?
1303
1304   DPRINT("NtUserCreateWindowEx(): About to send NCCREATE message.\n");
1305   Result = IntSendNCCREATEMessage(WindowObject->Self, &Cs);
1306   if (!Result)
1307     {
1308       /* FIXME: Cleanup. */
1309       IntReleaseWindowObject(ParentWindow);
1310       DPRINT("NtUserCreateWindowEx(): NCCREATE message failed.\n");
1311       return((HWND)0);
1312     }
1313  
1314   /* Calculate the non-client size. */
1315   MaxPos.x = WindowObject->WindowRect.left;
1316   MaxPos.y = WindowObject->WindowRect.top;
1317   DPRINT("NtUserCreateWindowEx(): About to get non-client size.\n");
1318   /* WinPosGetNonClientSize SENDS THE WM_NCCALCSIZE message */
1319   Result = WinPosGetNonClientSize(WindowObject->Self, 
1320                                   &WindowObject->WindowRect,
1321                                   &WindowObject->ClientRect);
1322   NtGdiOffsetRect(&WindowObject->WindowRect, 
1323                  MaxPos.x - WindowObject->WindowRect.left,
1324                  MaxPos.y - WindowObject->WindowRect.top);
1325
1326
1327   /* link the window into the parent's child list */
1328   ExAcquireFastMutexUnsafe(&ParentWindow->ChildrenListLock);
1329   if ((dwStyle & (WS_CHILD|WS_MAXIMIZE)) == WS_CHILD)
1330   {
1331     /* link window as bottom sibling */
1332     IntLinkWindow(WindowObject, ParentWindow, ParentWindow->LastChild /*prev sibling*/);
1333   }
1334   else
1335   {
1336     /* link window as top sibling */
1337     IntLinkWindow(WindowObject, ParentWindow, NULL /*prev sibling*/);
1338   }
1339   ExReleaseFastMutexUnsafe(&ParentWindow->ChildrenListLock);
1340
1341   /* Send the WM_CREATE message. */
1342   DPRINT("NtUserCreateWindowEx(): about to send CREATE message.\n");
1343   Result = IntSendCREATEMessage(WindowObject->Self, &Cs);
1344   if (Result == (LRESULT)-1)
1345     {
1346       /* FIXME: Cleanup. */
1347       IntReleaseWindowObject(ParentWindow);
1348       DPRINT("NtUserCreateWindowEx(): send CREATE message failed.\n");
1349       return((HWND)0);
1350     } 
1351   
1352   /* Send move and size messages. */
1353   if (!(WindowObject->Flags & WINDOWOBJECT_NEED_SIZE))
1354     {
1355       LONG lParam;
1356
1357       DPRINT("NtUserCreateWindow(): About to send WM_SIZE\n");
1358
1359       if ((WindowObject->ClientRect.right - WindowObject->ClientRect.left) < 0 ||
1360           (WindowObject->ClientRect.bottom - WindowObject->ClientRect.top) < 0)
1361          DPRINT("Sending bogus WM_SIZE\n");
1362       
1363       lParam = MAKE_LONG(WindowObject->ClientRect.right - 
1364                   WindowObject->ClientRect.left,
1365                   WindowObject->ClientRect.bottom - 
1366                   WindowObject->ClientRect.top);
1367       IntCallWindowProc(NULL, WindowObject->Self, WM_SIZE, SIZE_RESTORED, 
1368           lParam);
1369
1370       DPRINT("NtUserCreateWindow(): About to send WM_MOVE\n");
1371
1372       lParam = MAKE_LONG(WindowObject->ClientRect.left,
1373           WindowObject->ClientRect.top);
1374       IntCallWindowProc(NULL, WindowObject->Self, WM_MOVE, 0, lParam);
1375     }
1376
1377   /* Move from parent-client to screen coordinates */
1378   if (0 != (WindowObject->Style & WS_CHILD))
1379     {
1380     NtGdiOffsetRect(&WindowObject->WindowRect,
1381                    ParentWindow->ClientRect.left,
1382                    ParentWindow->ClientRect.top);
1383     NtGdiOffsetRect(&WindowObject->ClientRect,
1384                    ParentWindow->ClientRect.left,
1385                    ParentWindow->ClientRect.top);
1386     }
1387
1388   /* Show or maybe minimize or maximize the window. */
1389   if (WindowObject->Style & (WS_MINIMIZE | WS_MAXIMIZE))
1390     {
1391       RECT NewPos;
1392       UINT16 SwFlag;
1393
1394       SwFlag = (WindowObject->Style & WS_MINIMIZE) ? SW_MINIMIZE : 
1395         SW_MAXIMIZE;
1396       WinPosMinMaximize(WindowObject, SwFlag, &NewPos);
1397       SwFlag = 
1398         ((WindowObject->Style & WS_CHILD) || IntGetActiveWindow()) ?
1399         SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED :
1400         SWP_NOZORDER | SWP_FRAMECHANGED;
1401       DPRINT("NtUserCreateWindow(): About to minimize/maximize\n");
1402       WinPosSetWindowPos(WindowObject->Self, 0, NewPos.left, NewPos.top,
1403                          NewPos.right, NewPos.bottom, SwFlag);
1404     }
1405
1406   /* Notify the parent window of a new child. */
1407   if ((WindowObject->Style & WS_CHILD) ||
1408       (!(WindowObject->ExStyle & WS_EX_NOPARENTNOTIFY)))
1409     {
1410       DPRINT("NtUserCreateWindow(): About to notify parent\n");
1411       IntCallWindowProc(NULL, WindowObject->Parent->Self,
1412                          WM_PARENTNOTIFY, 
1413                          MAKEWPARAM(WM_CREATE, WindowObject->IDMenu),
1414                          (LPARAM)WindowObject->Self);
1415     }
1416
1417   if (dwStyle & WS_VISIBLE)
1418     {
1419       DPRINT("NtUserCreateWindow(): About to show window\n");
1420       WinPosShowWindow(WindowObject->Self, dwShowMode);
1421     }
1422   /* FIXME:  Should code be reworked to accomodate the following line? */
1423         DPRINT("Setting Active Window to %d\n\n\n",WindowObject->Self);
1424   NtUserSetActiveWindow(WindowObject->Self);
1425   DPRINT("NtUserCreateWindow(): = %X\n", Handle);
1426   DPRINT("WindowObject->SystemMenu = 0x%x\n", WindowObject->SystemMenu);
1427   return((HWND)Handle);
1428 }
1429
1430
1431 /*
1432  * @unimplemented
1433  */
1434 HDWP STDCALL
1435 NtUserDeferWindowPos(HDWP WinPosInfo,
1436                      HWND Wnd,
1437                      HWND WndInsertAfter,
1438                      int x,
1439          int y,
1440          int cx,
1441          int cy,
1442                      UINT Flags)
1443 {
1444   UNIMPLEMENTED
1445
1446   return 0;
1447 }
1448
1449
1450 /*
1451  * @implemented
1452  */
1453 BOOLEAN STDCALL
1454 NtUserDestroyWindow(HWND Wnd)
1455 {
1456   PWINDOW_OBJECT Window;
1457   BOOLEAN isChild;
1458   HWND hWndFocus;
1459
1460   Window = IntGetWindowObject(Wnd);
1461   if (Window == NULL)
1462     {
1463       return FALSE;
1464     }
1465
1466   /* Check for desktop window (has NULL parent) */
1467   if (NULL == Window->Parent)
1468     {
1469       IntReleaseWindowObject(Window);
1470       SetLastWin32Error(ERROR_ACCESS_DENIED);
1471       return FALSE;
1472     }
1473
1474   /* Look whether the focus is within the tree of windows we will
1475    * be destroying.
1476    */
1477   hWndFocus = IntGetFocusWindow();
1478   if (hWndFocus == Wnd || IntIsChildWindow(Wnd, hWndFocus))
1479     {
1480       HWND Parent = NtUserGetAncestor(Wnd, GA_PARENT);
1481       if (Parent == IntGetDesktopWindow())
1482         {
1483           Parent = NULL;
1484         }
1485         IntSetFocusWindow(Parent);
1486     }
1487
1488   /* Call hooks */
1489 #if 0 /* FIXME */
1490   if (HOOK_CallHooks(WH_CBT, HCBT_DESTROYWND, (WPARAM) hwnd, 0, TRUE))
1491     {
1492     return FALSE;
1493     }
1494 #endif
1495
1496   isChild = (0 != (Window->Style & WS_CHILD));
1497
1498 #if 0 /* FIXME */
1499   if (isChild)
1500     {
1501       if (! USER_IsExitingThread(GetCurrentThreadId()))
1502         {
1503           send_parent_notify(hwnd, WM_DESTROY);
1504         }
1505     }
1506   else if (NULL != GetWindow(Wnd, GW_OWNER))
1507     {
1508       HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
1509       /* FIXME: clean up palette - see "Internals" p.352 */
1510     }
1511
1512   if (! IsWindow(Wnd))
1513     {
1514     return TRUE;
1515     }
1516 #endif
1517
1518   /* Hide the window */
1519   if (! WinPosShowWindow(Wnd, SW_HIDE ))
1520     {
1521 #if 0 /* FIXME */
1522       if (hwnd == GetActiveWindow())
1523         {
1524           WINPOS_ActivateOtherWindow( hwnd );
1525         }
1526 #endif
1527     }
1528
1529 #if 0 /* FIXME */
1530   if (! IsWindow(Wnd))
1531     {
1532     return TRUE;
1533     }
1534 #endif
1535
1536   /* Recursively destroy owned windows */
1537 #if 0 /* FIXME */
1538   if (! isChild)
1539     {
1540       for (;;)
1541         {
1542           int i;
1543           BOOL GotOne = FALSE;
1544           HWND *list = WIN_ListChildren(GetDesktopWindow());
1545           if (list)
1546             {
1547               for (i = 0; list[i]; i++)
1548                 {
1549                   if (GetWindow(list[i], GW_OWNER) != Wnd)
1550                     {
1551                       continue;
1552                     }
1553                   if (WIN_IsCurrentThread(list[i]))
1554                     {
1555                       DestroyWindow(list[i]);
1556                       GotOne = TRUE;
1557                       continue;
1558                     }
1559                   WIN_SetOwner(list[i], NULL);
1560                 }
1561               HeapFree(GetProcessHeap(), 0, list);
1562             }
1563           if (! GotOne)
1564             {
1565               break;
1566             }
1567         }
1568     }
1569 #endif
1570
1571   /* Send destroy messages */
1572   IntSendDestroyMsg(Wnd);
1573
1574 #if 0 /* FIXME */
1575   if (!IsWindow(Wnd))
1576     {
1577       return TRUE;
1578     }
1579 #endif
1580
1581   /* Unlink now so we won't bother with the children later on */
1582 #if 0 /* FIXME */
1583   WIN_UnlinkWindow( hwnd );
1584 #endif
1585
1586   /* Destroy the window storage */
1587   IntDestroyWindow(Window, PsGetWin32Process(), PsGetWin32Thread(), TRUE);
1588
1589   return TRUE;
1590 }
1591
1592
1593 /*
1594  * @unimplemented
1595  */
1596 DWORD
1597 STDCALL
1598 NtUserDrawMenuBarTemp(
1599   HWND hWnd,
1600   HDC hDC,
1601   PRECT hRect,
1602   HMENU hMenu,
1603   HFONT hFont)
1604 {
1605   /* we'll use this function just for caching the menu bar */
1606   UNIMPLEMENTED
1607   return 0;
1608 }
1609
1610
1611 /*
1612  * @unimplemented
1613  */
1614 DWORD STDCALL
1615 NtUserEndDeferWindowPosEx(DWORD Unknown0,
1616                           DWORD Unknown1)
1617 {
1618   UNIMPLEMENTED
1619     
1620   return 0;
1621 }
1622
1623
1624 /*
1625  * @unimplemented
1626  */
1627 DWORD STDCALL
1628 NtUserFillWindow(DWORD Unknown0,
1629                  DWORD Unknown1,
1630                  DWORD Unknown2,
1631                  DWORD Unknown3)
1632 {
1633   UNIMPLEMENTED
1634
1635   return 0;
1636 }
1637
1638
1639 /*
1640  * FUNCTION:
1641  *   Searches a window's children for a window with the specified
1642  *   class and name
1643  * ARGUMENTS:
1644  *   hwndParent     = The window whose childs are to be searched. 
1645  *                                        NULL = desktop
1646  *
1647  *   hwndChildAfter = Search starts after this child window. 
1648  *                                        NULL = start from beginning
1649  *
1650  *   ucClassName    = Class name to search for
1651  *                                        Reguired parameter.
1652  *
1653  *   ucWindowName   = Window name
1654  *                                        ->Buffer == NULL = don't care
1655  *                        
1656  * RETURNS:
1657  *   The HWND of the window if it was found, otherwise NULL
1658  *
1659  * FIXME:
1660  *   Should use MmCopyFromCaller, we don't want an access violation in here
1661  *       
1662  */
1663 /*
1664  * @implemented
1665  */
1666 HWND STDCALL
1667 NtUserFindWindowEx(HWND hwndParent,
1668                    HWND hwndChildAfter,
1669                    PUNICODE_STRING ucClassName,
1670                    PUNICODE_STRING ucWindowName)
1671 {
1672   NTSTATUS status;
1673   HWND windowHandle;
1674   PWINDOW_OBJECT ParentWindow, WndChildAfter, WndChild;
1675   PWNDCLASS_OBJECT classObject;
1676   
1677   // Get a pointer to the class
1678   status = ClassReferenceClassByNameOrAtom(&classObject, ucClassName->Buffer);
1679   if (!NT_SUCCESS(status))
1680     {
1681       return NULL;
1682     }
1683   
1684   // If hwndParent==NULL use the desktop window instead
1685   if(!hwndParent)
1686       hwndParent = PsGetWin32Thread()->Desktop->DesktopWindow;
1687
1688   // Get the object
1689   ParentWindow = IntGetWindowObject(hwndParent);
1690
1691   if(!ParentWindow)
1692     {
1693       ObmDereferenceObject(classObject);
1694       return NULL;      
1695     }
1696
1697   ExAcquireFastMutexUnsafe (&ParentWindow->ChildrenListLock);
1698
1699   if(hwndChildAfter)
1700   {
1701     if (!(WndChildAfter = IntGetWindowObject(hwndChildAfter)))
1702     {
1703       SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
1704       return NULL;
1705     }
1706
1707     /* must be a direct child (not a decendant child)*/
1708     if (WndChildAfter->Parent != ParentWindow)
1709     {
1710       SetLastWin32Error(ERROR_INVALID_PARAMETER);
1711       return NULL;
1712     }
1713     
1714     WndChild = WndChildAfter->NextSibling;
1715   }
1716   else
1717   {
1718     WndChild = ParentWindow->FirstChild;
1719   }
1720
1721   while (WndChild)
1722   {
1723     if (classObject == WndChild->Class && (ucWindowName->Buffer==NULL || 
1724         RtlCompareUnicodeString (ucWindowName, &WndChild->WindowName, TRUE) == 0))
1725     {
1726       windowHandle = WndChild->Self;
1727
1728       ExReleaseFastMutexUnsafe (&ParentWindow->ChildrenListLock);
1729       IntReleaseWindowObject(ParentWindow);
1730       ObmDereferenceObject (classObject);
1731       
1732       return windowHandle;
1733     }
1734     
1735     WndChild = WndChild->NextSibling;
1736   }
1737
1738   ExReleaseFastMutexUnsafe (&ParentWindow->ChildrenListLock);
1739
1740   IntReleaseWindowObject(ParentWindow);
1741   ObmDereferenceObject (classObject);
1742
1743   return  NULL;
1744 }
1745
1746
1747 /*
1748  * @unimplemented
1749  */
1750 DWORD STDCALL
1751 NtUserFlashWindowEx(DWORD Unknown0)
1752 {
1753   UNIMPLEMENTED
1754
1755   return 0;
1756 }
1757
1758
1759 /*
1760  * @implemented
1761  */
1762 HWND STDCALL
1763 NtUserGetAncestor(HWND hWnd, UINT Type)
1764 {
1765   PWINDOW_OBJECT Wnd, WndAncestor;
1766   HWND hWndAncestor = NULL;
1767
1768   IntAcquireWinLockShared();
1769
1770   if (!(Wnd = IntGetWindowObject(hWnd)))
1771   {
1772     SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
1773     return NULL;
1774   }
1775
1776   WndAncestor = IntGetAncestor(Wnd, Type);
1777   if (WndAncestor) hWndAncestor = WndAncestor->Self;
1778
1779   IntReleaseWinLock();
1780
1781   return hWndAncestor;
1782 }
1783
1784
1785 /*
1786  * @implemented
1787  */
1788 HWND
1789 STDCALL
1790 NtUserGetCapture(VOID)
1791 {
1792   PWINDOW_OBJECT Window;
1793   Window = IntGetCaptureWindow();
1794   if (Window != NULL)
1795     {
1796       return(Window->Self);
1797     }
1798   else
1799     {
1800       return(NULL);
1801     }
1802 }
1803
1804
1805 /*!
1806  * Returns client window rectangle relative to the upper-left corner of client area.
1807  *
1808  * \param       hWnd    window handle.
1809  * \param       Rect    pointer to the buffer where the coordinates are returned.
1810  *
1811 */
1812 /*
1813  * @implemented
1814  */
1815 BOOL STDCALL
1816 NtUserGetClientRect(HWND hWnd, LPRECT Rect)
1817 {
1818   PWINDOW_OBJECT WindowObject;
1819   RECT SafeRect;
1820
1821   IntAcquireWinLockShared();
1822   if (!(WindowObject = IntGetWindowObject(hWnd)))
1823   {
1824     IntReleaseWinLock();
1825     SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);      
1826     return FALSE;
1827   }
1828
1829   IntGetClientRect(WindowObject, &SafeRect);
1830   IntReleaseWinLock();
1831
1832   if (! NT_SUCCESS(MmCopyToCaller(Rect, &SafeRect, sizeof(RECT))))
1833   {
1834     return(FALSE);
1835   }
1836
1837   return(TRUE);
1838 }
1839
1840
1841 /*
1842  * @implemented
1843  */
1844 HWND
1845 STDCALL
1846 NtUserGetDesktopWindow()
1847 {
1848   return IntGetDesktopWindow();
1849 }
1850
1851
1852 /*
1853  * @unimplemented
1854  */
1855 DWORD STDCALL
1856 NtUserGetForegroundWindow(VOID)
1857 {
1858   UNIMPLEMENTED
1859
1860   return 0;
1861 }
1862
1863
1864 /*
1865  * @unimplemented
1866  */
1867 DWORD STDCALL
1868 NtUserGetInternalWindowPos(DWORD Unknown0,
1869                            DWORD Unknown1,
1870                            DWORD Unknown2)
1871 {
1872   UNIMPLEMENTED
1873
1874   return 0;
1875 }
1876
1877
1878 /*
1879  * @implemented
1880  */
1881 HWND
1882 STDCALL
1883 NtUserGetLastActivePopup(HWND hWnd)
1884 {
1885   PWINDOW_OBJECT Wnd;
1886   HWND hWndLastPopup;
1887
1888   IntAcquireWinLockShared();
1889
1890   if (!(Wnd = IntGetWindowObject(hWnd)))
1891   {
1892     IntReleaseWinLock();
1893     SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
1894     return NULL;
1895   }
1896
1897   hWndLastPopup = Wnd->hWndLastPopup;
1898
1899   IntReleaseWinLock();
1900
1901   return hWndLastPopup;
1902 }
1903
1904
1905 /*
1906  * @unimplemented
1907  */
1908 DWORD STDCALL
1909 NtUserGetOpenClipboardWindow(VOID)
1910 {
1911   UNIMPLEMENTED
1912
1913   return 0;
1914 }
1915
1916
1917 /*
1918  * @implemented
1919  */
1920 HWND STDCALL
1921 NtUserGetParent(HWND hWnd)
1922 {
1923   PWINDOW_OBJECT Wnd, WndParent;
1924   HWND hWndParent = NULL;
1925
1926   IntAcquireWinLockShared();
1927
1928   if (!(Wnd = IntGetWindowObject(hWnd)))
1929   {
1930     SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
1931     return NULL;
1932   }
1933
1934   WndParent = IntGetParent(Wnd);
1935   if (WndParent) hWndParent = WndParent->Self;
1936
1937   IntReleaseWinLock();
1938
1939   return hWndParent;
1940 }
1941
1942
1943 /*
1944  * @implemented
1945  */
1946 HWND STDCALL
1947 NtUserGetShellWindow()
1948 {
1949         return hwndShellWindow;
1950 }
1951
1952
1953 /*
1954  * @implemented
1955  */
1956 HMENU
1957 STDCALL
1958 NtUserGetSystemMenu(
1959   HWND hWnd,
1960   BOOL bRevert)
1961 {
1962   HMENU res = (HMENU)0;
1963   PWINDOW_OBJECT WindowObject;
1964   WindowObject = IntGetWindowObject((HWND)hWnd);
1965   if(!WindowObject)
1966   {
1967     SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
1968     return (HMENU)0;
1969   }
1970   
1971   res = IntGetSystemMenu(WindowObject, bRevert, FALSE);
1972   
1973   IntReleaseWindowObject(WindowObject);
1974   return res;
1975 }
1976
1977
1978 /*
1979  * @implemented
1980  */
1981 HWND
1982 STDCALL
1983 NtUserGetWindow(HWND hWnd, UINT Relationship)
1984 {
1985   PWINDOW_OBJECT Wnd;
1986   HWND hWndResult = NULL;
1987
1988   IntAcquireWinLockShared();
1989
1990   if (!(Wnd = IntGetWindowObject(hWnd)))
1991   {
1992     IntReleaseWinLock();
1993     SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
1994     return NULL;
1995   }
1996   
1997   switch (Relationship)
1998   {
1999     case GW_HWNDFIRST:
2000       if (Wnd->Parent && Wnd->Parent->FirstChild)
2001       {
2002         hWndResult = Wnd->Parent->FirstChild->Self;
2003       }
2004       break;
2005     case GW_HWNDLAST:
2006       if (Wnd->Parent && Wnd->Parent->LastChild)
2007       {
2008         hWndResult = Wnd->Parent->LastChild->Self;
2009       }
2010       break;
2011     case GW_HWNDNEXT:
2012       if (Wnd->Parent && Wnd->NextSibling)
2013       {
2014         hWndResult = Wnd->NextSibling->Self;
2015       }
2016       break;
2017     case GW_HWNDPREV:
2018       if (Wnd->Parent && Wnd->PrevSibling)
2019       {
2020         hWndResult = Wnd->PrevSibling->Self;
2021       }
2022       break;
2023     case GW_OWNER:
2024       if (Wnd->Parent)
2025       {
2026         hWndResult = Wnd->hWndOwner;
2027       }
2028       break;
2029     case GW_CHILD:
2030       if (Wnd->FirstChild)
2031       {
2032         hWndResult = Wnd->FirstChild->Self;
2033       }
2034       break;
2035   }
2036
2037   IntReleaseWinLock();
2038
2039   return hWndResult;
2040 }
2041
2042
2043 /*
2044  * @implemented
2045  */
2046 DWORD STDCALL
2047 NtUserGetWindowDC(HWND hWnd)
2048 {
2049   return (DWORD) NtUserGetDCEx( hWnd, 0, DCX_USESTYLE | DCX_WINDOW );
2050 }
2051
2052
2053 /*
2054  * @implemented
2055  */
2056 LONG STDCALL
2057 NtUserGetWindowLong(HWND hWnd, DWORD Index, BOOL Ansi)
2058 {
2059   PWINDOW_OBJECT WindowObject;
2060   NTSTATUS Status;
2061   LONG Result;
2062
2063   Status = 
2064     ObmReferenceObjectByHandle(PsGetWin32Process()->WindowStation->HandleTable,
2065                                hWnd,
2066                                otWindow,
2067                                (PVOID*)&WindowObject);
2068   if (!NT_SUCCESS(Status))
2069     {
2070       SetLastWin32Error(ERROR_INVALID_HANDLE);
2071       return 0;
2072     }
2073
2074   if (0 <= (int) Index)
2075     {
2076       if (WindowObject->ExtraDataSize - sizeof(LONG) < Index ||
2077           0 != Index % sizeof(LONG))
2078         {
2079           SetLastWin32Error(ERROR_INVALID_PARAMETER);
2080           return 0;
2081         }
2082       Result = WindowObject->ExtraData[Index / sizeof(LONG)];
2083     }
2084   else
2085     {
2086       switch (Index)
2087         {
2088         case GWL_EXSTYLE:
2089           Result = WindowObject->ExStyle;
2090           break;
2091
2092         case GWL_STYLE:
2093           Result = WindowObject->Style;
2094           break;
2095         case GWL_WNDPROC:
2096           if (Ansi)
2097           {
2098                 Result = (LONG) WindowObject->WndProcA;
2099           }
2100           else
2101           {
2102                 Result = (LONG) WindowObject->WndProcW;
2103           }
2104           break;
2105
2106         case GWL_HINSTANCE:
2107           Result = (LONG) WindowObject->Instance;
2108           break;
2109
2110         case GWL_HWNDPARENT:
2111           Result = (LONG) WindowObject->ParentHandle;
2112           break;
2113
2114         case GWL_ID:
2115           Result = (LONG) WindowObject->IDMenu;
2116           break;
2117
2118         case GWL_USERDATA:
2119           Result = WindowObject->UserData;
2120           break;
2121     
2122         default:
2123           DPRINT1("NtUserGetWindowLong(): Unsupported index %d\n", Index);
2124           SetLastWin32Error(ERROR_INVALID_PARAMETER);
2125           Result = 0;
2126           break;
2127         }
2128     }
2129
2130   ObmDereferenceObject(WindowObject);
2131
2132   return Result;
2133 }
2134
2135
2136 /*
2137  * @unimplemented
2138  */
2139 DWORD STDCALL
2140 NtUserGetWindowPlacement(DWORD Unknown0,
2141                          DWORD Unknown1)
2142 {
2143   UNIMPLEMENTED
2144
2145   return 0;
2146 }
2147
2148
2149 /*!
2150  * Return the dimension of the window in the screen coordinates.
2151  * \param       hWnd    window handle.
2152  * \param       Rect    pointer to the buffer where the coordinates are returned.
2153 */
2154 /*
2155  * @implemented
2156  */
2157 BOOL STDCALL
2158 NtUserGetWindowRect(HWND hWnd, LPRECT Rect)
2159 {
2160   PWINDOW_OBJECT Wnd;
2161   RECT SafeRect;
2162
2163   IntAcquireWinLockShared();
2164   if (!(Wnd = IntGetWindowObject(hWnd)))
2165   {
2166     IntReleaseWinLock();
2167     SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);      
2168     return FALSE;
2169   }
2170   
2171   SafeRect = Wnd->WindowRect;
2172   IntReleaseWinLock();
2173
2174   if (! NT_SUCCESS(MmCopyToCaller(Rect, &SafeRect, sizeof(RECT))))
2175   {
2176     return FALSE;
2177   }
2178
2179   return TRUE;
2180 }
2181
2182
2183 /*
2184  * @implemented
2185  */
2186 DWORD STDCALL
2187 NtUserGetWindowThreadProcessId(HWND hWnd, LPDWORD UnsafePid)
2188 {
2189    PWINDOW_OBJECT Wnd;
2190    DWORD tid, pid;
2191
2192    IntAcquireWinLockShared();
2193
2194    if (!(Wnd = IntGetWindowObject(hWnd)))
2195    {
2196       IntReleaseWinLock();
2197       SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
2198       return 0;
2199    }
2200
2201    tid = IntGetWindowThreadProcessId(Wnd, &pid);
2202    IntReleaseWinLock();
2203    
2204    if (UnsafePid) MmCopyToCaller(UnsafePid, &pid, sizeof(DWORD));
2205    
2206    return tid;
2207 }
2208
2209
2210 /*
2211  * @unimplemented
2212  */
2213 DWORD STDCALL
2214 NtUserInternalGetWindowText(HWND hWnd,
2215                             LPWSTR lpString,
2216                             int nMaxCount)
2217 {
2218   DWORD res = 0;
2219   PWINDOW_OBJECT WindowObject;
2220   
2221   IntAcquireWinLockShared(); /* ??? */
2222   WindowObject = IntGetWindowObject(hWnd);
2223   if(!WindowObject)
2224   {
2225     IntReleaseWinLock(); /* ??? */
2226     SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
2227     return 0;
2228   }
2229   
2230   if(lpString)
2231   {
2232     /* FIXME - Window text is currently stored
2233                in the Atom 'USER32!WindowTextAtomA' */
2234     
2235   }
2236   else
2237   {
2238     /* FIXME - return length of window text */
2239   }
2240   
2241   IntReleaseWindowObject(WindowObject);
2242   
2243   IntReleaseWinLock(); /* ??? */
2244   return res;
2245 }
2246
2247
2248 /*
2249  * @unimplemented
2250  */
2251 DWORD STDCALL
2252 NtUserLockWindowUpdate(DWORD Unknown0)
2253 {
2254   UNIMPLEMENTED
2255
2256   return 0;
2257 }
2258
2259
2260 /*
2261  * @implemented
2262  */
2263 BOOL STDCALL
2264 NtUserMoveWindow(      
2265     HWND hWnd,
2266     int X,
2267     int Y,
2268     int nWidth,
2269     int nHeight,
2270     BOOL bRepaint)
2271 {
2272         UINT    flags = SWP_NOZORDER | SWP_NOACTIVATE;
2273
2274         if(!bRepaint)
2275                 flags |= SWP_NOREDRAW;
2276         return NtUserSetWindowPos(hWnd, 0, X, Y, nWidth, nHeight, flags);
2277 }
2278
2279 /*
2280         QueryWindow based on KJK::Hyperion and James Tabor.
2281
2282         0 = QWUniqueProcessId
2283         1 = QWUniqueThreadId
2284         4 = QWIsHung            Implements IsHungAppWindow found
2285                                 by KJK::Hyperion.
2286
2287         9 = QWKillWindow        When I called this with hWnd ==
2288                                 DesktopWindow, it shutdown the system
2289                                 and rebooted.
2290 */
2291 /*
2292  * @implemented
2293  */
2294 DWORD STDCALL
2295 NtUserQueryWindow(HWND hWnd, DWORD Index)
2296 {
2297
2298 PWINDOW_OBJECT Window = IntGetWindowObject(hWnd);
2299
2300         if(Window == NULL) return((DWORD)NULL);
2301
2302         IntReleaseWindowObject(Window);
2303
2304         switch(Index)
2305         {
2306         case 0x00:
2307                 return((DWORD)Window->OwnerThread->ThreadsProcess->UniqueProcessId);
2308
2309         case 0x01:
2310                 return((DWORD)Window->OwnerThread->Cid.UniqueThread);
2311
2312         default:
2313                 return((DWORD)NULL);
2314         }
2315
2316 }
2317
2318
2319 /*
2320  * @unimplemented
2321  */
2322 DWORD STDCALL
2323 NtUserRealChildWindowFromPoint(DWORD Unknown0,
2324                                DWORD Unknown1,
2325                                DWORD Unknown2)
2326 {
2327   UNIMPLEMENTED
2328
2329   return 0;
2330 }
2331
2332
2333 /*
2334  * @implemented
2335  */
2336 BOOL
2337 STDCALL
2338 NtUserRedrawWindow
2339 (
2340  HWND hWnd,
2341  CONST RECT *lprcUpdate,
2342  HRGN hrgnUpdate,
2343  UINT flags
2344 )
2345 {
2346  RECT SafeUpdateRect;
2347  NTSTATUS Status;
2348  PWINDOW_OBJECT Wnd;
2349
2350  if (!(Wnd = IntGetWindowObject(hWnd)))
2351  {
2352    SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
2353    return FALSE;
2354  }
2355
2356  if(NULL != lprcUpdate)
2357  {
2358   Status = MmCopyFromCaller(&SafeUpdateRect, (PRECT)lprcUpdate, sizeof(RECT));
2359
2360   if(!NT_SUCCESS(Status))
2361   {
2362    /* FIXME: set last error */
2363    return FALSE;
2364   }
2365  }
2366
2367
2368  Status = PaintRedrawWindow
2369  (
2370   Wnd,
2371   NULL == lprcUpdate ? NULL : &SafeUpdateRect,
2372   hrgnUpdate,
2373   flags,
2374   0
2375  );
2376
2377
2378  if(!NT_SUCCESS(Status))
2379  {
2380   /* FIXME: set last error */
2381   return FALSE;
2382  }
2383  
2384  return TRUE;
2385 }
2386
2387
2388 /*
2389  * @implemented
2390  */
2391 UINT STDCALL
2392 NtUserRegisterWindowMessage(PUNICODE_STRING MessageNameUnsafe)
2393 {
2394   PLIST_ENTRY Current;
2395   PREGISTERED_MESSAGE NewMsg, RegMsg;
2396   UINT Msg = REGISTERED_MESSAGE_MIN;
2397   UNICODE_STRING MessageName;
2398   NTSTATUS Status;
2399
2400   Status = MmCopyFromCaller(&MessageName, MessageNameUnsafe, sizeof(UNICODE_STRING));
2401   if (! NT_SUCCESS(Status))
2402     {
2403       SetLastNtError(Status);
2404       return 0;
2405     }
2406
2407   NewMsg = ExAllocatePoolWithTag(PagedPool,
2408                                  sizeof(REGISTERED_MESSAGE) +
2409                                  MessageName.Length,
2410                                  TAG_WNAM);
2411   if (NULL == NewMsg)
2412     {
2413       SetLastNtError(STATUS_NO_MEMORY);
2414       return 0;
2415     }
2416
2417   Status = MmCopyFromCaller(NewMsg->MessageName, MessageName.Buffer, MessageName.Length);
2418   if (! NT_SUCCESS(Status))
2419     {
2420       ExFreePool(NewMsg);
2421       SetLastNtError(Status);
2422       return 0;
2423     }
2424   NewMsg->MessageName[MessageName.Length / sizeof(WCHAR)] = L'\0';
2425   if (wcslen(NewMsg->MessageName) != MessageName.Length / sizeof(WCHAR))
2426     {
2427       ExFreePool(NewMsg);
2428       SetLastNtError(STATUS_INVALID_PARAMETER);
2429       return 0;
2430     }
2431
2432   Current = RegisteredMessageListHead.Flink;
2433   while (Current != &RegisteredMessageListHead)
2434     {
2435       RegMsg = CONTAINING_RECORD(Current, REGISTERED_MESSAGE, ListEntry);
2436       if (0 == wcscmp(NewMsg->MessageName, RegMsg->MessageName))
2437         {
2438           ExFreePool(NewMsg);
2439           return Msg;
2440         }
2441       Msg++;
2442       Current = Current->Flink;
2443     }
2444
2445   if (REGISTERED_MESSAGE_MAX < Msg)
2446     {
2447       ExFreePool(NewMsg);
2448       SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
2449       return 0;
2450     }
2451
2452   InsertTailList(&RegisteredMessageListHead, &(NewMsg->ListEntry));
2453
2454   return Msg;
2455 }
2456
2457
2458 /*
2459  * @unimplemented
2460  */
2461 DWORD STDCALL
2462 NtUserScrollWindowEx(DWORD Unknown0,
2463                      DWORD Unknown1,
2464                      DWORD Unknown2,
2465                      DWORD Unknown3,
2466                      DWORD Unknown4,
2467                      DWORD Unknown5,
2468                      DWORD Unknown6,
2469                      DWORD Unknown7)
2470 {
2471   UNIMPLEMENTED
2472
2473   return 0;
2474 }
2475
2476
2477 /*
2478  * @implemented
2479  */
2480 HWND STDCALL
2481 NtUserSetCapture(HWND Wnd)
2482 {
2483   PWINDOW_OBJECT Window;
2484   PWINDOW_OBJECT Prev;
2485
2486   Prev = IntGetCaptureWindow();
2487
2488   if (Prev != NULL)
2489     {
2490       IntSendMessage(Prev->Self, WM_CAPTURECHANGED, 0L, (LPARAM)Wnd, FALSE);
2491     }
2492
2493   if (Wnd == NULL)
2494     {
2495       IntSetCaptureWindow(NULL);
2496     }
2497   else  
2498     {
2499       Window = IntGetWindowObject(Wnd);
2500       IntSetCaptureWindow(Window);
2501       IntReleaseWindowObject(Window);
2502     }
2503   if (Prev != NULL)
2504     {
2505       return(Prev->Self);
2506     }
2507   else
2508     {
2509       return(NULL);
2510     }
2511 }
2512
2513
2514 /*
2515  * @unimplemented
2516  */
2517 DWORD STDCALL
2518 NtUserSetImeOwnerWindow(DWORD Unknown0,
2519                         DWORD Unknown1)
2520 {
2521   UNIMPLEMENTED
2522
2523   return 0;
2524 }
2525
2526
2527 /*
2528  * @unimplemented
2529  */
2530 DWORD STDCALL
2531 NtUserSetInternalWindowPos(DWORD Unknown0,
2532                            DWORD Unknown1,
2533                            DWORD Unknown2,
2534                            DWORD Unknown3)
2535 {
2536   UNIMPLEMENTED
2537
2538   return 0;
2539
2540 }
2541
2542
2543 /*
2544  * @unimplemented
2545  */
2546 DWORD STDCALL
2547 NtUserSetLayeredWindowAttributes(DWORD Unknown0,
2548                                  DWORD Unknown1,
2549                                  DWORD Unknown2,
2550                                  DWORD Unknown3)
2551 {
2552   UNIMPLEMENTED
2553
2554   return 0;
2555 }
2556
2557
2558 /*
2559  * @unimplemented
2560  */
2561 DWORD STDCALL
2562 NtUserSetLogonNotifyWindow(DWORD Unknown0)
2563 {
2564   UNIMPLEMENTED
2565
2566   return 0;
2567 }
2568
2569
2570 /*
2571  * @implemented
2572  */
2573 BOOL STDCALL
2574 NtUserSetMenu(
2575   HWND hWnd,
2576   HMENU hMenu,
2577   BOOL bRepaint)
2578 {
2579   PWINDOW_OBJECT WindowObject;
2580   PMENU_OBJECT MenuObject;
2581   WindowObject = IntGetWindowObject((HWND)hWnd);
2582   if(!WindowObject)
2583   {
2584     SetLastWin32Error(ERROR_INVALID_HANDLE);
2585     return FALSE;
2586   }
2587   
2588   if(hMenu)
2589   {
2590     /* assign new menu handle */
2591     MenuObject = IntGetMenuObject((HWND)hMenu);
2592     if(!MenuObject)
2593     {
2594       IntReleaseWindowObject(WindowObject);
2595       SetLastWin32Error(ERROR_INVALID_MENU_HANDLE);
2596       return FALSE;
2597     }
2598     
2599     WindowObject->IDMenu = (UINT)hMenu;
2600     
2601     IntReleaseMenuObject(MenuObject);
2602   }
2603   else
2604   {
2605     /* remove the menu handle */
2606     WindowObject->IDMenu = 0;
2607   }
2608   
2609   IntReleaseWindowObject(WindowObject);
2610   
2611   /* FIXME (from wine)
2612   if(bRepaint)
2613   {
2614     if (IsWindowVisible(hWnd))
2615         SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
2616                       SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
2617   }
2618   */
2619   
2620   return TRUE;
2621 }
2622
2623
2624 /*
2625  * @implemented
2626  */
2627 HWND
2628 STDCALL
2629 NtUserSetParent(HWND hWndChild, HWND hWndNewParent)
2630 {
2631   PWINDOW_OBJECT Wnd = NULL, WndParent = NULL, WndOldParent;
2632   HWND hWndOldParent;
2633
2634   if (IntIsBroadcastHwnd(hWndChild) || IntIsBroadcastHwnd(hWndNewParent))
2635   {
2636     SetLastWin32Error(ERROR_INVALID_PARAMETER);
2637     return NULL;
2638   }
2639   
2640   IntAcquireWinLockExclusive();
2641   if (hWndNewParent)
2642   {
2643     if (!(WndParent = IntGetWindowObject(hWndNewParent)))
2644     {
2645       IntReleaseWinLock();
2646       SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
2647       return NULL;
2648     }
2649   }
2650
2651   if (!(Wnd = IntGetWindowObject(hWndNewParent)))
2652   {
2653     IntReleaseWinLock();
2654     SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
2655     return NULL;
2656   }
2657
2658   WndOldParent = IntSetParent(Wnd, WndParent);
2659   if (WndOldParent) hWndOldParent = WndOldParent->Self;
2660
2661   IntReleaseWinLock();
2662
2663   return hWndOldParent;    
2664 }
2665
2666
2667 /*
2668  * @implemented
2669  */
2670 DWORD STDCALL
2671 NtUserSetShellWindowEx(HWND hwndShell, HWND hwndShellListView)
2672 {
2673         PEPROCESS my_current = IoGetCurrentProcess();
2674
2675          /* test if we are permitted to change the shell window */
2676         if (pidShellWindow && my_current->UniqueProcessId!=pidShellWindow)
2677                 return FALSE;
2678
2679         hwndShellWindow = hwndShell;
2680         hwndShellListView = hwndShellListView;
2681
2682         if (hwndShell)
2683                 pidShellWindow = my_current->UniqueProcessId;   /* request shell window for the calling process */
2684         else
2685                 pidShellWindow = 0;     /* shell window is now free for other processes. */
2686
2687         return TRUE;
2688 }
2689
2690
2691 /*
2692  * @implemented
2693  */
2694 BOOL STDCALL
2695 NtUserSetSystemMenu(
2696   HWND hWnd,
2697   HMENU hMenu)
2698 {
2699   BOOL res = FALSE;
2700   PWINDOW_OBJECT WindowObject;
2701   PMENU_OBJECT MenuObject;
2702   WindowObject = IntGetWindowObject((HWND)hWnd);
2703   if(!WindowObject)
2704   {
2705     SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
2706     return FALSE;
2707   }
2708   
2709   if(hMenu)
2710   {
2711     /* assign new menu handle */
2712     MenuObject = IntGetMenuObject(hMenu);
2713     if(!MenuObject)
2714     {
2715       IntReleaseWindowObject(WindowObject);
2716       SetLastWin32Error(ERROR_INVALID_MENU_HANDLE);
2717       return FALSE;
2718     }
2719     
2720     res = IntSetSystemMenu(WindowObject, MenuObject);
2721     
2722     IntReleaseMenuObject(MenuObject);
2723   }
2724   
2725   IntReleaseWindowObject(WindowObject);
2726   return res;
2727 }
2728
2729
2730 /*
2731  * @unimplemented
2732  */
2733 DWORD STDCALL
2734 NtUserSetWindowFNID(DWORD Unknown0,
2735                     DWORD Unknown1)
2736 {
2737   UNIMPLEMENTED
2738
2739   return 0;
2740 }
2741
2742
2743 /*
2744  * @implemented
2745  */
2746 LONG STDCALL
2747 NtUserSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi)
2748 {
2749   PWINDOW_OBJECT WindowObject;
2750   NTSTATUS Status;
2751   LONG OldValue;
2752   STYLESTRUCT Style;
2753
2754   Status = 
2755     ObmReferenceObjectByHandle(PsGetWin32Process()->WindowStation->HandleTable,
2756                                hWnd,
2757                                otWindow,
2758                                (PVOID*)&WindowObject);
2759   if (!NT_SUCCESS(Status))
2760     {
2761       SetLastWin32Error(ERROR_INVALID_HANDLE);
2762       return(0);
2763     }
2764
2765   if (0 <= (int) Index)
2766     {
2767       if (WindowObject->ExtraDataSize - sizeof(LONG) < Index ||
2768           0 != Index % sizeof(LONG))
2769         {
2770           SetLastWin32Error(ERROR_INVALID_PARAMETER);
2771           return 0;
2772         }
2773       OldValue = WindowObject->ExtraData[Index / sizeof(LONG)];
2774       WindowObject->ExtraData[Index / sizeof(LONG)] = NewValue;
2775     }
2776   else
2777     {
2778       switch (Index)
2779         {
2780         case GWL_EXSTYLE:
2781           OldValue = (LONG) WindowObject->ExStyle;
2782           Style.styleOld = OldValue;
2783           Style.styleNew = NewValue;
2784           IntSendSTYLECHANGINGMessage(hWnd, GWL_EXSTYLE, &Style);
2785           WindowObject->ExStyle = (DWORD)Style.styleNew;
2786           IntSendSTYLECHANGEDMessage(hWnd, GWL_EXSTYLE, &Style);
2787           break;
2788
2789         case GWL_STYLE:
2790           OldValue = (LONG) WindowObject->Style;
2791           Style.styleOld = OldValue;
2792           Style.styleNew = NewValue;
2793           IntSendSTYLECHANGINGMessage(hWnd, GWL_STYLE, &Style);
2794           WindowObject->Style = (DWORD)Style.styleNew;
2795           IntSendSTYLECHANGEDMessage(hWnd, GWL_STYLE, &Style);
2796           break;
2797
2798         case GWL_WNDPROC:
2799           /* FIXME: should check if window belongs to current process */
2800           if (Ansi)
2801           {
2802             OldValue = (LONG) WindowObject->WndProcA;
2803             WindowObject->WndProcA = (WNDPROC) NewValue;
2804                 WindowObject->WndProcW = (WNDPROC) NewValue+0x80000000;
2805                 WindowObject->Unicode = FALSE;
2806           }
2807           else
2808           {
2809             OldValue = (LONG) WindowObject->WndProcW;
2810             WindowObject->WndProcW = (WNDPROC) NewValue;
2811                 WindowObject->WndProcA = (WNDPROC) NewValue+0x80000000;
2812                 WindowObject->Unicode = TRUE;
2813           }
2814           break;
2815
2816         case GWL_HINSTANCE:
2817           OldValue = (LONG) WindowObject->Instance;
2818           WindowObject->Instance = (HINSTANCE) NewValue;
2819           break;
2820
2821         case GWL_HWNDPARENT:
2822           OldValue = (LONG) WindowObject->ParentHandle;
2823           WindowObject->ParentHandle = (HWND) NewValue;
2824           /* FIXME: Need to update window lists of old and new parent */
2825           UNIMPLEMENTED;
2826           break;
2827
2828         case GWL_ID:
2829           OldValue = (LONG) WindowObject->IDMenu;
2830           WindowObject->IDMenu = (UINT) NewValue;
2831           break;
2832
2833         case GWL_USERDATA:
2834           OldValue = WindowObject->UserData;
2835           WindowObject->UserData = NewValue;
2836           break;
2837     
2838         default:
2839           DPRINT1("NtUserSetWindowLong(): Unsupported index %d\n", Index);
2840           SetLastWin32Error(ERROR_INVALID_PARAMETER);
2841           OldValue = 0;
2842           break;
2843         }
2844     }
2845
2846   ObmDereferenceObject(WindowObject);
2847   return(OldValue);
2848 }
2849
2850
2851 /*
2852  * @unimplemented
2853  */
2854 DWORD STDCALL
2855 NtUserSetWindowPlacement(DWORD Unknown0,
2856                          DWORD Unknown1)
2857 {
2858   UNIMPLEMENTED
2859
2860   return 0;
2861 }
2862
2863
2864 /*
2865  * @implemented
2866  */
2867 BOOL STDCALL
2868 NtUserSetWindowPos(      
2869     HWND hWnd,
2870     HWND hWndInsertAfter,
2871     int X,
2872     int Y,
2873     int cx,
2874     int cy,
2875     UINT uFlags)
2876 {
2877   return WinPosSetWindowPos(hWnd, hWndInsertAfter, X, Y, cx, cy, uFlags);
2878 }
2879
2880
2881 /*
2882  * @unimplemented
2883  */
2884 DWORD STDCALL
2885 NtUserSetWindowRgn(DWORD Unknown0,
2886                    DWORD Unknown1,
2887                    DWORD Unknown2)
2888 {
2889   UNIMPLEMENTED
2890
2891   return 0;
2892 }
2893
2894
2895 /*
2896  * @unimplemented
2897  */
2898 WORD STDCALL
2899 NtUserSetWindowWord(HWND hWnd, INT Index, WORD NewVal)
2900 {
2901   UNIMPLEMENTED
2902   return 0;
2903 }
2904
2905
2906 /*
2907  * @implemented
2908  */
2909 BOOL STDCALL
2910 NtUserShowWindow(HWND hWnd,
2911                  LONG nCmdShow)
2912 {
2913   return(WinPosShowWindow(hWnd, nCmdShow));
2914 }
2915
2916
2917 /*
2918  * @unimplemented
2919  */
2920 DWORD STDCALL
2921 NtUserShowWindowAsync(DWORD Unknown0,
2922                       DWORD Unknown1)
2923 {
2924   UNIMPLEMENTED
2925
2926   return 0;
2927 }
2928
2929
2930 /*
2931  * @implemented
2932  */
2933 BOOL STDCALL
2934 NtUserUpdateWindow(HWND hWnd)
2935 {
2936     PWINDOW_OBJECT pWindow = IntGetWindowObject( hWnd);
2937
2938     if (!pWindow)
2939         return FALSE;
2940     if (pWindow->UpdateRegion)
2941         NtUserSendMessage( hWnd, WM_PAINT,0,0);
2942     IntReleaseWindowObject(pWindow);
2943     return TRUE;
2944 }
2945
2946
2947 /*
2948  * @unimplemented
2949  */
2950 DWORD STDCALL
2951 NtUserUpdateLayeredWindow(DWORD Unknown0,
2952                           DWORD Unknown1,
2953                           DWORD Unknown2,
2954                           DWORD Unknown3,
2955                           DWORD Unknown4,
2956                           DWORD Unknown5,
2957                           DWORD Unknown6,
2958                           DWORD Unknown7,
2959                           DWORD Unknown8)
2960 {
2961   UNIMPLEMENTED
2962
2963   return 0;
2964 }
2965
2966
2967 /*
2968  * @implemented
2969  */
2970 VOID STDCALL
2971 NtUserValidateRect(HWND hWnd, const RECT* Rect)
2972 {
2973   return (VOID)NtUserRedrawWindow(hWnd, Rect, 0, RDW_VALIDATE | RDW_NOCHILDREN);
2974 }
2975
2976
2977 /*
2978  * @unimplemented
2979  */
2980 DWORD STDCALL
2981 NtUserWindowFromPoint(DWORD Unknown0,
2982                       DWORD Unknown1)
2983 {
2984   UNIMPLEMENTED
2985
2986   return 0;
2987 }
2988
2989 /* EOF */