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