Fix the strange case in WIN_FixCoordinates where x and cx are not
[wine] / windows / win.c
1 /*
2  * Window related functions
3  *
4  * Copyright 1993, 1994 Alexandre Julliard
5  */
6
7 #include <assert.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include "windef.h"
11 #include "wine/winbase16.h"
12 #include "wine/winuser16.h"
13 #include "wine/server.h"
14 #include "wine/unicode.h"
15 #include "win.h"
16 #include "user.h"
17 #include "dce.h"
18 #include "controls.h"
19 #include "cursoricon.h"
20 #include "hook.h"
21 #include "message.h"
22 #include "queue.h"
23 #include "task.h"
24 #include "winpos.h"
25 #include "winerror.h"
26 #include "stackframe.h"
27 #include "debugtools.h"
28
29 DEFAULT_DEBUG_CHANNEL(win);
30 DECLARE_DEBUG_CHANNEL(msg);
31
32 #define NB_USER_HANDLES  (LAST_USER_HANDLE - FIRST_USER_HANDLE + 1)
33
34 /**********************************************************************/
35
36 /* Desktop window */
37 static WND *pWndDesktop = NULL;
38
39 static WORD wDragWidth = 4;
40 static WORD wDragHeight= 3;
41
42 static void *user_handles[NB_USER_HANDLES];
43
44 /* thread safeness */
45 extern SYSLEVEL USER_SysLevel;  /* FIXME */
46
47 /***********************************************************************
48  *           WIN_SuspendWndsLock
49  *
50  *   Suspend the lock on WND structures.
51  *   Returns the number of locks suspended
52  */
53 int WIN_SuspendWndsLock( void )
54 {
55     int isuspendedLocks = _ConfirmSysLevel( &USER_SysLevel );
56     int count = isuspendedLocks;
57
58     while ( count-- > 0 )
59         _LeaveSysLevel( &USER_SysLevel );
60
61     return isuspendedLocks;
62 }
63
64 /***********************************************************************
65  *           WIN_RestoreWndsLock
66  *
67  *  Restore the suspended locks on WND structures
68  */
69 void WIN_RestoreWndsLock( int ipreviousLocks )
70 {
71     while ( ipreviousLocks-- > 0 )
72         _EnterSysLevel( &USER_SysLevel );
73 }
74
75 /***********************************************************************
76  *           create_window_handle
77  *
78  * Create a window handle with the server.
79  */
80 static WND *create_window_handle( HWND parent, HWND owner, ATOM atom, INT size )
81 {
82     BOOL res;
83     user_handle_t handle = 0;
84     WORD index;
85     WND *win = HeapAlloc( GetProcessHeap(), 0, size );
86
87     if (!win) return NULL;
88
89     USER_Lock();
90
91     SERVER_START_REQ( create_window )
92     {
93         req->parent = parent;
94         req->owner = owner;
95         req->atom = atom;
96         if ((res = !wine_server_call_err( req ))) handle = reply->handle;
97     }
98     SERVER_END_REQ;
99
100     if (!res)
101     {
102         USER_Unlock();
103         HeapFree( GetProcessHeap(), 0, win );
104         return NULL;
105     }
106     index = LOWORD(handle) - FIRST_USER_HANDLE;
107     assert( index < NB_USER_HANDLES );
108     user_handles[index] = win;
109     win->hwndSelf = handle;
110     win->dwMagic = WND_MAGIC;
111     win->irefCount = 1;
112     return win;
113 }
114
115
116 /***********************************************************************
117  *           free_window_handle
118  *
119  * Free a window handle.
120  */
121 static WND *free_window_handle( HWND hwnd )
122 {
123     WND *ptr;
124     WORD index = LOWORD(hwnd) - FIRST_USER_HANDLE;
125
126     if (index >= NB_USER_HANDLES) return NULL;
127     USER_Lock();
128     if ((ptr = user_handles[index]))
129     {
130         SERVER_START_REQ( destroy_window )
131         {
132             req->handle = hwnd;
133             if (!wine_server_call_err( req ))
134                 user_handles[index] = NULL;
135             else
136                 ptr = NULL;
137         }
138         SERVER_END_REQ;
139     }
140     USER_Unlock();
141     if (ptr) HeapFree( GetProcessHeap(), 0, ptr );
142     return ptr;
143 }
144
145
146 /*******************************************************************
147  *           list_window_children
148  *
149  * Build an array of the children of a given window. The array must be
150  * freed with HeapFree. Returns NULL when no windows are found.
151  */
152 static HWND *list_window_children( HWND hwnd, ATOM atom, DWORD tid )
153 {
154     HWND *list;
155     int size = 32;
156
157     for (;;)
158     {
159         int count = 0;
160
161         if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) break;
162
163         SERVER_START_REQ( get_window_children )
164         {
165             req->parent = hwnd;
166             req->atom = atom;
167             req->tid = (void *)tid;
168             wine_server_set_reply( req, list, (size-1) * sizeof(HWND) );
169             if (!wine_server_call( req )) count = reply->count;
170         }
171         SERVER_END_REQ;
172         if (count && count < size)
173         {
174             list[count] = 0;
175             return list;
176         }
177         HeapFree( GetProcessHeap(), 0, list );
178         if (!count) break;
179         size = count + 1;  /* restart with a large enough buffer */
180     }
181     return NULL;
182 }
183
184
185 /*******************************************************************
186  *           send_parent_notify
187  */
188 static void send_parent_notify( HWND hwnd, UINT msg )
189 {
190     if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD)) return;
191     if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOPARENTNOTIFY) return;
192     SendMessageW( GetParent(hwnd), WM_PARENTNOTIFY,
193                   MAKEWPARAM( msg, GetWindowLongW( hwnd, GWL_ID )), (LPARAM)hwnd );
194 }
195
196
197 /*******************************************************************
198  *              get_server_window_text
199  *
200  * Retrieve the window text from the server.
201  */
202 static void get_server_window_text( HWND hwnd, LPWSTR text, INT count )
203 {
204     size_t len = 0;
205
206     SERVER_START_REQ( get_window_text )
207     {
208         req->handle = hwnd;
209         wine_server_set_reply( req, text, (count - 1) * sizeof(WCHAR) );
210         if (!wine_server_call_err( req )) len = wine_server_reply_size(reply);
211     }
212     SERVER_END_REQ;
213     text[len / sizeof(WCHAR)] = 0;
214 }
215
216
217 /***********************************************************************
218  *           WIN_GetPtr
219  *
220  * Return a pointer to the WND structure if local to the process,
221  * or WND_OTHER_PROCESS is handle may be valid in other process.
222  * If ret value is a valid pointer, it must be released with WIN_ReleasePtr.
223  */
224 WND *WIN_GetPtr( HWND hwnd )
225 {
226     WND * ptr;
227     WORD index = LOWORD(hwnd) - FIRST_USER_HANDLE;
228
229     if (index >= NB_USER_HANDLES) return NULL;
230
231     USER_Lock();
232     if ((ptr = user_handles[index]))
233     {
234         if (ptr->dwMagic == WND_MAGIC && (!HIWORD(hwnd) || hwnd == ptr->hwndSelf))
235             return ptr;
236         ptr = NULL;
237     }
238     else ptr = WND_OTHER_PROCESS;
239     USER_Unlock();
240     return ptr;
241 }
242
243
244 /***********************************************************************
245  *           WIN_IsCurrentProcess
246  *
247  * Check whether a given window belongs to the current process (and return the full handle).
248  */
249 HWND WIN_IsCurrentProcess( HWND hwnd )
250 {
251     WND *ptr;
252     HWND ret;
253
254     if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS) return 0;
255     ret = ptr->hwndSelf;
256     WIN_ReleasePtr( ptr );
257     return ret;
258 }
259
260
261 /***********************************************************************
262  *           WIN_IsCurrentThread
263  *
264  * Check whether a given window belongs to the current thread (and return the full handle).
265  */
266 HWND WIN_IsCurrentThread( HWND hwnd )
267 {
268     WND *ptr;
269     HWND ret = 0;
270
271     if ((ptr = WIN_GetPtr( hwnd )) && ptr != WND_OTHER_PROCESS)
272     {
273         if (ptr->tid == GetCurrentThreadId()) ret = ptr->hwndSelf;
274         WIN_ReleasePtr( ptr );
275     }
276     return ret;
277 }
278
279
280 /***********************************************************************
281  *           WIN_Handle32
282  *
283  * Convert a 16-bit window handle to a full 32-bit handle.
284  */
285 HWND WIN_Handle32( HWND16 hwnd16 )
286 {
287     WND *ptr;
288     HWND hwnd = (HWND)(ULONG_PTR)hwnd16;
289
290     if (hwnd16 <= 1 || hwnd16 == 0xffff) return hwnd;
291     /* do sign extension for -2 and -3 */
292     if (hwnd16 >= (HWND16)-3) return (HWND)(LONG_PTR)(INT16)hwnd16;
293
294     if (!(ptr = WIN_GetPtr( hwnd ))) return hwnd;
295
296     if (ptr != WND_OTHER_PROCESS)
297     {
298         hwnd = ptr->hwndSelf;
299         WIN_ReleasePtr( ptr );
300     }
301     else  /* may belong to another process */
302     {
303         SERVER_START_REQ( get_window_info )
304         {
305             req->handle = hwnd;
306             if (!wine_server_call_err( req )) hwnd = reply->full_handle;
307         }
308         SERVER_END_REQ;
309     }
310     return hwnd;
311 }
312
313
314 /***********************************************************************
315  *           WIN_FindWndPtr
316  *
317  * Return a pointer to the WND structure corresponding to a HWND.
318  */
319 WND * WIN_FindWndPtr( HWND hwnd )
320 {
321     WND * ptr;
322
323     if (!hwnd) return NULL;
324
325     if ((ptr = WIN_GetPtr( hwnd )))
326     {
327         if (ptr != WND_OTHER_PROCESS)
328         {
329             /* increment destruction monitoring */
330             ptr->irefCount++;
331             return ptr;
332         }
333         if (IsWindow( hwnd )) /* check other processes */
334         {
335             ERR( "window %04x belongs to other process\n", hwnd );
336             /* DbgBreakPoint(); */
337         }
338     }
339     SetLastError( ERROR_INVALID_WINDOW_HANDLE );
340     return NULL;
341 }
342
343
344 /***********************************************************************
345  *           WIN_ReleaseWndPtr
346  *
347  * Release the pointer to the WND structure.
348  */
349 void WIN_ReleaseWndPtr(WND *wndPtr)
350 {
351     if(!wndPtr) return;
352
353     /* Decrement destruction monitoring value */
354      wndPtr->irefCount--;
355      /* Check if it's time to release the memory */
356      if(wndPtr->irefCount == 0 && !wndPtr->dwMagic)
357      {
358          /* Release memory */
359          free_window_handle( wndPtr->hwndSelf );
360      }
361      else if(wndPtr->irefCount < 0)
362      {
363          /* This else if is useful to monitor the WIN_ReleaseWndPtr function */
364          ERR("forgot a Lock on %p somewhere\n",wndPtr);
365      }
366      /* unlock all WND structures for thread safeness */
367      USER_Unlock();
368 }
369
370
371 /***********************************************************************
372  *           WIN_UnlinkWindow
373  *
374  * Remove a window from the siblings linked list.
375  */
376 void WIN_UnlinkWindow( HWND hwnd )
377 {
378     WIN_LinkWindow( hwnd, 0, 0 );
379 }
380
381
382 /***********************************************************************
383  *           WIN_LinkWindow
384  *
385  * Insert a window into the siblings linked list.
386  * The window is inserted after the specified window, which can also
387  * be specified as HWND_TOP or HWND_BOTTOM.
388  * If parent is 0, window is unlinked from the tree.
389  */
390 void WIN_LinkWindow( HWND hwnd, HWND parent, HWND hwndInsertAfter )
391 {
392     WND *wndPtr = WIN_GetPtr( hwnd );
393
394     if (!wndPtr) return;
395     if (wndPtr == WND_OTHER_PROCESS)
396     {
397         if (IsWindow(hwnd)) ERR(" cannot link other process window %x\n", hwnd );
398         return;
399     }
400
401     SERVER_START_REQ( link_window )
402     {
403         req->handle   = hwnd;
404         req->parent   = parent;
405         req->previous = hwndInsertAfter;
406         if (!wine_server_call( req ))
407         {
408             if (reply->full_parent && reply->full_parent != wndPtr->parent)
409             {
410                 wndPtr->owner = 0;  /* reset owner when changing parent */
411                 wndPtr->parent = reply->full_parent;
412             }
413         }
414
415     }
416     SERVER_END_REQ;
417     WIN_ReleasePtr( wndPtr );
418 }
419
420
421 /***********************************************************************
422  *           WIN_SetOwner
423  *
424  * Change the owner of a window.
425  */
426 void WIN_SetOwner( HWND hwnd, HWND owner )
427 {
428     WND *win = WIN_GetPtr( hwnd );
429
430     if (!win) return;
431     if (win == WND_OTHER_PROCESS)
432     {
433         if (IsWindow(hwnd)) ERR( "cannot set owner %x on other process window %x\n", owner, hwnd );
434         return;
435     }
436     SERVER_START_REQ( set_window_owner )
437     {
438         req->handle = hwnd;
439         req->owner  = owner;
440         if (!wine_server_call( req )) win->owner = reply->full_owner;
441     }
442     SERVER_END_REQ;
443     WIN_ReleasePtr( win );
444 }
445
446
447 /***********************************************************************
448  *           WIN_SetStyle
449  *
450  * Change the style of a window.
451  */
452 LONG WIN_SetStyle( HWND hwnd, LONG style )
453 {
454     BOOL ok;
455     LONG ret = 0;
456     WND *win = WIN_GetPtr( hwnd );
457
458     if (!win) return 0;
459     if (win == WND_OTHER_PROCESS)
460     {
461         if (IsWindow(hwnd))
462             ERR( "cannot set style %lx on other process window %x\n", style, hwnd );
463         return 0;
464     }
465     if (style == win->dwStyle)
466     {
467         WIN_ReleasePtr( win );
468         return style;
469     }
470     SERVER_START_REQ( set_window_info )
471     {
472         req->handle = hwnd;
473         req->flags  = SET_WIN_STYLE;
474         req->style  = style;
475         if ((ok = !wine_server_call( req )))
476         {
477             ret = reply->old_style;
478             win->dwStyle = style;
479         }
480     }
481     SERVER_END_REQ;
482     WIN_ReleasePtr( win );
483     if (ok && USER_Driver.pSetWindowStyle) USER_Driver.pSetWindowStyle( hwnd, ret );
484     return ret;
485 }
486
487
488 /***********************************************************************
489  *           WIN_SetExStyle
490  *
491  * Change the extended style of a window.
492  */
493 LONG WIN_SetExStyle( HWND hwnd, LONG style )
494 {
495     LONG ret = 0;
496     WND *win = WIN_GetPtr( hwnd );
497
498     if (!win) return 0;
499     if (win == WND_OTHER_PROCESS)
500     {
501         if (IsWindow(hwnd))
502             ERR( "cannot set exstyle %lx on other process window %x\n", style, hwnd );
503         return 0;
504     }
505     if (style == win->dwExStyle)
506     {
507         WIN_ReleasePtr( win );
508         return style;
509     }
510     SERVER_START_REQ( set_window_info )
511     {
512         req->handle   = hwnd;
513         req->flags    = SET_WIN_EXSTYLE;
514         req->ex_style = style;
515         if (!wine_server_call( req ))
516         {
517             ret = reply->old_ex_style;
518             win->dwExStyle = style;
519         }
520     }
521     SERVER_END_REQ;
522     WIN_ReleasePtr( win );
523     return ret;
524 }
525
526
527 /***********************************************************************
528  *           WIN_SetRectangles
529  *
530  * Set the window and client rectangles.
531  */
532 void WIN_SetRectangles( HWND hwnd, const RECT *rectWindow, const RECT *rectClient )
533 {
534     WND *win = WIN_GetPtr( hwnd );
535     BOOL ret;
536
537     if (!win) return;
538     if (win == WND_OTHER_PROCESS)
539     {
540         if (IsWindow( hwnd )) ERR( "cannot set rectangles of other process window %x\n", hwnd );
541         return;
542     }
543     SERVER_START_REQ( set_window_rectangles )
544     {
545         req->handle        = hwnd;
546         req->window.left   = rectWindow->left;
547         req->window.top    = rectWindow->top;
548         req->window.right  = rectWindow->right;
549         req->window.bottom = rectWindow->bottom;
550         req->client.left   = rectClient->left;
551         req->client.top    = rectClient->top;
552         req->client.right  = rectClient->right;
553         req->client.bottom = rectClient->bottom;
554         ret = !wine_server_call( req );
555     }
556     SERVER_END_REQ;
557     if (ret)
558     {
559         win->rectWindow = *rectWindow;
560         win->rectClient = *rectClient;
561
562         TRACE( "win %x window (%d,%d)-(%d,%d) client (%d,%d)-(%d,%d)\n", hwnd,
563                rectWindow->left, rectWindow->top, rectWindow->right, rectWindow->bottom,
564                rectClient->left, rectClient->top, rectClient->right, rectClient->bottom );
565     }
566     WIN_ReleasePtr( win );
567 }
568
569
570 /***********************************************************************
571  *           WIN_GetRectangles
572  *
573  * Get the window and client rectangles.
574  */
575 BOOL WIN_GetRectangles( HWND hwnd, RECT *rectWindow, RECT *rectClient )
576 {
577     WND *win = WIN_GetPtr( hwnd );
578     BOOL ret = TRUE;
579
580     if (!win) return FALSE;
581     if (win == WND_OTHER_PROCESS)
582     {
583         SERVER_START_REQ( get_window_rectangles )
584         {
585             req->handle = hwnd;
586             if ((ret = !wine_server_call( req )))
587             {
588                 if (rectWindow)
589                 {
590                     rectWindow->left   = reply->window.left;
591                     rectWindow->top    = reply->window.top;
592                     rectWindow->right  = reply->window.right;
593                     rectWindow->bottom = reply->window.bottom;
594                 }
595                 if (rectClient)
596                 {
597                     rectClient->left   = reply->client.left;
598                     rectClient->top    = reply->client.top;
599                     rectClient->right  = reply->client.right;
600                     rectClient->bottom = reply->client.bottom;
601                 }
602             }
603         }
604         SERVER_END_REQ;
605     }
606     else
607     {
608         if (rectWindow) *rectWindow = win->rectWindow;
609         if (rectClient) *rectClient = win->rectClient;
610         WIN_ReleasePtr( win );
611     }
612     return ret;
613 }
614
615
616 /***********************************************************************
617  *           WIN_DestroyWindow
618  *
619  * Destroy storage associated to a window. "Internals" p.358
620  */
621 LRESULT WIN_DestroyWindow( HWND hwnd )
622 {
623     WND *wndPtr;
624     HWND *list;
625
626     TRACE("%04x\n", hwnd );
627
628     if (!(hwnd = WIN_IsCurrentThread( hwnd )))
629     {
630         ERR( "window doesn't belong to current thread\n" );
631         return 0;
632     }
633
634     /* free child windows */
635     if ((list = WIN_ListChildren( hwnd )))
636     {
637         int i;
638         for (i = 0; list[i]; i++)
639         {
640             if (WIN_IsCurrentThread( list[i] )) WIN_DestroyWindow( list[i] );
641             else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
642         }
643         HeapFree( GetProcessHeap(), 0, list );
644     }
645
646     /*
647      * Clear the update region to make sure no WM_PAINT messages will be
648      * generated for this window while processing the WM_NCDESTROY.
649      */
650     RedrawWindow( hwnd, NULL, 0,
651                   RDW_VALIDATE | RDW_NOFRAME | RDW_NOERASE | RDW_NOINTERNALPAINT | RDW_NOCHILDREN);
652
653     /*
654      * Send the WM_NCDESTROY to the window being destroyed.
655      */
656     SendMessageA( hwnd, WM_NCDESTROY, 0, 0);
657
658     /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
659
660     WINPOS_CheckInternalPos( hwnd );
661     if( hwnd == GetCapture()) ReleaseCapture();
662
663     /* free resources associated with the window */
664
665     TIMER_RemoveWindowTimers( hwnd );
666
667     if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
668     wndPtr->hmemTaskQ = 0;
669
670     if (!(wndPtr->dwStyle & WS_CHILD))
671     {
672         HMENU menu = (HMENU)SetWindowLongW( hwnd, GWL_ID, 0 );
673         if (menu) DestroyMenu( menu );
674     }
675     if (wndPtr->hSysMenu)
676     {
677         DestroyMenu( wndPtr->hSysMenu );
678         wndPtr->hSysMenu = 0;
679     }
680     USER_Driver.pDestroyWindow( hwnd );
681     DCE_FreeWindowDCE( hwnd );    /* Always do this to catch orphaned DCs */
682     WINPROC_FreeProc( wndPtr->winproc, WIN_PROC_WINDOW );
683     CLASS_RemoveWindow( wndPtr->class );
684     wndPtr->class = NULL;
685     wndPtr->dwMagic = 0;  /* Mark it as invalid */
686     WIN_ReleaseWndPtr( wndPtr );
687     return 0;
688 }
689
690 /***********************************************************************
691  *           WIN_DestroyThreadWindows
692  *
693  * Destroy all children of 'wnd' owned by the current thread.
694  * Return TRUE if something was done.
695  */
696 void WIN_DestroyThreadWindows( HWND hwnd )
697 {
698     HWND *list;
699     int i;
700
701     if (!(list = WIN_ListChildren( hwnd ))) return;
702     for (i = 0; list[i]; i++)
703     {
704         if (WIN_IsCurrentThread( list[i] ))
705             DestroyWindow( list[i] );
706         else
707             WIN_DestroyThreadWindows( list[i] );
708     }
709     HeapFree( GetProcessHeap(), 0, list );
710 }
711
712 /***********************************************************************
713  *           WIN_CreateDesktopWindow
714  *
715  * Create the desktop window.
716  */
717 BOOL WIN_CreateDesktopWindow(void)
718 {
719     struct tagCLASS *class;
720     HWND hwndDesktop;
721     INT wndExtra;
722     DWORD clsStyle;
723     WNDPROC winproc;
724     DCE *dce;
725     CREATESTRUCTA cs;
726     RECT rect;
727
728     TRACE("Creating desktop window\n");
729
730     if (!WINPOS_CreateInternalPosAtom() ||
731         !(class = CLASS_AddWindow( (ATOM)LOWORD(DESKTOP_CLASS_ATOM), 0, WIN_PROC_32W,
732                                    &wndExtra, &winproc, &clsStyle, &dce )))
733         return FALSE;
734
735     pWndDesktop = create_window_handle( 0, 0, LOWORD(DESKTOP_CLASS_ATOM),
736                                         sizeof(WND) + wndExtra - sizeof(pWndDesktop->wExtra) );
737     if (!pWndDesktop) return FALSE;
738     hwndDesktop = pWndDesktop->hwndSelf;
739
740     pWndDesktop->tid               = 0;  /* nobody owns the desktop */
741     pWndDesktop->parent            = 0;
742     pWndDesktop->owner             = 0;
743     pWndDesktop->class             = class;
744     pWndDesktop->hInstance         = 0;
745     pWndDesktop->text              = NULL;
746     pWndDesktop->hmemTaskQ         = 0;
747     pWndDesktop->hrgnUpdate        = 0;
748     pWndDesktop->hwndLastActive    = hwndDesktop;
749     pWndDesktop->dwStyle           = 0;
750     pWndDesktop->dwExStyle         = 0;
751     pWndDesktop->clsStyle          = clsStyle;
752     pWndDesktop->dce               = NULL;
753     pWndDesktop->pVScroll          = NULL;
754     pWndDesktop->pHScroll          = NULL;
755     pWndDesktop->wIDmenu           = 0;
756     pWndDesktop->helpContext       = 0;
757     pWndDesktop->flags             = 0;
758     pWndDesktop->hSysMenu          = 0;
759     pWndDesktop->userdata          = 0;
760     pWndDesktop->winproc           = winproc;
761     pWndDesktop->cbWndExtra        = wndExtra;
762
763     cs.lpCreateParams = NULL;
764     cs.hInstance      = 0;
765     cs.hMenu          = 0;
766     cs.hwndParent     = 0;
767     cs.x              = 0;
768     cs.y              = 0;
769     cs.cx             = GetSystemMetrics( SM_CXSCREEN );
770     cs.cy             = GetSystemMetrics( SM_CYSCREEN );
771     cs.style          = pWndDesktop->dwStyle;
772     cs.dwExStyle      = pWndDesktop->dwExStyle;
773     cs.lpszName       = NULL;
774     cs.lpszClass      = DESKTOP_CLASS_ATOM;
775
776     SetRect( &rect, 0, 0, cs.cx, cs.cy );
777     WIN_SetRectangles( hwndDesktop, &rect, &rect );
778     WIN_SetStyle( hwndDesktop, WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS );
779
780     if (!USER_Driver.pCreateWindow( hwndDesktop, &cs, FALSE )) return FALSE;
781
782     pWndDesktop->flags |= WIN_NEEDS_ERASEBKGND;
783     WIN_ReleaseWndPtr( pWndDesktop );
784     return TRUE;
785 }
786
787
788 /***********************************************************************
789  *           WIN_FixCoordinates
790  *
791  * Fix the coordinates - Helper for WIN_CreateWindowEx.
792  * returns default show mode in sw.
793  * Note: the feature presented as undocumented *is* in the MSDN since 1993.
794  */
795 static void WIN_FixCoordinates( CREATESTRUCTA *cs, INT *sw)
796 {
797     if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16 ||
798         cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16)
799     {
800         if (cs->style & (WS_CHILD | WS_POPUP))
801         {
802             if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16) cs->x = cs->y = 0;
803             if (cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16) cs->cx = cs->cy = 0;
804         }
805         else  /* overlapped window */
806         {
807             STARTUPINFOA info;
808
809             GetStartupInfoA( &info );
810
811             if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16)
812             {
813                 /* Never believe Microsoft's documentation... CreateWindowEx doc says
814                  * that if an overlapped window is created with WS_VISIBLE style bit
815                  * set and the x parameter is set to CW_USEDEFAULT, the system ignores
816                  * the y parameter. However, disassembling NT implementation (WIN32K.SYS)
817                  * reveals that
818                  *
819                  * 1) not only it checks for CW_USEDEFAULT but also for CW_USEDEFAULT16
820                  * 2) it does not ignore the y parameter as the docs claim; instead, it
821                  *    uses it as second parameter to ShowWindow() unless y is either
822                  *    CW_USEDEFAULT or CW_USEDEFAULT16.
823                  *
824                  * The fact that we didn't do 2) caused bogus windows pop up when wine
825                  * was running apps that were using this obscure feature. Example -
826                  * calc.exe that comes with Win98 (only Win98, it's different from
827                  * the one that comes with Win95 and NT)
828                  */
829                 if (cs->y != CW_USEDEFAULT && cs->y != CW_USEDEFAULT16) *sw = cs->y;
830                 cs->x = (info.dwFlags & STARTF_USEPOSITION) ? info.dwX : 0;
831                 cs->y = (info.dwFlags & STARTF_USEPOSITION) ? info.dwY : 0;
832             }
833
834             if (cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16)
835             {
836                 if (info.dwFlags & STARTF_USESIZE)
837                 {
838                     cs->cx = info.dwXSize;
839                     cs->cy = info.dwYSize;
840                 }
841                 else  /* if no other hint from the app, pick 3/4 of the screen real estate */
842                 {
843                     RECT r;
844                     SystemParametersInfoA( SPI_GETWORKAREA, 0, &r, 0);
845                     cs->cx = (((r.right - r.left) * 3) / 4) - cs->x;
846                     cs->cy = (((r.bottom - r.top) * 3) / 4) - cs->y;
847                 }
848             }
849         }
850     }
851     else
852     {
853         /* neither x nor cx are default. Check the y values .
854          * In the trace we see Outlook and Outlook Express using 
855          * cy set to CW_USEDEFAULT when opening the address book.
856          */
857         if (cs->cy == CW_USEDEFAULT || cs->cy == CW_USEDEFAULT16) {
858             RECT r;
859             FIXME("Strange use of CW_USEDEFAULT in nHeight\n");
860             SystemParametersInfoA( SPI_GETWORKAREA, 0, &r, 0);
861             cs->cy = (((r.bottom - r.top) * 3) / 4) - cs->y;
862         }
863     }
864 }
865
866 /***********************************************************************
867  *           dump_window_styles
868  */
869 static void dump_window_styles( DWORD style, DWORD exstyle )
870 {
871     TRACE( "style:" );
872     if(style & WS_POPUP) DPRINTF(" WS_POPUP");
873     if(style & WS_CHILD) DPRINTF(" WS_CHILD");
874     if(style & WS_MINIMIZE) DPRINTF(" WS_MINIMIZE");
875     if(style & WS_VISIBLE) DPRINTF(" WS_VISIBLE");
876     if(style & WS_DISABLED) DPRINTF(" WS_DISABLED");
877     if(style & WS_CLIPSIBLINGS) DPRINTF(" WS_CLIPSIBLINGS");
878     if(style & WS_CLIPCHILDREN) DPRINTF(" WS_CLIPCHILDREN");
879     if(style & WS_MAXIMIZE) DPRINTF(" WS_MAXIMIZE");
880     if((style & WS_CAPTION) == WS_CAPTION) DPRINTF(" WS_CAPTION");
881     else
882     {
883         if(style & WS_BORDER) DPRINTF(" WS_BORDER");
884         if(style & WS_DLGFRAME) DPRINTF(" WS_DLGFRAME");
885     }
886     if(style & WS_VSCROLL) DPRINTF(" WS_VSCROLL");
887     if(style & WS_HSCROLL) DPRINTF(" WS_HSCROLL");
888     if(style & WS_SYSMENU) DPRINTF(" WS_SYSMENU");
889     if(style & WS_THICKFRAME) DPRINTF(" WS_THICKFRAME");
890     if(style & WS_GROUP) DPRINTF(" WS_GROUP");
891     if(style & WS_TABSTOP) DPRINTF(" WS_TABSTOP");
892     if(style & WS_MINIMIZEBOX) DPRINTF(" WS_MINIMIZEBOX");
893     if(style & WS_MAXIMIZEBOX) DPRINTF(" WS_MAXIMIZEBOX");
894
895     /* FIXME: Add dumping of BS_/ES_/SBS_/LBS_/CBS_/DS_/etc. styles */
896 #define DUMPED_STYLES \
897     (WS_POPUP | \
898      WS_CHILD | \
899      WS_MINIMIZE | \
900      WS_VISIBLE | \
901      WS_DISABLED | \
902      WS_CLIPSIBLINGS | \
903      WS_CLIPCHILDREN | \
904      WS_MAXIMIZE | \
905      WS_BORDER | \
906      WS_DLGFRAME | \
907      WS_VSCROLL | \
908      WS_HSCROLL | \
909      WS_SYSMENU | \
910      WS_THICKFRAME | \
911      WS_GROUP | \
912      WS_TABSTOP | \
913      WS_MINIMIZEBOX | \
914      WS_MAXIMIZEBOX)
915
916     if(style & ~DUMPED_STYLES) DPRINTF(" %08lx", style & ~DUMPED_STYLES);
917     DPRINTF("\n");
918 #undef DUMPED_STYLES
919
920     TRACE( "exstyle:" );
921     if(exstyle & WS_EX_DLGMODALFRAME) DPRINTF(" WS_EX_DLGMODALFRAME");
922     if(exstyle & WS_EX_DRAGDETECT) DPRINTF(" WS_EX_DRAGDETECT");
923     if(exstyle & WS_EX_NOPARENTNOTIFY) DPRINTF(" WS_EX_NOPARENTNOTIFY");
924     if(exstyle & WS_EX_TOPMOST) DPRINTF(" WS_EX_TOPMOST");
925     if(exstyle & WS_EX_ACCEPTFILES) DPRINTF(" WS_EX_ACCEPTFILES");
926     if(exstyle & WS_EX_TRANSPARENT) DPRINTF(" WS_EX_TRANSPARENT");
927     if(exstyle & WS_EX_MDICHILD) DPRINTF(" WS_EX_MDICHILD");
928     if(exstyle & WS_EX_TOOLWINDOW) DPRINTF(" WS_EX_TOOLWINDOW");
929     if(exstyle & WS_EX_WINDOWEDGE) DPRINTF(" WS_EX_WINDOWEDGE");
930     if(exstyle & WS_EX_CLIENTEDGE) DPRINTF(" WS_EX_CLIENTEDGE");
931     if(exstyle & WS_EX_CONTEXTHELP) DPRINTF(" WS_EX_CONTEXTHELP");
932     if(exstyle & WS_EX_RIGHT) DPRINTF(" WS_EX_RIGHT");
933     if(exstyle & WS_EX_RTLREADING) DPRINTF(" WS_EX_RTLREADING");
934     if(exstyle & WS_EX_LEFTSCROLLBAR) DPRINTF(" WS_EX_LEFTSCROLLBAR");
935     if(exstyle & WS_EX_CONTROLPARENT) DPRINTF(" WS_EX_CONTROLPARENT");
936     if(exstyle & WS_EX_STATICEDGE) DPRINTF(" WS_EX_STATICEDGE");
937     if(exstyle & WS_EX_APPWINDOW) DPRINTF(" WS_EX_APPWINDOW");
938     if(exstyle & WS_EX_LAYERED) DPRINTF(" WS_EX_LAYERED");
939
940 #define DUMPED_EX_STYLES \
941     (WS_EX_DLGMODALFRAME | \
942      WS_EX_DRAGDETECT | \
943      WS_EX_NOPARENTNOTIFY | \
944      WS_EX_TOPMOST | \
945      WS_EX_ACCEPTFILES | \
946      WS_EX_TRANSPARENT | \
947      WS_EX_MDICHILD | \
948      WS_EX_TOOLWINDOW | \
949      WS_EX_WINDOWEDGE | \
950      WS_EX_CLIENTEDGE | \
951      WS_EX_CONTEXTHELP | \
952      WS_EX_RIGHT | \
953      WS_EX_RTLREADING | \
954      WS_EX_LEFTSCROLLBAR | \
955      WS_EX_CONTROLPARENT | \
956      WS_EX_STATICEDGE | \
957      WS_EX_APPWINDOW | \
958      WS_EX_LAYERED)
959
960     if(exstyle & ~DUMPED_EX_STYLES) DPRINTF(" %08lx", exstyle & ~DUMPED_EX_STYLES);
961     DPRINTF("\n");
962 #undef DUMPED_EX_STYLES
963 }
964
965
966 /***********************************************************************
967  *           WIN_CreateWindowEx
968  *
969  * Implementation of CreateWindowEx().
970  */
971 static HWND WIN_CreateWindowEx( CREATESTRUCTA *cs, ATOM classAtom,
972                                 WINDOWPROCTYPE type )
973 {
974     INT sw = SW_SHOW;
975     struct tagCLASS *classPtr;
976     WND *wndPtr;
977     HWND hwnd, parent, owner;
978     INT wndExtra;
979     DWORD clsStyle;
980     WNDPROC winproc;
981     DCE *dce;
982     BOOL unicode = (type == WIN_PROC_32W);
983
984     TRACE("%s %s ex=%08lx style=%08lx %d,%d %dx%d parent=%04x menu=%04x inst=%08x params=%p\n",
985           (type == WIN_PROC_32W) ? debugres_w((LPWSTR)cs->lpszName) : debugres_a(cs->lpszName),
986           (type == WIN_PROC_32W) ? debugres_w((LPWSTR)cs->lpszClass) : debugres_a(cs->lpszClass),
987           cs->dwExStyle, cs->style, cs->x, cs->y, cs->cx, cs->cy,
988           cs->hwndParent, cs->hMenu, cs->hInstance, cs->lpCreateParams );
989
990     if(TRACE_ON(win)) dump_window_styles( cs->style, cs->dwExStyle );
991
992     TRACE("winproc type is %d (%s)\n", type, (type == WIN_PROC_16) ? "WIN_PROC_16" :
993             ((type == WIN_PROC_32A) ? "WIN_PROC_32A" : "WIN_PROC_32W") );
994
995     /* Find the parent window */
996
997     parent = GetDesktopWindow();
998     owner = 0;
999     if (cs->hwndParent)
1000     {
1001         /* Make sure parent is valid */
1002         if (!IsWindow( cs->hwndParent ))
1003         {
1004             WARN("Bad parent %04x\n", cs->hwndParent );
1005             return 0;
1006         }
1007         if (cs->style & WS_CHILD) parent = WIN_GetFullHandle(cs->hwndParent);
1008         else owner = GetAncestor( cs->hwndParent, GA_ROOT );
1009     }
1010     else if ((cs->style & WS_CHILD) && !(cs->style & WS_POPUP))
1011     {
1012         WARN("No parent for child window\n" );
1013         return 0;  /* WS_CHILD needs a parent, but WS_POPUP doesn't */
1014     }
1015
1016     /* Find the window class */
1017     if (!(classPtr = CLASS_AddWindow( classAtom, cs->hInstance, type,
1018                                       &wndExtra, &winproc, &clsStyle, &dce )))
1019     {
1020         WARN("Bad class '%s'\n", cs->lpszClass );
1021         return 0;
1022     }
1023
1024     WIN_FixCoordinates(cs, &sw); /* fix default coordinates */
1025
1026     /* Correct the window style - stage 1
1027      *
1028      * These are patches that appear to affect both the style loaded into the
1029      * WIN structure and passed in the CreateStruct to the WM_CREATE etc.
1030      *
1031      * WS_EX_WINDOWEDGE appears to be enforced based on the other styles, so
1032      * why does the user get to set it?
1033      */
1034
1035     /* This has been tested for WS_CHILD | WS_VISIBLE.  It has not been
1036      * tested for WS_POPUP
1037      */
1038     if ((cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
1039         ((!(cs->dwExStyle & WS_EX_STATICEDGE)) &&
1040           (cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
1041         cs->dwExStyle |= WS_EX_WINDOWEDGE;
1042     else
1043         cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
1044
1045     /* Create the window structure */
1046
1047     if (!(wndPtr = create_window_handle( parent, owner, classAtom,
1048                                          sizeof(*wndPtr) + wndExtra - sizeof(wndPtr->wExtra) )))
1049     {
1050         TRACE("out of memory\n" );
1051         return 0;
1052     }
1053     hwnd = wndPtr->hwndSelf;
1054
1055     /* Fill the window structure */
1056
1057     wndPtr->tid            = GetCurrentThreadId();
1058     wndPtr->owner          = owner;
1059     wndPtr->parent         = parent;
1060     wndPtr->class          = classPtr;
1061     wndPtr->winproc        = winproc;
1062     wndPtr->hInstance      = cs->hInstance;
1063     wndPtr->text           = NULL;
1064     wndPtr->hmemTaskQ      = InitThreadInput16( 0, 0 );
1065     wndPtr->hrgnUpdate     = 0;
1066     wndPtr->hrgnWnd        = 0;
1067     wndPtr->hwndLastActive = hwnd;
1068     wndPtr->dwStyle        = cs->style & ~WS_VISIBLE;
1069     wndPtr->dwExStyle      = cs->dwExStyle;
1070     wndPtr->clsStyle       = clsStyle;
1071     wndPtr->wIDmenu        = 0;
1072     wndPtr->helpContext    = 0;
1073     wndPtr->flags          = (type == WIN_PROC_16) ? 0 : WIN_ISWIN32;
1074     wndPtr->pVScroll       = NULL;
1075     wndPtr->pHScroll       = NULL;
1076     wndPtr->userdata       = 0;
1077     wndPtr->hSysMenu       = (wndPtr->dwStyle & WS_SYSMENU)
1078                              ? MENU_GetSysMenu( hwnd, 0 ) : 0;
1079     wndPtr->cbWndExtra     = wndExtra;
1080
1081     if (wndExtra) memset( wndPtr->wExtra, 0, wndExtra);
1082
1083     /* Correct the window style - stage 2 */
1084
1085     if (!(cs->style & WS_CHILD))
1086     {
1087         wndPtr->dwStyle |= WS_CLIPSIBLINGS;
1088         if (!(cs->style & WS_POPUP))
1089         {
1090             wndPtr->dwStyle |= WS_CAPTION;
1091             wndPtr->flags |= WIN_NEED_SIZE;
1092         }
1093     }
1094     SERVER_START_REQ( set_window_info )
1095     {
1096         req->handle    = hwnd;
1097         req->flags     = SET_WIN_STYLE | SET_WIN_EXSTYLE | SET_WIN_INSTANCE;
1098         req->style     = wndPtr->dwStyle;
1099         req->ex_style  = wndPtr->dwExStyle;
1100         req->instance  = (void *)wndPtr->hInstance;
1101         wine_server_call( req );
1102     }
1103     SERVER_END_REQ;
1104
1105     /* Get class or window DC if needed */
1106
1107     if (clsStyle & CS_OWNDC) wndPtr->dce = DCE_AllocDCE(hwnd,DCE_WINDOW_DC);
1108     else if (clsStyle & CS_CLASSDC) wndPtr->dce = dce;
1109     else wndPtr->dce = NULL;
1110
1111     /* Set the window menu */
1112
1113     if ((wndPtr->dwStyle & (WS_CAPTION | WS_CHILD)) == WS_CAPTION )
1114     {
1115         if (cs->hMenu) SetMenu(hwnd, cs->hMenu);
1116         else
1117         {
1118             LPCSTR menuName = (LPCSTR)GetClassLongA( hwnd, GCL_MENUNAME );
1119             if (menuName)
1120             {
1121                 if (HIWORD(cs->hInstance))
1122                     cs->hMenu = LoadMenuA(cs->hInstance,menuName);
1123                 else
1124                     cs->hMenu = LoadMenu16(cs->hInstance,menuName);
1125
1126                 if (cs->hMenu) SetMenu( hwnd, cs->hMenu );
1127             }
1128         }
1129     }
1130     else SetWindowLongW( hwnd, GWL_ID, (UINT)cs->hMenu );
1131     WIN_ReleaseWndPtr( wndPtr );
1132
1133     if (!USER_Driver.pCreateWindow( hwnd, cs, unicode))
1134     {
1135         WIN_DestroyWindow( hwnd );
1136         return 0;
1137     }
1138
1139     /* Notify the parent window only */
1140
1141     send_parent_notify( hwnd, WM_CREATE );
1142     if (!IsWindow( hwnd )) return 0;
1143
1144     if (cs->style & WS_VISIBLE)
1145     {
1146         /* in case WS_VISIBLE got set in the meantime */
1147         if (!(wndPtr = WIN_GetPtr( hwnd ))) return 0;
1148         WIN_SetStyle( hwnd, wndPtr->dwStyle & ~WS_VISIBLE );
1149         WIN_ReleasePtr( wndPtr );
1150         ShowWindow( hwnd, sw );
1151     }
1152
1153     /* Call WH_SHELL hook */
1154
1155     if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1156         HOOK_CallHooksA( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0 );
1157
1158     TRACE("created window %04x\n", hwnd);
1159     return hwnd;
1160 }
1161
1162
1163 /***********************************************************************
1164  *              CreateWindow (USER.41)
1165  */
1166 HWND16 WINAPI CreateWindow16( LPCSTR className, LPCSTR windowName,
1167                               DWORD style, INT16 x, INT16 y, INT16 width,
1168                               INT16 height, HWND16 parent, HMENU16 menu,
1169                               HINSTANCE16 instance, LPVOID data )
1170 {
1171     return CreateWindowEx16( 0, className, windowName, style,
1172                            x, y, width, height, parent, menu, instance, data );
1173 }
1174
1175
1176 /***********************************************************************
1177  *              CreateWindowEx (USER.452)
1178  */
1179 HWND16 WINAPI CreateWindowEx16( DWORD exStyle, LPCSTR className,
1180                                 LPCSTR windowName, DWORD style, INT16 x,
1181                                 INT16 y, INT16 width, INT16 height,
1182                                 HWND16 parent, HMENU16 menu,
1183                                 HINSTANCE16 instance, LPVOID data )
1184 {
1185     ATOM classAtom;
1186     CREATESTRUCTA cs;
1187     char buffer[256];
1188
1189     /* Find the class atom */
1190
1191     if (HIWORD(className))
1192     {
1193         if (!(classAtom = GlobalFindAtomA( className )))
1194         {
1195             ERR( "bad class name %s\n", debugres_a(className) );
1196             return 0;
1197         }
1198     }
1199     else
1200     {
1201         classAtom = LOWORD(className);
1202         if (!GlobalGetAtomNameA( classAtom, buffer, sizeof(buffer) ))
1203         {
1204             ERR( "bad atom %x\n", classAtom);
1205             return 0;
1206         }
1207         className = buffer;
1208     }
1209
1210     /* Fix the coordinates */
1211
1212     cs.x  = (x == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)x;
1213     cs.y  = (y == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)y;
1214     cs.cx = (width == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)width;
1215     cs.cy = (height == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)height;
1216
1217     /* Create the window */
1218
1219     cs.lpCreateParams = data;
1220     cs.hInstance      = (HINSTANCE)instance;
1221     cs.hMenu          = (HMENU)menu;
1222     cs.hwndParent     = WIN_Handle32( parent );
1223     cs.style          = style;
1224     cs.lpszName       = windowName;
1225     cs.lpszClass      = className;
1226     cs.dwExStyle      = exStyle;
1227
1228     return WIN_Handle16( WIN_CreateWindowEx( &cs, classAtom, WIN_PROC_16 ));
1229 }
1230
1231
1232 /***********************************************************************
1233  *              CreateWindowExA (USER32.@)
1234  */
1235 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1236                                  LPCSTR windowName, DWORD style, INT x,
1237                                  INT y, INT width, INT height,
1238                                  HWND parent, HMENU menu,
1239                                  HINSTANCE instance, LPVOID data )
1240 {
1241     ATOM classAtom;
1242     CREATESTRUCTA cs;
1243     char buffer[256];
1244
1245     if(!instance)
1246         instance=GetModuleHandleA(NULL);
1247
1248     if(exStyle & WS_EX_MDICHILD)
1249         return CreateMDIWindowA(className, windowName, style, x, y, width, height, parent, instance, (LPARAM)data);
1250
1251     /* Find the class atom */
1252
1253     if (HIWORD(className))
1254     {
1255         if (!(classAtom = GlobalFindAtomA( className )))
1256         {
1257             ERR( "bad class name %s\n", debugres_a(className) );
1258             return 0;
1259         }
1260     }
1261     else
1262     {
1263         classAtom = LOWORD(className);
1264         if (!GlobalGetAtomNameA( classAtom, buffer, sizeof(buffer) ))
1265         {
1266             ERR( "bad atom %x\n", classAtom);
1267             return 0;
1268         }
1269         className = buffer;
1270     }
1271
1272     /* Create the window */
1273
1274     cs.lpCreateParams = data;
1275     cs.hInstance      = instance;
1276     cs.hMenu          = menu;
1277     cs.hwndParent     = parent;
1278     cs.x              = x;
1279     cs.y              = y;
1280     cs.cx             = width;
1281     cs.cy             = height;
1282     cs.style          = style;
1283     cs.lpszName       = windowName;
1284     cs.lpszClass      = className;
1285     cs.dwExStyle      = exStyle;
1286
1287     return WIN_CreateWindowEx( &cs, classAtom, WIN_PROC_32A );
1288 }
1289
1290
1291 /***********************************************************************
1292  *              CreateWindowExW (USER32.@)
1293  */
1294 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1295                                  LPCWSTR windowName, DWORD style, INT x,
1296                                  INT y, INT width, INT height,
1297                                  HWND parent, HMENU menu,
1298                                  HINSTANCE instance, LPVOID data )
1299 {
1300     ATOM classAtom;
1301     CREATESTRUCTW cs;
1302     WCHAR buffer[256];
1303
1304     if(!instance)
1305         instance=GetModuleHandleA(NULL);
1306
1307     if(exStyle & WS_EX_MDICHILD)
1308         return CreateMDIWindowW(className, windowName, style, x, y, width, height, parent, instance, (LPARAM)data);
1309
1310     /* Find the class atom */
1311
1312     if (HIWORD(className))
1313     {
1314         if (!(classAtom = GlobalFindAtomW( className )))
1315         {
1316             ERR( "bad class name %s\n", debugres_w(className) );
1317             return 0;
1318         }
1319     }
1320     else
1321     {
1322         classAtom = LOWORD(className);
1323         if (!GlobalGetAtomNameW( classAtom, buffer, sizeof(buffer)/sizeof(WCHAR) ))
1324         {
1325             ERR( "bad atom %x\n", classAtom);
1326             return 0;
1327         }
1328         className = buffer;
1329     }
1330
1331     /* Create the window */
1332
1333     cs.lpCreateParams = data;
1334     cs.hInstance      = instance;
1335     cs.hMenu          = menu;
1336     cs.hwndParent     = parent;
1337     cs.x              = x;
1338     cs.y              = y;
1339     cs.cx             = width;
1340     cs.cy             = height;
1341     cs.style          = style;
1342     cs.lpszName       = windowName;
1343     cs.lpszClass      = className;
1344     cs.dwExStyle      = exStyle;
1345
1346     /* Note: we rely on the fact that CREATESTRUCTA and */
1347     /* CREATESTRUCTW have the same layout. */
1348     return WIN_CreateWindowEx( (CREATESTRUCTA *)&cs, classAtom, WIN_PROC_32W );
1349 }
1350
1351
1352 /***********************************************************************
1353  *           WIN_SendDestroyMsg
1354  */
1355 static void WIN_SendDestroyMsg( HWND hwnd )
1356 {
1357     if( CARET_GetHwnd() == hwnd) DestroyCaret();
1358     if (USER_Driver.pResetSelectionOwner)
1359         USER_Driver.pResetSelectionOwner( hwnd, TRUE );
1360
1361     /*
1362      * Send the WM_DESTROY to the window.
1363      */
1364     SendMessageA( hwnd, WM_DESTROY, 0, 0);
1365
1366     /*
1367      * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1368      * make sure that the window still exists when we come back.
1369      */
1370     if (IsWindow(hwnd))
1371     {
1372         HWND* pWndArray;
1373         int i;
1374
1375         if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1376
1377         /* start from the end (FIXME: is this needed?) */
1378         for (i = 0; pWndArray[i]; i++) ;
1379
1380         while (--i >= 0)
1381         {
1382             if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1383         }
1384         HeapFree( GetProcessHeap(), 0, pWndArray );
1385     }
1386     else
1387       WARN("\tdestroyed itself while in WM_DESTROY!\n");
1388 }
1389
1390
1391 /***********************************************************************
1392  *              DestroyWindow (USER32.@)
1393  */
1394 BOOL WINAPI DestroyWindow( HWND hwnd )
1395 {
1396     BOOL is_child;
1397     HWND h;
1398
1399     if (!(hwnd = WIN_IsCurrentThread( hwnd )) || (hwnd == GetDesktopWindow()))
1400     {
1401         SetLastError( ERROR_ACCESS_DENIED );
1402         return FALSE;
1403     }
1404
1405     TRACE("(%04x)\n", hwnd);
1406
1407     /* Look whether the focus is within the tree of windows we will
1408      * be destroying.
1409      */
1410     h = GetFocus();
1411     if (h == hwnd || IsChild( hwnd, h ))
1412     {
1413         HWND parent = GetAncestor( hwnd, GA_PARENT );
1414         if (parent == GetDesktopWindow()) parent = 0;
1415         SetFocus( parent );
1416     }
1417
1418       /* Call hooks */
1419
1420     if( HOOK_CallHooksA( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0L) ) return FALSE;
1421
1422     is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;
1423
1424     if (is_child)
1425     {
1426         if (!USER_IsExitingThread( GetCurrentThreadId() ))
1427             send_parent_notify( hwnd, WM_DESTROY );
1428     }
1429     else if (!GetWindow( hwnd, GW_OWNER ))
1430     {
1431         HOOK_CallHooksA( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L );
1432         /* FIXME: clean up palette - see "Internals" p.352 */
1433     }
1434
1435     if (!IsWindow(hwnd)) return TRUE;
1436
1437     if (USER_Driver.pResetSelectionOwner)
1438         USER_Driver.pResetSelectionOwner( hwnd, FALSE ); /* before the window is unmapped */
1439
1440       /* Hide the window */
1441
1442     ShowWindow( hwnd, SW_HIDE );
1443     if (!IsWindow(hwnd)) return TRUE;
1444
1445       /* Recursively destroy owned windows */
1446
1447     if (!is_child)
1448     {
1449         HWND owner;
1450
1451         for (;;)
1452         {
1453             int i, got_one = 0;
1454             HWND *list = WIN_ListChildren( GetDesktopWindow() );
1455             if (list)
1456             {
1457                 for (i = 0; list[i]; i++)
1458                 {
1459                     if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1460                     if (WIN_IsCurrentThread( list[i] ))
1461                     {
1462                         DestroyWindow( list[i] );
1463                         got_one = 1;
1464                         continue;
1465                     }
1466                     WIN_SetOwner( list[i], 0 );
1467                 }
1468                 HeapFree( GetProcessHeap(), 0, list );
1469             }
1470             if (!got_one) break;
1471         }
1472
1473         WINPOS_ActivateOtherWindow( hwnd );
1474
1475         if ((owner = GetWindow( hwnd, GW_OWNER )))
1476         {
1477             WND *ptr = WIN_FindWndPtr( owner );
1478             if (ptr)
1479             {
1480                 if (ptr->hwndLastActive == hwnd) ptr->hwndLastActive = owner;
1481                 WIN_ReleaseWndPtr( ptr );
1482             }
1483         }
1484     }
1485
1486       /* Send destroy messages */
1487
1488     WIN_SendDestroyMsg( hwnd );
1489     if (!IsWindow( hwnd )) return TRUE;
1490
1491       /* Unlink now so we won't bother with the children later on */
1492
1493     WIN_UnlinkWindow( hwnd );
1494
1495       /* Destroy the window storage */
1496
1497     WIN_DestroyWindow( hwnd );
1498     return TRUE;
1499 }
1500
1501
1502 /***********************************************************************
1503  *              CloseWindow (USER32.@)
1504  */
1505 BOOL WINAPI CloseWindow( HWND hwnd )
1506 {
1507     if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1508     ShowWindow( hwnd, SW_MINIMIZE );
1509     return TRUE;
1510 }
1511
1512
1513 /***********************************************************************
1514  *              OpenIcon (USER32.@)
1515  */
1516 BOOL WINAPI OpenIcon( HWND hwnd )
1517 {
1518     if (!IsIconic( hwnd )) return FALSE;
1519     ShowWindow( hwnd, SW_SHOWNORMAL );
1520     return TRUE;
1521 }
1522
1523
1524 /***********************************************************************
1525  *           WIN_FindWindow
1526  *
1527  * Implementation of FindWindow() and FindWindowEx().
1528  */
1529 static HWND WIN_FindWindow( HWND parent, HWND child, ATOM className, LPCWSTR title )
1530 {
1531     HWND *list = NULL;
1532     HWND retvalue = 0;
1533     int i = 0, len = 0;
1534     WCHAR *buffer = NULL;
1535
1536     if (!parent) parent = GetDesktopWindow();
1537     if (title)
1538     {
1539         len = strlenW(title) + 1;  /* one extra char to check for chars beyond the end */
1540         if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1541     }
1542
1543     if (!(list = list_window_children( parent, className, 0 ))) goto done;
1544
1545     if (child)
1546     {
1547         child = WIN_GetFullHandle( child );
1548         while (list[i] && list[i] != child) i++;
1549         if (!list[i]) goto done;
1550         i++;  /* start from next window */
1551     }
1552
1553     if (title)
1554     {
1555         while (list[i])
1556         {
1557             if (GetWindowTextW( list[i], buffer, len ) && !strcmpiW( buffer, title )) break;
1558             i++;
1559         }
1560     }
1561     retvalue = list[i];
1562
1563  done:
1564     if (list) HeapFree( GetProcessHeap(), 0, list );
1565     if (buffer) HeapFree( GetProcessHeap(), 0, buffer );
1566     return retvalue;
1567 }
1568
1569
1570
1571 /***********************************************************************
1572  *              FindWindowA (USER32.@)
1573  */
1574 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1575 {
1576     HWND ret = FindWindowExA( 0, 0, className, title );
1577     if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1578     return ret;
1579 }
1580
1581
1582 /***********************************************************************
1583  *              FindWindowExA (USER32.@)
1584  */
1585 HWND WINAPI FindWindowExA( HWND parent, HWND child,
1586                                LPCSTR className, LPCSTR title )
1587 {
1588     ATOM atom = 0;
1589     LPWSTR buffer;
1590     HWND hwnd;
1591     INT len;
1592
1593     if (className)
1594     {
1595         /* If the atom doesn't exist, then no class */
1596         /* with this name exists either. */
1597         if (!(atom = GlobalFindAtomA( className )))
1598         {
1599             SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1600             return 0;
1601         }
1602     }
1603     if (!title) return WIN_FindWindow( parent, child, atom, NULL );
1604
1605     len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
1606     if (!(buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
1607     MultiByteToWideChar( CP_ACP, 0, title, -1, buffer, len );
1608     hwnd = WIN_FindWindow( parent, child, atom, buffer );
1609     HeapFree( GetProcessHeap(), 0, buffer );
1610     return hwnd;
1611 }
1612
1613
1614 /***********************************************************************
1615  *              FindWindowExW (USER32.@)
1616  */
1617 HWND WINAPI FindWindowExW( HWND parent, HWND child,
1618                                LPCWSTR className, LPCWSTR title )
1619 {
1620     ATOM atom = 0;
1621
1622     if (className)
1623     {
1624         /* If the atom doesn't exist, then no class */
1625         /* with this name exists either. */
1626         if (!(atom = GlobalFindAtomW( className )))
1627         {
1628             SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1629             return 0;
1630         }
1631     }
1632     return WIN_FindWindow( parent, child, atom, title );
1633 }
1634
1635
1636 /***********************************************************************
1637  *              FindWindowW (USER32.@)
1638  */
1639 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
1640 {
1641     return FindWindowExW( 0, 0, className, title );
1642 }
1643
1644
1645 /**********************************************************************
1646  *              GetDesktopWindow (USER32.@)
1647  */
1648 HWND WINAPI GetDesktopWindow(void)
1649 {
1650     if (pWndDesktop) return pWndDesktop->hwndSelf;
1651     ERR( "Wine init error: either you're trying to use an invalid native USER.EXE config, or some graphics/GUI libraries or DLLs didn't initialize properly. Aborting.\n" );
1652     ExitProcess(1);
1653     return 0;
1654 }
1655
1656
1657 /*******************************************************************
1658  *              EnableWindow (USER32.@)
1659  */
1660 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
1661 {
1662     WND *wndPtr;
1663     BOOL retvalue;
1664     LONG style;
1665     HWND full_handle;
1666
1667     if (!(full_handle = WIN_IsCurrentThread( hwnd )))
1668         return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
1669
1670     hwnd = full_handle;
1671
1672     TRACE("( %x, %d )\n", hwnd, enable);
1673
1674     if (!(wndPtr = WIN_GetPtr( hwnd ))) return FALSE;
1675     style = wndPtr->dwStyle;
1676     retvalue = ((style & WS_DISABLED) != 0);
1677     WIN_ReleasePtr( wndPtr );
1678
1679     if (enable && retvalue)
1680     {
1681         WIN_SetStyle( hwnd, style & ~WS_DISABLED );
1682         SendMessageA( hwnd, WM_ENABLE, TRUE, 0 );
1683     }
1684     else if (!enable && !retvalue)
1685     {
1686         SendMessageA( hwnd, WM_CANCELMODE, 0, 0);
1687
1688         WIN_SetStyle( hwnd, style | WS_DISABLED );
1689
1690         if (hwnd == GetFocus())
1691             SetFocus( 0 );  /* A disabled window can't have the focus */
1692
1693         if (hwnd == GetCapture())
1694             ReleaseCapture();  /* A disabled window can't capture the mouse */
1695
1696         SendMessageA( hwnd, WM_ENABLE, FALSE, 0 );
1697     }
1698     return retvalue;
1699 }
1700
1701
1702 /***********************************************************************
1703  *              IsWindowEnabled (USER32.@)
1704  */
1705 BOOL WINAPI IsWindowEnabled(HWND hWnd)
1706 {
1707     return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
1708 }
1709
1710
1711 /***********************************************************************
1712  *              IsWindowUnicode (USER32.@)
1713  */
1714 BOOL WINAPI IsWindowUnicode( HWND hwnd )
1715 {
1716     WND * wndPtr;
1717     BOOL retvalue;
1718
1719     if (!(wndPtr = WIN_FindWndPtr(hwnd))) return FALSE;
1720     retvalue = (WINPROC_GetProcType( wndPtr->winproc ) == WIN_PROC_32W);
1721     WIN_ReleaseWndPtr(wndPtr);
1722     return retvalue;
1723 }
1724
1725
1726 /**********************************************************************
1727  *              GetWindowWord (USER32.@)
1728  */
1729 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
1730 {
1731     if (offset >= 0)
1732     {
1733         WORD retvalue = 0;
1734         WND *wndPtr = WIN_GetPtr( hwnd );
1735         if (!wndPtr)
1736         {
1737             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1738             return 0;
1739         }
1740         if (wndPtr == WND_OTHER_PROCESS)
1741         {
1742             if (IsWindow( hwnd ))
1743                 FIXME( "(%d) not supported yet on other process window %x\n", offset, hwnd );
1744             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1745             return 0;
1746         }
1747         if (offset > wndPtr->cbWndExtra - sizeof(WORD))
1748         {
1749             WARN("Invalid offset %d\n", offset );
1750             SetLastError( ERROR_INVALID_INDEX );
1751         }
1752         else retvalue = *(WORD *)(((char *)wndPtr->wExtra) + offset);
1753         WIN_ReleasePtr( wndPtr );
1754         return retvalue;
1755     }
1756
1757     switch(offset)
1758     {
1759     case GWL_HWNDPARENT:
1760         return GetWindowLongW( hwnd, offset );
1761     case GWL_ID:
1762     case GWL_HINSTANCE:
1763         {
1764             LONG ret = GetWindowLongW( hwnd, offset );
1765             if (HIWORD(ret))
1766                 WARN("%d: discards high bits of 0x%08lx!\n", offset, ret );
1767             return LOWORD(ret);
1768         }
1769     default:
1770         WARN("Invalid offset %d\n", offset );
1771         return 0;
1772     }
1773 }
1774
1775
1776 /**********************************************************************
1777  *              SetWindowWord (USER32.@)
1778  */
1779 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
1780 {
1781     WORD *ptr, retval;
1782     WND * wndPtr;
1783
1784     switch(offset)
1785     {
1786     case GWL_ID:
1787     case GWL_HINSTANCE:
1788     case GWL_HWNDPARENT:
1789         return SetWindowLongW( hwnd, offset, (UINT)newval );
1790     default:
1791         if (offset < 0)
1792         {
1793             WARN("Invalid offset %d\n", offset );
1794             SetLastError( ERROR_INVALID_INDEX );
1795             return 0;
1796         }
1797     }
1798
1799     wndPtr = WIN_GetPtr( hwnd );
1800     if (wndPtr == WND_OTHER_PROCESS)
1801     {
1802         if (IsWindow(hwnd))
1803             FIXME( "set %d <- %x not supported yet on other process window %x\n",
1804                    offset, newval, hwnd );
1805         wndPtr = NULL;
1806     }
1807     if (!wndPtr)
1808     {
1809        SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1810        return 0;
1811     }
1812
1813     if (offset > wndPtr->cbWndExtra - sizeof(WORD))
1814     {
1815         WARN("Invalid offset %d\n", offset );
1816         WIN_ReleasePtr(wndPtr);
1817         SetLastError( ERROR_INVALID_INDEX );
1818         return 0;
1819     }
1820     ptr = (WORD *)(((char *)wndPtr->wExtra) + offset);
1821     retval = *ptr;
1822     *ptr = newval;
1823     WIN_ReleasePtr(wndPtr);
1824     return retval;
1825 }
1826
1827
1828 /**********************************************************************
1829  *           WIN_GetWindowLong
1830  *
1831  * Helper function for GetWindowLong().
1832  */
1833 static LONG WIN_GetWindowLong( HWND hwnd, INT offset, WINDOWPROCTYPE type )
1834 {
1835     LONG retvalue = 0;
1836     WND *wndPtr;
1837
1838     if (offset == GWL_HWNDPARENT) return (LONG)GetParent( hwnd );
1839
1840     if (!(wndPtr = WIN_GetPtr( hwnd )))
1841     {
1842         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1843         return 0;
1844     }
1845
1846     if (wndPtr == WND_OTHER_PROCESS)
1847     {
1848         if (offset >= 0)
1849         {
1850             if (IsWindow(hwnd))
1851                 FIXME( "(%d) not supported on other process window %x\n", offset, hwnd );
1852             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1853             return 0;
1854         }
1855         if (offset == GWL_WNDPROC)
1856         {
1857             SetLastError( ERROR_ACCESS_DENIED );
1858             return 0;
1859         }
1860         SERVER_START_REQ( set_window_info )
1861         {
1862             req->handle = hwnd;
1863             req->flags  = 0;  /* don't set anything, just retrieve */
1864             if (!wine_server_call_err( req ))
1865             {
1866                 switch(offset)
1867                 {
1868                 case GWL_STYLE:     retvalue = reply->old_style; break;
1869                 case GWL_EXSTYLE:   retvalue = reply->old_ex_style; break;
1870                 case GWL_ID:        retvalue = reply->old_id; break;
1871                 case GWL_HINSTANCE: retvalue = (ULONG_PTR)reply->old_instance; break;
1872                 case GWL_USERDATA:  retvalue = (ULONG_PTR)reply->old_user_data; break;
1873                 default:
1874                     SetLastError( ERROR_INVALID_INDEX );
1875                     break;
1876                 }
1877             }
1878         }
1879         SERVER_END_REQ;
1880         return retvalue;
1881     }
1882
1883     /* now we have a valid wndPtr */
1884
1885     if (offset >= 0)
1886     {
1887         if (offset > wndPtr->cbWndExtra - sizeof(LONG))
1888         {
1889           /*
1890             * Some programs try to access last element from 16 bit
1891             * code using illegal offset value. Hopefully this is
1892             * what those programs really expect.
1893             */
1894            if (type == WIN_PROC_16 && 
1895                wndPtr->cbWndExtra >= 4 &&
1896                offset == wndPtr->cbWndExtra - sizeof(WORD))
1897            {
1898                INT offset2 = wndPtr->cbWndExtra - sizeof(LONG);
1899              
1900                ERR( "- replaced invalid offset %d with %d\n",
1901                     offset, offset2 );
1902            
1903                 retvalue = *(LONG *)(((char *)wndPtr->wExtra) + offset2);
1904                 WIN_ReleasePtr( wndPtr );
1905                 return retvalue;
1906             }
1907             WARN("Invalid offset %d\n", offset );
1908             WIN_ReleasePtr( wndPtr );
1909             SetLastError( ERROR_INVALID_INDEX );
1910             return 0;
1911         }
1912         retvalue = *(LONG *)(((char *)wndPtr->wExtra) + offset);
1913         /* Special case for dialog window procedure */
1914         if ((offset == DWL_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
1915             retvalue = (LONG)WINPROC_GetProc( (HWINDOWPROC)retvalue, type );
1916         WIN_ReleasePtr( wndPtr );
1917         return retvalue;
1918     }
1919
1920     switch(offset)
1921     {
1922     case GWL_USERDATA:   retvalue = wndPtr->userdata; break;
1923     case GWL_STYLE:      retvalue = wndPtr->dwStyle; break;
1924     case GWL_EXSTYLE:    retvalue = wndPtr->dwExStyle; break;
1925     case GWL_ID:         retvalue = (LONG)wndPtr->wIDmenu; break;
1926     case GWL_WNDPROC:    retvalue = (LONG)WINPROC_GetProc( wndPtr->winproc, type ); break;
1927     case GWL_HINSTANCE:  retvalue = wndPtr->hInstance; break;
1928     default:
1929         WARN("Unknown offset %d\n", offset );
1930         SetLastError( ERROR_INVALID_INDEX );
1931         break;
1932     }
1933     WIN_ReleasePtr(wndPtr);
1934     return retvalue;
1935 }
1936
1937
1938 /**********************************************************************
1939  *           WIN_SetWindowLong
1940  *
1941  * Helper function for SetWindowLong().
1942  *
1943  * 0 is the failure code. However, in the case of failure SetLastError
1944  * must be set to distinguish between a 0 return value and a failure.
1945  */
1946 static LONG WIN_SetWindowLong( HWND hwnd, INT offset, LONG newval,
1947                                WINDOWPROCTYPE type )
1948 {
1949     LONG retval = 0;
1950     WND *wndPtr;
1951
1952     TRACE( "%x %d %lx %x\n", hwnd, offset, newval, type );
1953
1954     if (!WIN_IsCurrentProcess( hwnd ))
1955     {
1956         if (offset == GWL_WNDPROC)
1957         {
1958             SetLastError( ERROR_ACCESS_DENIED );
1959             return 0;
1960         }
1961         return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, offset, newval );
1962     }
1963
1964     wndPtr = WIN_GetPtr( hwnd );
1965
1966     if (offset >= 0)
1967     {
1968         LONG *ptr = (LONG *)(((char *)wndPtr->wExtra) + offset);
1969         if (offset > wndPtr->cbWndExtra - sizeof(LONG))
1970         {
1971             WARN("Invalid offset %d\n", offset );
1972             WIN_ReleasePtr( wndPtr );
1973             SetLastError( ERROR_INVALID_INDEX );
1974             return 0;
1975         }
1976         /* Special case for dialog window procedure */
1977         if ((offset == DWL_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
1978         {
1979             retval = (LONG)WINPROC_GetProc( (HWINDOWPROC)*ptr, type );
1980             WINPROC_SetProc( (HWINDOWPROC *)ptr, (WNDPROC16)newval,
1981                              type, WIN_PROC_WINDOW );
1982             WIN_ReleasePtr( wndPtr );
1983             return retval;
1984         }
1985         retval = *ptr;
1986         *ptr = newval;
1987         WIN_ReleasePtr( wndPtr );
1988     }
1989     else
1990     {
1991         STYLESTRUCT style;
1992         BOOL ok;
1993
1994         /* first some special cases */
1995         switch( offset )
1996         {
1997         case GWL_STYLE:
1998         case GWL_EXSTYLE:
1999             style.styleOld = wndPtr->dwStyle;
2000             style.styleNew = newval;
2001             WIN_ReleasePtr( wndPtr );
2002             SendMessageW( hwnd, WM_STYLECHANGING, offset, (LPARAM)&style );
2003             if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2004             newval = style.styleNew;
2005             break;
2006         case GWL_HWNDPARENT:
2007             WIN_ReleasePtr( wndPtr );
2008             return (LONG)SetParent( hwnd, (HWND)newval );
2009         case GWL_WNDPROC:
2010             retval = (LONG)WINPROC_GetProc( wndPtr->winproc, type );
2011             WINPROC_SetProc( &wndPtr->winproc, (WNDPROC16)newval,
2012                              type, WIN_PROC_WINDOW );
2013             WIN_ReleasePtr( wndPtr );
2014             return retval;
2015         case GWL_ID:
2016         case GWL_HINSTANCE:
2017         case GWL_USERDATA:
2018             break;
2019         default:
2020             WIN_ReleasePtr( wndPtr );
2021             WARN("Invalid offset %d\n", offset );
2022             SetLastError( ERROR_INVALID_INDEX );
2023             return 0;
2024         }
2025
2026         SERVER_START_REQ( set_window_info )
2027         {
2028             req->handle = hwnd;
2029             switch(offset)
2030             {
2031             case GWL_STYLE:
2032                 req->flags = SET_WIN_STYLE;
2033                 req->style = newval;
2034                 break;
2035             case GWL_EXSTYLE:
2036                 req->flags = SET_WIN_EXSTYLE;
2037                 req->ex_style = newval;
2038                 break;
2039             case GWL_ID:
2040                 req->flags = SET_WIN_ID;
2041                 req->id = newval;
2042                 break;
2043             case GWL_HINSTANCE:
2044                 req->flags = SET_WIN_INSTANCE;
2045                 req->instance = (void *)newval;
2046                 break;
2047             case GWL_USERDATA:
2048                 req->flags = SET_WIN_USERDATA;
2049                 req->user_data = (void *)newval;
2050                 break;
2051             }
2052             if ((ok = !wine_server_call_err( req )))
2053             {
2054                 switch(offset)
2055                 {
2056                 case GWL_STYLE:
2057                     wndPtr->dwStyle = newval;
2058                     retval = reply->old_style;
2059                     break;
2060                 case GWL_EXSTYLE:
2061                     wndPtr->dwExStyle = newval;
2062                     retval = reply->old_ex_style;
2063                     break;
2064                 case GWL_ID:
2065                     wndPtr->wIDmenu = newval;
2066                     retval = reply->old_id;
2067                     break;
2068                 case GWL_HINSTANCE:
2069                     wndPtr->hInstance = newval;
2070                     retval = (HINSTANCE)reply->old_instance;
2071                     break;
2072                 case GWL_USERDATA:
2073                     wndPtr->userdata = newval;
2074                     retval = (ULONG_PTR)reply->old_user_data;
2075                     break;
2076                 }
2077             }
2078         }
2079         SERVER_END_REQ;
2080         WIN_ReleasePtr( wndPtr );
2081
2082         if (!ok) return 0;
2083
2084         if (offset == GWL_STYLE && USER_Driver.pSetWindowStyle)
2085             USER_Driver.pSetWindowStyle( hwnd, retval );
2086
2087         if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2088             SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2089
2090     }
2091     return retval;
2092 }
2093
2094
2095 /**********************************************************************
2096  *              GetWindowLong (USER.135)
2097  */
2098 LONG WINAPI GetWindowLong16( HWND16 hwnd, INT16 offset )
2099 {
2100     return WIN_GetWindowLong( WIN_Handle32(hwnd), offset, WIN_PROC_16 );
2101 }
2102
2103
2104 /**********************************************************************
2105  *              GetWindowLongA (USER32.@)
2106  */
2107 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2108 {
2109     return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32A );
2110 }
2111
2112
2113 /**********************************************************************
2114  *              GetWindowLongW (USER32.@)
2115  */
2116 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2117 {
2118     return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32W );
2119 }
2120
2121
2122 /**********************************************************************
2123  *              SetWindowLong (USER.136)
2124  */
2125 LONG WINAPI SetWindowLong16( HWND16 hwnd, INT16 offset, LONG newval )
2126 {
2127     return WIN_SetWindowLong( WIN_Handle32(hwnd), offset, newval, WIN_PROC_16 );
2128 }
2129
2130
2131 /**********************************************************************
2132  *              SetWindowLongA (USER32.@)
2133  */
2134 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2135 {
2136     return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32A );
2137 }
2138
2139
2140 /**********************************************************************
2141  *              SetWindowLongW (USER32.@) Set window attribute
2142  *
2143  * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2144  * value in a window's extra memory.
2145  *
2146  * The _hwnd_ parameter specifies the window.  is the handle to a
2147  * window that has extra memory. The _newval_ parameter contains the
2148  * new attribute or extra memory value.  If positive, the _offset_
2149  * parameter is the byte-addressed location in the window's extra
2150  * memory to set.  If negative, _offset_ specifies the window
2151  * attribute to set, and should be one of the following values:
2152  *
2153  * GWL_EXSTYLE      The window's extended window style
2154  *
2155  * GWL_STYLE        The window's window style.
2156  *
2157  * GWL_WNDPROC      Pointer to the window's window procedure.
2158  *
2159  * GWL_HINSTANCE    The window's pplication instance handle.
2160  *
2161  * GWL_ID           The window's identifier.
2162  *
2163  * GWL_USERDATA     The window's user-specified data.
2164  *
2165  * If the window is a dialog box, the _offset_ parameter can be one of
2166  * the following values:
2167  *
2168  * DWL_DLGPROC      The address of the window's dialog box procedure.
2169  *
2170  * DWL_MSGRESULT    The return value of a message
2171  *                  that the dialog box procedure processed.
2172  *
2173  * DWL_USER         Application specific information.
2174  *
2175  * RETURNS
2176  *
2177  * If successful, returns the previous value located at _offset_. Otherwise,
2178  * returns 0.
2179  *
2180  * NOTES
2181  *
2182  * Extra memory for a window class is specified by a nonzero cbWndExtra
2183  * parameter of the WNDCLASS structure passed to RegisterClass() at the
2184  * time of class creation.
2185  *
2186  * Using GWL_WNDPROC to set a new window procedure effectively creates
2187  * a window subclass. Use CallWindowProc() in the new windows procedure
2188  * to pass messages to the superclass's window procedure.
2189  *
2190  * The user data is reserved for use by the application which created
2191  * the window.
2192  *
2193  * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2194  * instead, call the EnableWindow() function to change the window's
2195  * disabled state.
2196  *
2197  * Do not use GWL_HWNDPARENT to reset the window's parent, use
2198  * SetParent() instead.
2199  *
2200  * Win95:
2201  * When offset is GWL_STYLE and the calling app's ver is 4.0,
2202  * it sends WM_STYLECHANGING before changing the settings
2203  * and WM_STYLECHANGED afterwards.
2204  * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2205  */
2206 LONG WINAPI SetWindowLongW(
2207     HWND hwnd,  /* [in] window to alter */
2208     INT offset, /* [in] offset, in bytes, of location to alter */
2209     LONG newval /* [in] new value of location */
2210 ) {
2211     return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32W );
2212 }
2213
2214
2215 /*******************************************************************
2216  *              GetWindowTextA (USER32.@)
2217  */
2218 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2219 {
2220     WCHAR *buffer;
2221
2222     if (WIN_IsCurrentProcess( hwnd ))
2223         return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2224
2225     /* when window belongs to other process, don't send a message */
2226     if (nMaxCount <= 0) return 0;
2227     if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2228     get_server_window_text( hwnd, buffer, nMaxCount );
2229     if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2230         lpString[nMaxCount-1] = 0;
2231     HeapFree( GetProcessHeap(), 0, buffer );
2232     return strlen(lpString);
2233 }
2234
2235
2236 /*******************************************************************
2237  *              InternalGetWindowText (USER32.@)
2238  */
2239 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2240 {
2241     WND *win;
2242
2243     if (nMaxCount <= 0) return 0;
2244     if (!(win = WIN_GetPtr( hwnd ))) return 0;
2245     if (win != WND_OTHER_PROCESS)
2246     {
2247         if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2248         else lpString[0] = 0;
2249         WIN_ReleasePtr( win );
2250     }
2251     else
2252     {
2253         get_server_window_text( hwnd, lpString, nMaxCount );
2254     }
2255     return strlenW(lpString);
2256 }
2257
2258
2259 /*******************************************************************
2260  *              GetWindowTextW (USER32.@)
2261  */
2262 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2263 {
2264     if (WIN_IsCurrentProcess( hwnd ))
2265         return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2266
2267     /* when window belongs to other process, don't send a message */
2268     if (nMaxCount <= 0) return 0;
2269     get_server_window_text( hwnd, lpString, nMaxCount );
2270     return strlenW(lpString);
2271 }
2272
2273
2274 /*******************************************************************
2275  *              SetWindowText  (USER32.@)
2276  *              SetWindowTextA (USER32.@)
2277  */
2278 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2279 {
2280     if (!WIN_IsCurrentProcess( hwnd ))
2281     {
2282         FIXME( "cannot set text %s of other process window %x\n", debugstr_a(lpString), hwnd );
2283         SetLastError( ERROR_ACCESS_DENIED );
2284         return FALSE;
2285     }
2286     return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2287 }
2288
2289
2290 /*******************************************************************
2291  *              SetWindowTextW (USER32.@)
2292  */
2293 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2294 {
2295     if (!WIN_IsCurrentProcess( hwnd ))
2296     {
2297         FIXME( "cannot set text %s of other process window %x\n", debugstr_w(lpString), hwnd );
2298         SetLastError( ERROR_ACCESS_DENIED );
2299         return FALSE;
2300     }
2301     return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2302 }
2303
2304
2305 /*******************************************************************
2306  *              GetWindowTextLengthA (USER32.@)
2307  */
2308 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2309 {
2310     return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2311 }
2312
2313 /*******************************************************************
2314  *              GetWindowTextLengthW (USER32.@)
2315  */
2316 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2317 {
2318     return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2319 }
2320
2321
2322 /*******************************************************************
2323  *              IsWindow (USER32.@)
2324  */
2325 BOOL WINAPI IsWindow( HWND hwnd )
2326 {
2327     WND *ptr;
2328     BOOL ret;
2329
2330     if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2331
2332     if (ptr != WND_OTHER_PROCESS)
2333     {
2334         WIN_ReleasePtr( ptr );
2335         return TRUE;
2336     }
2337
2338     /* check other processes */
2339     SERVER_START_REQ( get_window_info )
2340     {
2341         req->handle = hwnd;
2342         ret = !wine_server_call_err( req );
2343     }
2344     SERVER_END_REQ;
2345     return ret;
2346 }
2347
2348
2349 /***********************************************************************
2350  *              GetWindowThreadProcessId (USER32.@)
2351  */
2352 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2353 {
2354     WND *ptr;
2355     DWORD tid = 0;
2356
2357     if (!(ptr = WIN_GetPtr( hwnd )))
2358     {
2359         SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2360         return 0;
2361     }
2362
2363     if (ptr != WND_OTHER_PROCESS)
2364     {
2365         /* got a valid window */
2366         tid = ptr->tid;
2367         if (process) *process = GetCurrentProcessId();
2368         WIN_ReleasePtr( ptr );
2369         return tid;
2370     }
2371
2372     /* check other processes */
2373     SERVER_START_REQ( get_window_info )
2374     {
2375         req->handle = hwnd;
2376         if (!wine_server_call_err( req ))
2377         {
2378             tid = (DWORD)reply->tid;
2379             if (process) *process = (DWORD)reply->pid;
2380         }
2381     }
2382     SERVER_END_REQ;
2383     return tid;
2384 }
2385
2386
2387 /*****************************************************************
2388  *              GetParent (USER32.@)
2389  */
2390 HWND WINAPI GetParent( HWND hwnd )
2391 {
2392     WND *wndPtr;
2393     HWND retvalue = 0;
2394
2395     if (!(wndPtr = WIN_GetPtr( hwnd )))
2396     {
2397         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2398         return 0;
2399     }
2400     if (wndPtr == WND_OTHER_PROCESS)
2401     {
2402         LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2403         if (style & (WS_POPUP | WS_CHILD))
2404         {
2405             SERVER_START_REQ( get_window_tree )
2406             {
2407                 req->handle = hwnd;
2408                 if (!wine_server_call_err( req ))
2409                 {
2410                     if (style & WS_CHILD) retvalue = reply->parent;
2411                     else retvalue = reply->owner;
2412                 }
2413             }
2414             SERVER_END_REQ;
2415         }
2416     }
2417     else
2418     {
2419         if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2420         else if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2421         WIN_ReleasePtr( wndPtr );
2422     }
2423     return retvalue;
2424 }
2425
2426
2427 /*****************************************************************
2428  *              GetAncestor (USER32.@)
2429  */
2430 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2431 {
2432     WND *win;
2433     HWND *list, ret = 0;
2434
2435     if (type == GA_PARENT)
2436     {
2437         if (!(win = WIN_GetPtr( hwnd )))
2438         {
2439             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2440             return 0;
2441         }
2442         if (win != WND_OTHER_PROCESS)
2443         {
2444             ret = win->parent;
2445             WIN_ReleasePtr( win );
2446         }
2447         else /* need to query the server */
2448         {
2449             SERVER_START_REQ( get_window_tree )
2450             {
2451                 req->handle = hwnd;
2452                 if (!wine_server_call_err( req )) ret = reply->parent;
2453             }
2454             SERVER_END_REQ;
2455         }
2456         return ret;
2457     }
2458
2459     if (!(list = WIN_ListParents( hwnd ))) return 0;
2460
2461     if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd );  /* top-level window */
2462     else
2463     {
2464         int count = 2;
2465         while (list[count]) count++;
2466         ret = list[count - 2];  /* get the one before the desktop */
2467     }
2468     HeapFree( GetProcessHeap(), 0, list );
2469
2470     if (ret && type == GA_ROOTOWNER)
2471     {
2472         for (;;)
2473         {
2474             HWND owner = GetWindow( ret, GW_OWNER );
2475             if (!owner) break;
2476             ret = owner;
2477         }
2478     }
2479     return ret;
2480 }
2481
2482
2483 /*****************************************************************
2484  *              SetParent (USER32.@)
2485  */
2486 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2487 {
2488     WND *wndPtr;
2489     HWND retvalue, full_handle;
2490     BOOL was_visible;
2491
2492     if (!parent) parent = GetDesktopWindow();
2493     else parent = WIN_GetFullHandle( parent );
2494
2495     if (!IsWindow( parent ))
2496     {
2497         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2498         return 0;
2499     }
2500
2501     if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2502         return SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2503
2504     hwnd = full_handle;
2505
2506     if (USER_Driver.pSetParent)
2507         return USER_Driver.pSetParent( hwnd, parent );
2508
2509     /* Windows hides the window first, then shows it again
2510      * including the WM_SHOWWINDOW messages and all */
2511     was_visible = ShowWindow( hwnd, SW_HIDE );
2512
2513     if (!IsWindow( parent )) return 0;
2514     if (!(wndPtr = WIN_GetPtr(hwnd)) || wndPtr == WND_OTHER_PROCESS) return 0;
2515
2516     retvalue = wndPtr->parent;  /* old parent */
2517     if (parent != retvalue)
2518     {
2519         WIN_LinkWindow( hwnd, parent, HWND_TOP );
2520
2521         if (parent != GetDesktopWindow()) /* a child window */
2522         {
2523             if (!(wndPtr->dwStyle & WS_CHILD))
2524             {
2525                 HMENU menu = (HMENU)SetWindowLongW( hwnd, GWL_ID, 0 );
2526                 if (menu) DestroyMenu( menu );
2527             }
2528         }
2529     }
2530     WIN_ReleasePtr( wndPtr );
2531
2532     /* SetParent additionally needs to make hwnd the topmost window
2533        in the x-order and send the expected WM_WINDOWPOSCHANGING and
2534        WM_WINDOWPOSCHANGED notification messages.
2535     */
2536     SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0,
2537                   SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | (was_visible ? SWP_SHOWWINDOW : 0) );
2538     /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
2539      * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
2540     return retvalue;
2541 }
2542
2543
2544 /*******************************************************************
2545  *              IsChild (USER32.@)
2546  */
2547 BOOL WINAPI IsChild( HWND parent, HWND child )
2548 {
2549     HWND *list = WIN_ListParents( child );
2550     int i;
2551     BOOL ret;
2552
2553     if (!list) return FALSE;
2554     parent = WIN_GetFullHandle( parent );
2555     for (i = 0; list[i]; i++) if (list[i] == parent) break;
2556     ret = (list[i] != 0);
2557     HeapFree( GetProcessHeap(), 0, list );
2558     return ret;
2559 }
2560
2561
2562 /***********************************************************************
2563  *              IsWindowVisible (USER32.@)
2564  */
2565 BOOL WINAPI IsWindowVisible( HWND hwnd )
2566 {
2567     HWND *list;
2568     BOOL retval;
2569     int i;
2570
2571     if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2572     if (!(list = WIN_ListParents( hwnd ))) return TRUE;
2573     for (i = 0; list[i]; i++)
2574         if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2575     retval = !list[i];
2576     HeapFree( GetProcessHeap(), 0, list );
2577     return retval;
2578 }
2579
2580
2581 /***********************************************************************
2582  *           WIN_IsWindowDrawable
2583  *
2584  * hwnd is drawable when it is visible, all parents are not
2585  * minimized, and it is itself not minimized unless we are
2586  * trying to draw its default class icon.
2587  */
2588 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2589 {
2590     HWND *list;
2591     BOOL retval;
2592     int i;
2593     LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2594
2595     if (!(style & WS_VISIBLE)) return FALSE;
2596     if ((style & WS_MINIMIZE) && icon && GetClassLongA( hwnd, GCL_HICON ))  return FALSE;
2597
2598     if (!(list = WIN_ListParents( hwnd ))) return TRUE;
2599     for (i = 0; list[i]; i++)
2600         if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2601             break;
2602     retval = !list[i];
2603     HeapFree( GetProcessHeap(), 0, list );
2604     return retval;
2605 }
2606
2607
2608 /*******************************************************************
2609  *              GetTopWindow (USER32.@)
2610  */
2611 HWND WINAPI GetTopWindow( HWND hwnd )
2612 {
2613     if (!hwnd) hwnd = GetDesktopWindow();
2614     return GetWindow( hwnd, GW_CHILD );
2615 }
2616
2617
2618 /*******************************************************************
2619  *              GetWindow (USER32.@)
2620  */
2621 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2622 {
2623     HWND retval = 0;
2624
2625     if (rel == GW_OWNER)  /* this one may be available locally */
2626     {
2627         WND *wndPtr = WIN_GetPtr( hwnd );
2628         if (!wndPtr)
2629         {
2630             SetLastError( ERROR_INVALID_HANDLE );
2631             return 0;
2632         }
2633         if (wndPtr != WND_OTHER_PROCESS)
2634         {
2635             retval = wndPtr->owner;
2636             WIN_ReleasePtr( wndPtr );
2637             return retval;
2638         }
2639         /* else fall through to server call */
2640     }
2641
2642     SERVER_START_REQ( get_window_tree )
2643     {
2644         req->handle = hwnd;
2645         if (!wine_server_call_err( req ))
2646         {
2647             switch(rel)
2648             {
2649             case GW_HWNDFIRST:
2650                 retval = reply->first_sibling;
2651                 break;
2652             case GW_HWNDLAST:
2653                 retval = reply->last_sibling;
2654                 break;
2655             case GW_HWNDNEXT:
2656                 retval = reply->next_sibling;
2657                 break;
2658             case GW_HWNDPREV:
2659                 retval = reply->prev_sibling;
2660                 break;
2661             case GW_OWNER:
2662                 retval = reply->owner;
2663                 break;
2664             case GW_CHILD:
2665                 retval = reply->first_child;
2666                 break;
2667             }
2668         }
2669     }
2670     SERVER_END_REQ;
2671     return retval;
2672 }
2673
2674
2675 /***********************************************************************
2676  *           WIN_InternalShowOwnedPopups
2677  *
2678  * Internal version of ShowOwnedPopups; Wine functions should use this
2679  * to avoid interfering with application calls to ShowOwnedPopups
2680  * and to make sure the application can't prevent showing/hiding.
2681  *
2682  * Set unmanagedOnly to TRUE to show/hide unmanaged windows only.
2683  *
2684  */
2685
2686 BOOL WIN_InternalShowOwnedPopups( HWND owner, BOOL fShow, BOOL unmanagedOnly )
2687 {
2688     int count = 0;
2689     WND *pWnd;
2690     HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2691
2692     if (!win_array) return TRUE;
2693
2694     /*
2695      * Show windows Lowest first, Highest last to preserve Z-Order
2696      */
2697     while (win_array[count]) count++;
2698     while (--count >= 0)
2699     {
2700         if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2701         if (!(pWnd = WIN_FindWndPtr( win_array[count] ))) continue;
2702
2703         if (pWnd->dwStyle & WS_POPUP)
2704         {
2705             if (fShow)
2706             {
2707                 /* check in window was flagged for showing in previous WIN_InternalShowOwnedPopups call */
2708                 if (pWnd->flags & WIN_NEEDS_INTERNALSOP)
2709                 {
2710                     /*
2711                      * Call ShowWindow directly because an application can intercept WM_SHOWWINDOW messages
2712                      */
2713                     ShowWindow(pWnd->hwndSelf,SW_SHOW);
2714                     pWnd->flags &= ~WIN_NEEDS_INTERNALSOP; /* remove the flag */
2715                 }
2716             }
2717             else
2718             {
2719                 if ( IsWindowVisible(pWnd->hwndSelf) &&                   /* hide only if window is visible */
2720                      !( pWnd->flags & WIN_NEEDS_INTERNALSOP ) &&          /* don't hide if previous call already did it */
2721                      !( unmanagedOnly && (pWnd->dwExStyle & WS_EX_MANAGED) ) ) /* don't hide managed windows if unmanagedOnly is TRUE */
2722                 {
2723                     /*
2724                      * Call ShowWindow directly because an application can intercept WM_SHOWWINDOW messages
2725                      */
2726                     ShowWindow(pWnd->hwndSelf,SW_HIDE);
2727                     /* flag the window for showing on next WIN_InternalShowOwnedPopups call */
2728                     pWnd->flags |= WIN_NEEDS_INTERNALSOP;
2729                 }
2730             }
2731         }
2732         WIN_ReleaseWndPtr( pWnd );
2733     }
2734     HeapFree( GetProcessHeap(), 0, win_array );
2735
2736     return TRUE;
2737 }
2738
2739 /*******************************************************************
2740  *              ShowOwnedPopups (USER32.@)
2741  */
2742 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2743 {
2744     int count = 0;
2745     WND *pWnd;
2746     HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2747
2748     if (!win_array) return TRUE;
2749
2750     while (win_array[count]) count++;
2751     while (--count >= 0)
2752     {
2753         if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2754         if (!(pWnd = WIN_FindWndPtr( win_array[count] ))) continue;
2755
2756         if (pWnd->dwStyle & WS_POPUP)
2757         {
2758             if (fShow)
2759             {
2760                 if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2761                 {
2762                     /* In Windows, ShowOwnedPopups(TRUE) generates
2763                      * WM_SHOWWINDOW messages with SW_PARENTOPENING,
2764                      * regardless of the state of the owner
2765                      */
2766                     SendMessageA(pWnd->hwndSelf, WM_SHOWWINDOW, SW_SHOW, SW_PARENTOPENING);
2767                     pWnd->flags &= ~WIN_NEEDS_SHOW_OWNEDPOPUP;
2768                 }
2769             }
2770             else
2771             {
2772                 if (IsWindowVisible(pWnd->hwndSelf))
2773                 {
2774                     /* In Windows, ShowOwnedPopups(FALSE) generates
2775                      * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
2776                      * regardless of the state of the owner
2777                      */
2778                     SendMessageA(pWnd->hwndSelf, WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
2779                     pWnd->flags |= WIN_NEEDS_SHOW_OWNEDPOPUP;
2780                 }
2781             }
2782         }
2783         WIN_ReleaseWndPtr( pWnd );
2784     }
2785     HeapFree( GetProcessHeap(), 0, win_array );
2786     return TRUE;
2787 }
2788
2789
2790 /*******************************************************************
2791  *              GetLastActivePopup (USER32.@)
2792  */
2793 HWND WINAPI GetLastActivePopup( HWND hwnd )
2794 {
2795     HWND retval;
2796     WND *wndPtr =WIN_FindWndPtr(hwnd);
2797     if (!wndPtr) return hwnd;
2798     retval = wndPtr->hwndLastActive;
2799     if (!IsWindow( retval )) retval = wndPtr->hwndSelf;
2800     WIN_ReleaseWndPtr(wndPtr);
2801     return retval;
2802 }
2803
2804
2805 /*******************************************************************
2806  *           WIN_ListParents
2807  *
2808  * Build an array of all parents of a given window, starting with
2809  * the immediate parent. The array must be freed with HeapFree.
2810  * Returns NULL if window is a top-level window.
2811  */
2812 HWND *WIN_ListParents( HWND hwnd )
2813 {
2814     WND *win;
2815     HWND current, *list;
2816     int pos = 0, size = 16, count = 0;
2817
2818     if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
2819
2820     current = hwnd;
2821     for (;;)
2822     {
2823         if (!(win = WIN_GetPtr( current ))) goto empty;
2824         if (win == WND_OTHER_PROCESS) break;  /* need to do it the hard way */
2825         list[pos] = win->parent;
2826         WIN_ReleasePtr( win );
2827         if (!(current = list[pos]))
2828         {
2829             if (!pos) goto empty;
2830             return list;
2831         }
2832         if (++pos == size - 1)
2833         {
2834             /* need to grow the list */
2835             HWND *new_list = HeapReAlloc( GetProcessHeap(), 0, list, (size+16) * sizeof(HWND) );
2836             if (!new_list) goto empty;
2837             list = new_list;
2838             size += 16;
2839         }
2840     }
2841
2842     /* at least one parent belongs to another process, have to query the server */
2843
2844     for (;;)
2845     {
2846         count = 0;
2847         SERVER_START_REQ( get_window_parents )
2848         {
2849             req->handle = hwnd;
2850             wine_server_set_reply( req, list, (size-1) * sizeof(HWND) );
2851             if (!wine_server_call( req )) count = reply->count;
2852         }
2853         SERVER_END_REQ;
2854         if (!count) goto empty;
2855         if (size > count)
2856         {
2857             list[count] = 0;
2858             return list;
2859         }
2860         HeapFree( GetProcessHeap(), 0, list );
2861         size = count + 1;
2862         if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
2863     }
2864
2865  empty:
2866     HeapFree( GetProcessHeap(), 0, list );
2867     return NULL;
2868 }
2869
2870
2871 /*******************************************************************
2872  *           WIN_ListChildren
2873  *
2874  * Build an array of the children of a given window. The array must be
2875  * freed with HeapFree. Returns NULL when no windows are found.
2876  */
2877 HWND *WIN_ListChildren( HWND hwnd )
2878 {
2879     return list_window_children( hwnd, 0, 0 );
2880 }
2881
2882
2883 /*******************************************************************
2884  *              EnumWindows (USER32.@)
2885  */
2886 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
2887 {
2888     HWND *list;
2889     BOOL ret = TRUE;
2890     int i, iWndsLocks;
2891
2892     /* We have to build a list of all windows first, to avoid */
2893     /* unpleasant side-effects, for instance if the callback */
2894     /* function changes the Z-order of the windows.          */
2895
2896     if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
2897
2898     /* Now call the callback function for every window */
2899
2900     iWndsLocks = WIN_SuspendWndsLock();
2901     for (i = 0; list[i]; i++)
2902     {
2903         /* Make sure that the window still exists */
2904         if (!IsWindow( list[i] )) continue;
2905         if (!(ret = lpEnumFunc( list[i], lParam ))) break;
2906     }
2907     WIN_RestoreWndsLock(iWndsLocks);
2908     HeapFree( GetProcessHeap(), 0, list );
2909     return ret;
2910 }
2911
2912
2913 /**********************************************************************
2914  *              EnumThreadWindows (USER32.@)
2915  */
2916 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
2917 {
2918     HWND *list;
2919     int i, iWndsLocks;
2920
2921     if (!(list = list_window_children( GetDesktopWindow(), 0, GetCurrentThreadId() )))
2922         return TRUE ;
2923
2924     /* Now call the callback function for every window */
2925
2926     iWndsLocks = WIN_SuspendWndsLock();
2927     for (i = 0; list[i]; i++)
2928         if (!func( list[i], lParam )) break;
2929     WIN_RestoreWndsLock(iWndsLocks);
2930     HeapFree( GetProcessHeap(), 0, list );
2931     return TRUE;
2932 }
2933
2934
2935 /**********************************************************************
2936  *           WIN_EnumChildWindows
2937  *
2938  * Helper function for EnumChildWindows().
2939  */
2940 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
2941 {
2942     HWND *childList;
2943     BOOL ret = FALSE;
2944
2945     for ( ; *list; list++)
2946     {
2947         /* Make sure that the window still exists */
2948         if (!IsWindow( *list )) continue;
2949         /* skip owned windows */
2950         if (GetWindow( *list, GW_OWNER )) continue;
2951         /* Build children list first */
2952         childList = WIN_ListChildren( *list );
2953
2954         ret = func( *list, lParam );
2955
2956         if (childList)
2957         {
2958             if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
2959             HeapFree( GetProcessHeap(), 0, childList );
2960         }
2961         if (!ret) return FALSE;
2962     }
2963     return TRUE;
2964 }
2965
2966
2967 /**********************************************************************
2968  *              EnumChildWindows (USER32.@)
2969  */
2970 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
2971 {
2972     HWND *list;
2973     int iWndsLocks;
2974
2975     if (!(list = WIN_ListChildren( parent ))) return FALSE;
2976     iWndsLocks = WIN_SuspendWndsLock();
2977     WIN_EnumChildWindows( list, func, lParam );
2978     WIN_RestoreWndsLock(iWndsLocks);
2979     HeapFree( GetProcessHeap(), 0, list );
2980     return TRUE;
2981 }
2982
2983
2984 /*******************************************************************
2985  *              AnyPopup (USER.52)
2986  */
2987 BOOL16 WINAPI AnyPopup16(void)
2988 {
2989     return AnyPopup();
2990 }
2991
2992
2993 /*******************************************************************
2994  *              AnyPopup (USER32.@)
2995  */
2996 BOOL WINAPI AnyPopup(void)
2997 {
2998     int i;
2999     BOOL retvalue;
3000     HWND *list = WIN_ListChildren( GetDesktopWindow() );
3001
3002     if (!list) return FALSE;
3003     for (i = 0; list[i]; i++)
3004     {
3005         if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
3006     }
3007     retvalue = (list[i] != 0);
3008     HeapFree( GetProcessHeap(), 0, list );
3009     return retvalue;
3010 }
3011
3012
3013 /*******************************************************************
3014  *              FlashWindow (USER32.@)
3015  */
3016 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3017 {
3018     WND *wndPtr = WIN_FindWndPtr(hWnd);
3019
3020     TRACE("%04x\n", hWnd);
3021
3022     if (!wndPtr) return FALSE;
3023     hWnd = wndPtr->hwndSelf;  /* make it a full handle */
3024
3025     if (wndPtr->dwStyle & WS_MINIMIZE)
3026     {
3027         if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
3028         {
3029             HDC hDC = GetDC(hWnd);
3030
3031             if (!SendMessageW( hWnd, WM_ERASEBKGND, (WPARAM16)hDC, 0 ))
3032                 wndPtr->flags |= WIN_NEEDS_ERASEBKGND;
3033
3034             ReleaseDC( hWnd, hDC );
3035             wndPtr->flags |= WIN_NCACTIVATED;
3036         }
3037         else
3038         {
3039             RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
3040             wndPtr->flags &= ~WIN_NCACTIVATED;
3041         }
3042         WIN_ReleaseWndPtr(wndPtr);
3043         return TRUE;
3044     }
3045     else
3046     {
3047         WPARAM16 wparam;
3048         if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3049         else wparam = (hWnd == GetActiveWindow());
3050
3051         WIN_ReleaseWndPtr(wndPtr);
3052         SendMessageW( hWnd, WM_NCACTIVATE, wparam, (LPARAM)0 );
3053         return wparam;
3054     }
3055 }
3056
3057
3058 /*******************************************************************
3059  *              GetWindowContextHelpId (USER32.@)
3060  */
3061 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3062 {
3063     DWORD retval;
3064     WND *wnd = WIN_FindWndPtr( hwnd );
3065     if (!wnd) return 0;
3066     retval = wnd->helpContext;
3067     WIN_ReleaseWndPtr(wnd);
3068     return retval;
3069 }
3070
3071
3072 /*******************************************************************
3073  *              SetWindowContextHelpId (USER32.@)
3074  */
3075 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3076 {
3077     WND *wnd = WIN_FindWndPtr( hwnd );
3078     if (!wnd) return FALSE;
3079     wnd->helpContext = id;
3080     WIN_ReleaseWndPtr(wnd);
3081     return TRUE;
3082 }
3083
3084
3085 /*******************************************************************
3086  *                      DRAG_QueryUpdate
3087  *
3088  * recursively find a child that contains spDragInfo->pt point
3089  * and send WM_QUERYDROPOBJECT
3090  */
3091 BOOL16 DRAG_QueryUpdate( HWND hQueryWnd, SEGPTR spDragInfo, BOOL bNoSend )
3092 {
3093     BOOL16 wParam, bResult = 0;
3094     POINT pt;
3095     LPDRAGINFO16 ptrDragInfo = MapSL(spDragInfo);
3096     RECT tempRect;
3097
3098     if (!ptrDragInfo) return FALSE;
3099
3100     CONV_POINT16TO32( &ptrDragInfo->pt, &pt );
3101
3102     GetWindowRect(hQueryWnd,&tempRect);
3103
3104     if( !PtInRect(&tempRect,pt) || !IsWindowEnabled(hQueryWnd)) return FALSE;
3105
3106     if (!IsIconic( hQueryWnd ))
3107     {
3108         GetClientRect( hQueryWnd, &tempRect );
3109         MapWindowPoints( hQueryWnd, 0, (LPPOINT)&tempRect, 2 );
3110
3111         if (PtInRect( &tempRect, pt))
3112         {
3113             int i;
3114             HWND *list = WIN_ListChildren( hQueryWnd );
3115
3116             wParam = 0;
3117
3118             if (list)
3119             {
3120                 for (i = 0; list[i]; i++)
3121                 {
3122                     if (GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)
3123                     {
3124                         GetWindowRect( list[i], &tempRect );
3125                         if (PtInRect( &tempRect, pt )) break;
3126                     }
3127                 }
3128                 if (list[i])
3129                 {
3130                     if (IsWindowEnabled( list[i] ))
3131                         bResult = DRAG_QueryUpdate( list[i], spDragInfo, bNoSend );
3132                 }
3133                 HeapFree( GetProcessHeap(), 0, list );
3134             }
3135             if(bResult) return bResult;
3136         }
3137         else wParam = 1;
3138     }
3139     else wParam = 1;
3140
3141     ScreenToClient16(hQueryWnd,&ptrDragInfo->pt);
3142
3143     ptrDragInfo->hScope = hQueryWnd;
3144
3145     if (bNoSend) bResult = (GetWindowLongA( hQueryWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES) != 0;
3146     else bResult = SendMessage16( hQueryWnd, WM_QUERYDROPOBJECT, (WPARAM16)wParam, spDragInfo );
3147
3148     if( !bResult ) CONV_POINT32TO16( &pt, &ptrDragInfo->pt );
3149
3150     return bResult;
3151 }
3152
3153
3154 /*******************************************************************
3155  *              DragDetect (USER32.@)
3156  */
3157 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3158 {
3159     MSG msg;
3160     RECT rect;
3161
3162     rect.left = pt.x - wDragWidth;
3163     rect.right = pt.x + wDragWidth;
3164
3165     rect.top = pt.y - wDragHeight;
3166     rect.bottom = pt.y + wDragHeight;
3167
3168     SetCapture(hWnd);
3169
3170     while(1)
3171     {
3172         while(PeekMessageA(&msg ,0 ,WM_MOUSEFIRST ,WM_MOUSELAST ,PM_REMOVE))
3173         {
3174             if( msg.message == WM_LBUTTONUP )
3175             {
3176                 ReleaseCapture();
3177                 return 0;
3178             }
3179             if( msg.message == WM_MOUSEMOVE )
3180             {
3181                 POINT tmp;
3182                 tmp.x = LOWORD(msg.lParam);
3183                 tmp.y = HIWORD(msg.lParam);
3184                 if( !PtInRect( &rect, tmp ))
3185                 {
3186                     ReleaseCapture();
3187                     return 1;
3188                 }
3189             }
3190         }
3191         WaitMessage();
3192     }
3193     return 0;
3194 }
3195
3196 /******************************************************************************
3197  *              DragObject (USER.464)
3198  */
3199 DWORD WINAPI DragObject16( HWND16 hwndScope, HWND16 hWnd, UINT16 wObj,
3200                            HANDLE16 hOfStruct, WORD szList, HCURSOR16 hCursor )
3201 {
3202     MSG msg;
3203     LPDRAGINFO16 lpDragInfo;
3204     SEGPTR      spDragInfo;
3205     HCURSOR16   hDragCursor=0, hOldCursor=0, hBummer=0;
3206     HGLOBAL16   hDragInfo  = GlobalAlloc16( GMEM_SHARE | GMEM_ZEROINIT, 2*sizeof(DRAGINFO16));
3207     HCURSOR16   hCurrentCursor = 0;
3208     HWND16      hCurrentWnd = 0;
3209
3210     lpDragInfo = (LPDRAGINFO16) GlobalLock16(hDragInfo);
3211     spDragInfo = K32WOWGlobalLock16(hDragInfo);
3212
3213     if( !lpDragInfo || !spDragInfo ) return 0L;
3214
3215     if (!(hBummer = LoadCursorA(0, MAKEINTRESOURCEA(OCR_NO))))
3216     {
3217         GlobalFree16(hDragInfo);
3218         return 0L;
3219     }
3220
3221     if(hCursor)
3222     {
3223         if( !(hDragCursor = CURSORICON_IconToCursor(hCursor, FALSE)) )
3224         {
3225             GlobalFree16(hDragInfo);
3226             return 0L;
3227         }
3228
3229         if( hDragCursor == hCursor ) hDragCursor = 0;
3230         else hCursor = hDragCursor;
3231
3232         hOldCursor = SetCursor(hDragCursor);
3233     }
3234
3235     lpDragInfo->hWnd   = hWnd;
3236     lpDragInfo->hScope = 0;
3237     lpDragInfo->wFlags = wObj;
3238     lpDragInfo->hList  = szList; /* near pointer! */
3239     lpDragInfo->hOfStruct = hOfStruct;
3240     lpDragInfo->l = 0L;
3241
3242     SetCapture(hWnd);
3243     ShowCursor( TRUE );
3244
3245     do
3246     {
3247         GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST );
3248
3249        *(lpDragInfo+1) = *lpDragInfo;
3250
3251         lpDragInfo->pt.x = msg.pt.x;
3252         lpDragInfo->pt.y = msg.pt.y;
3253
3254         /* update DRAGINFO struct */
3255         TRACE_(msg)("lpDI->hScope = %04x\n",lpDragInfo->hScope);
3256
3257         if( DRAG_QueryUpdate(hwndScope, spDragInfo, FALSE) > 0 )
3258             hCurrentCursor = hCursor;
3259         else
3260         {
3261             hCurrentCursor = hBummer;
3262             lpDragInfo->hScope = 0;
3263         }
3264         if( hCurrentCursor )
3265             SetCursor(hCurrentCursor);
3266
3267         /* send WM_DRAGLOOP */
3268         SendMessage16( hWnd, WM_DRAGLOOP, (WPARAM16)(hCurrentCursor != hBummer),
3269                                           (LPARAM) spDragInfo );
3270         /* send WM_DRAGSELECT or WM_DRAGMOVE */
3271         if( hCurrentWnd != lpDragInfo->hScope )
3272         {
3273             if( hCurrentWnd )
3274                 SendMessage16( hCurrentWnd, WM_DRAGSELECT, 0,
3275                        (LPARAM)MAKELONG(LOWORD(spDragInfo)+sizeof(DRAGINFO16),
3276                                         HIWORD(spDragInfo)) );
3277             hCurrentWnd = lpDragInfo->hScope;
3278             if( hCurrentWnd )
3279                 SendMessage16( hCurrentWnd, WM_DRAGSELECT, 1, (LPARAM)spDragInfo);
3280         }
3281         else
3282             if( hCurrentWnd )
3283                 SendMessage16( hCurrentWnd, WM_DRAGMOVE, 0, (LPARAM)spDragInfo);
3284
3285     } while( msg.message != WM_LBUTTONUP && msg.message != WM_NCLBUTTONUP );
3286
3287     ReleaseCapture();
3288     ShowCursor( FALSE );
3289
3290     if( hCursor )
3291     {
3292         SetCursor( hOldCursor );
3293         if (hDragCursor) DestroyCursor( hDragCursor );
3294     }
3295
3296     if( hCurrentCursor != hBummer )
3297         msg.lParam = SendMessage16( lpDragInfo->hScope, WM_DROPOBJECT,
3298                                    (WPARAM16)hWnd, (LPARAM)spDragInfo );
3299     else
3300         msg.lParam = 0;
3301     GlobalFree16(hDragInfo);
3302
3303     return (DWORD)(msg.lParam);
3304 }
3305
3306
3307 /******************************************************************************
3308  *              GetWindowModuleFileNameA (USER32.@)
3309  */
3310 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR lpszFileName, UINT cchFileNameMax)
3311 {
3312     FIXME("GetWindowModuleFileNameA(hwnd 0x%x, lpszFileName %p, cchFileNameMax %u) stub!\n",
3313           hwnd, lpszFileName, cchFileNameMax);
3314     return 0;
3315 }
3316
3317 /******************************************************************************
3318  *              GetWindowModuleFileNameW (USER32.@)
3319  */
3320 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPSTR lpszFileName, UINT cchFileNameMax)
3321 {
3322     FIXME("GetWindowModuleFileNameW(hwnd 0x%x, lpszFileName %p, cchFileNameMax %u) stub!\n",
3323           hwnd, lpszFileName, cchFileNameMax);
3324     return 0;
3325 }