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