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