Make EnumWindows return TRUE if no windows exists.
[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, 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     /* Correct the window style - stage 2 */
1071
1072     if (!(cs->style & WS_CHILD))
1073     {
1074         wndPtr->dwStyle |= WS_CLIPSIBLINGS;
1075         if (!(cs->style & WS_POPUP))
1076         {
1077             wndPtr->dwStyle |= WS_CAPTION;
1078             wndPtr->flags |= WIN_NEED_SIZE;
1079         }
1080     }
1081     SERVER_START_REQ( set_window_info )
1082     {
1083         req->handle    = hwnd;
1084         req->flags     = SET_WIN_STYLE | SET_WIN_EXSTYLE | SET_WIN_INSTANCE;
1085         req->style     = wndPtr->dwStyle;
1086         req->ex_style  = wndPtr->dwExStyle;
1087         req->instance  = (void *)wndPtr->hInstance;
1088         wine_server_call( req );
1089     }
1090     SERVER_END_REQ;
1091
1092     /* Get class or window DC if needed */
1093
1094     if (clsStyle & CS_OWNDC) wndPtr->dce = DCE_AllocDCE(hwnd,DCE_WINDOW_DC);
1095     else if (clsStyle & CS_CLASSDC) wndPtr->dce = dce;
1096     else wndPtr->dce = NULL;
1097
1098     /* Set the window menu */
1099
1100     if ((wndPtr->dwStyle & (WS_CAPTION | WS_CHILD)) == WS_CAPTION )
1101     {
1102         if (cs->hMenu) SetMenu(hwnd, cs->hMenu);
1103         else
1104         {
1105             LPCSTR menuName = (LPCSTR)GetClassLongA( hwnd, GCL_MENUNAME );
1106             if (menuName)
1107             {
1108                 if (HIWORD(cs->hInstance))
1109                     cs->hMenu = LoadMenuA(cs->hInstance,menuName);
1110                 else
1111                     cs->hMenu = LoadMenu16(cs->hInstance,menuName);
1112
1113                 if (cs->hMenu) SetMenu( hwnd, cs->hMenu );
1114             }
1115         }
1116     }
1117     else SetWindowLongW( hwnd, GWL_ID, (UINT)cs->hMenu );
1118     WIN_ReleaseWndPtr( wndPtr );
1119
1120     if (!USER_Driver.pCreateWindow( hwnd, cs, unicode))
1121     {
1122         WIN_DestroyWindow( hwnd );
1123         return 0;
1124     }
1125
1126     /* Notify the parent window only */
1127
1128     send_parent_notify( hwnd, WM_CREATE );
1129     if (!IsWindow( hwnd )) return 0;
1130
1131     if (cs->style & WS_VISIBLE)
1132     {
1133         /* in case WS_VISIBLE got set in the meantime */
1134         if (!(wndPtr = WIN_GetPtr( hwnd ))) return 0;
1135         WIN_SetStyle( hwnd, wndPtr->dwStyle & ~WS_VISIBLE );
1136         WIN_ReleasePtr( wndPtr );
1137         ShowWindow( hwnd, sw );
1138     }
1139
1140     /* Call WH_SHELL hook */
1141
1142     if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1143         HOOK_CallHooksA( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0 );
1144
1145     TRACE("created window %04x\n", hwnd);
1146     return hwnd;
1147 }
1148
1149
1150 /***********************************************************************
1151  *              CreateWindow (USER.41)
1152  */
1153 HWND16 WINAPI CreateWindow16( LPCSTR className, LPCSTR windowName,
1154                               DWORD style, INT16 x, INT16 y, INT16 width,
1155                               INT16 height, HWND16 parent, HMENU16 menu,
1156                               HINSTANCE16 instance, LPVOID data )
1157 {
1158     return CreateWindowEx16( 0, className, windowName, style,
1159                            x, y, width, height, parent, menu, instance, data );
1160 }
1161
1162
1163 /***********************************************************************
1164  *              CreateWindowEx (USER.452)
1165  */
1166 HWND16 WINAPI CreateWindowEx16( DWORD exStyle, LPCSTR className,
1167                                 LPCSTR windowName, DWORD style, INT16 x,
1168                                 INT16 y, INT16 width, INT16 height,
1169                                 HWND16 parent, HMENU16 menu,
1170                                 HINSTANCE16 instance, LPVOID data )
1171 {
1172     ATOM classAtom;
1173     CREATESTRUCTA cs;
1174     char buffer[256];
1175
1176     /* Find the class atom */
1177
1178     if (HIWORD(className))
1179     {
1180         if (!(classAtom = GlobalFindAtomA( className )))
1181         {
1182             ERR( "bad class name %s\n", debugres_a(className) );
1183             return 0;
1184         }
1185     }
1186     else
1187     {
1188         classAtom = LOWORD(className);
1189         if (!GlobalGetAtomNameA( classAtom, buffer, sizeof(buffer) ))
1190         {
1191             ERR( "bad atom %x\n", classAtom);
1192             return 0;
1193         }
1194         className = buffer;
1195     }
1196
1197     /* Fix the coordinates */
1198
1199     cs.x  = (x == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)x;
1200     cs.y  = (y == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)y;
1201     cs.cx = (width == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)width;
1202     cs.cy = (height == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)height;
1203
1204     /* Create the window */
1205
1206     cs.lpCreateParams = data;
1207     cs.hInstance      = (HINSTANCE)instance;
1208     cs.hMenu          = (HMENU)menu;
1209     cs.hwndParent     = WIN_Handle32( parent );
1210     cs.style          = style;
1211     cs.lpszName       = windowName;
1212     cs.lpszClass      = className;
1213     cs.dwExStyle      = exStyle;
1214
1215     return WIN_Handle16( WIN_CreateWindowEx( &cs, classAtom, WIN_PROC_16 ));
1216 }
1217
1218
1219 /***********************************************************************
1220  *              CreateWindowExA (USER32.@)
1221  */
1222 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1223                                  LPCSTR windowName, DWORD style, INT x,
1224                                  INT y, INT width, INT height,
1225                                  HWND parent, HMENU menu,
1226                                  HINSTANCE instance, LPVOID data )
1227 {
1228     ATOM classAtom;
1229     CREATESTRUCTA cs;
1230     char buffer[256];
1231
1232     if(!instance)
1233         instance=GetModuleHandleA(NULL);
1234
1235     if(exStyle & WS_EX_MDICHILD)
1236         return CreateMDIWindowA(className, windowName, style, x, y, width, height, parent, instance, (LPARAM)data);
1237
1238     /* Find the class atom */
1239
1240     if (HIWORD(className))
1241     {
1242         if (!(classAtom = GlobalFindAtomA( className )))
1243         {
1244             ERR( "bad class name %s\n", debugres_a(className) );
1245             return 0;
1246         }
1247     }
1248     else
1249     {
1250         classAtom = LOWORD(className);
1251         if (!GlobalGetAtomNameA( classAtom, buffer, sizeof(buffer) ))
1252         {
1253             ERR( "bad atom %x\n", classAtom);
1254             return 0;
1255         }
1256         className = buffer;
1257     }
1258
1259     /* Create the window */
1260
1261     cs.lpCreateParams = data;
1262     cs.hInstance      = instance;
1263     cs.hMenu          = menu;
1264     cs.hwndParent     = parent;
1265     cs.x              = x;
1266     cs.y              = y;
1267     cs.cx             = width;
1268     cs.cy             = height;
1269     cs.style          = style;
1270     cs.lpszName       = windowName;
1271     cs.lpszClass      = className;
1272     cs.dwExStyle      = exStyle;
1273
1274     return WIN_CreateWindowEx( &cs, classAtom, WIN_PROC_32A );
1275 }
1276
1277
1278 /***********************************************************************
1279  *              CreateWindowExW (USER32.@)
1280  */
1281 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1282                                  LPCWSTR windowName, DWORD style, INT x,
1283                                  INT y, INT width, INT height,
1284                                  HWND parent, HMENU menu,
1285                                  HINSTANCE instance, LPVOID data )
1286 {
1287     ATOM classAtom;
1288     CREATESTRUCTW cs;
1289     WCHAR buffer[256];
1290
1291     if(!instance)
1292         instance=GetModuleHandleA(NULL);
1293
1294     if(exStyle & WS_EX_MDICHILD)
1295         return CreateMDIWindowW(className, windowName, style, x, y, width, height, parent, instance, (LPARAM)data);
1296
1297     /* Find the class atom */
1298
1299     if (HIWORD(className))
1300     {
1301         if (!(classAtom = GlobalFindAtomW( className )))
1302         {
1303             ERR( "bad class name %s\n", debugres_w(className) );
1304             return 0;
1305         }
1306     }
1307     else
1308     {
1309         classAtom = LOWORD(className);
1310         if (!GlobalGetAtomNameW( classAtom, buffer, sizeof(buffer)/sizeof(WCHAR) ))
1311         {
1312             ERR( "bad atom %x\n", classAtom);
1313             return 0;
1314         }
1315         className = buffer;
1316     }
1317
1318     /* Create the window */
1319
1320     cs.lpCreateParams = data;
1321     cs.hInstance      = instance;
1322     cs.hMenu          = menu;
1323     cs.hwndParent     = parent;
1324     cs.x              = x;
1325     cs.y              = y;
1326     cs.cx             = width;
1327     cs.cy             = height;
1328     cs.style          = style;
1329     cs.lpszName       = windowName;
1330     cs.lpszClass      = className;
1331     cs.dwExStyle      = exStyle;
1332
1333     /* Note: we rely on the fact that CREATESTRUCTA and */
1334     /* CREATESTRUCTW have the same layout. */
1335     return WIN_CreateWindowEx( (CREATESTRUCTA *)&cs, classAtom, WIN_PROC_32W );
1336 }
1337
1338
1339 /***********************************************************************
1340  *           WIN_SendDestroyMsg
1341  */
1342 static void WIN_SendDestroyMsg( HWND hwnd )
1343 {
1344     if( CARET_GetHwnd() == hwnd) DestroyCaret();
1345     if (USER_Driver.pResetSelectionOwner)
1346         USER_Driver.pResetSelectionOwner( hwnd, TRUE );
1347
1348     /*
1349      * Send the WM_DESTROY to the window.
1350      */
1351     SendMessageA( hwnd, WM_DESTROY, 0, 0);
1352
1353     /*
1354      * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1355      * make sure that the window still exists when we come back.
1356      */
1357     if (IsWindow(hwnd))
1358     {
1359         HWND* pWndArray;
1360         int i;
1361
1362         if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1363
1364         /* start from the end (FIXME: is this needed?) */
1365         for (i = 0; pWndArray[i]; i++) ;
1366
1367         while (--i >= 0)
1368         {
1369             if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1370         }
1371         HeapFree( GetProcessHeap(), 0, pWndArray );
1372     }
1373     else
1374       WARN("\tdestroyed itself while in WM_DESTROY!\n");
1375 }
1376
1377
1378 /***********************************************************************
1379  *              DestroyWindow (USER32.@)
1380  */
1381 BOOL WINAPI DestroyWindow( HWND hwnd )
1382 {
1383     BOOL is_child;
1384     HWND h;
1385
1386     if (!(hwnd = WIN_IsCurrentThread( hwnd )) || (hwnd == GetDesktopWindow()))
1387     {
1388         SetLastError( ERROR_ACCESS_DENIED );
1389         return FALSE;
1390     }
1391
1392     TRACE("(%04x)\n", hwnd);
1393
1394     /* Look whether the focus is within the tree of windows we will
1395      * be destroying.
1396      */
1397     h = GetFocus();
1398     if (h == hwnd || IsChild( hwnd, h ))
1399     {
1400         HWND parent = GetAncestor( hwnd, GA_PARENT );
1401         if (parent == GetDesktopWindow()) parent = 0;
1402         SetFocus( parent );
1403     }
1404
1405       /* Call hooks */
1406
1407     if( HOOK_CallHooksA( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0L) ) return FALSE;
1408
1409     is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;
1410
1411     if (is_child)
1412     {
1413         if (!USER_IsExitingThread( GetCurrentThreadId() ))
1414             send_parent_notify( hwnd, WM_DESTROY );
1415     }
1416     else if (!GetWindow( hwnd, GW_OWNER ))
1417     {
1418         HOOK_CallHooksA( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L );
1419         /* FIXME: clean up palette - see "Internals" p.352 */
1420     }
1421
1422     if (!IsWindow(hwnd)) return TRUE;
1423
1424     if (USER_Driver.pResetSelectionOwner)
1425         USER_Driver.pResetSelectionOwner( hwnd, FALSE ); /* before the window is unmapped */
1426
1427       /* Hide the window */
1428
1429     ShowWindow( hwnd, SW_HIDE );
1430     if (!IsWindow(hwnd)) return TRUE;
1431
1432       /* Recursively destroy owned windows */
1433
1434     if (!is_child)
1435     {
1436         HWND owner;
1437
1438         for (;;)
1439         {
1440             int i, got_one = 0;
1441             HWND *list = WIN_ListChildren( GetDesktopWindow() );
1442             if (list)
1443             {
1444                 for (i = 0; list[i]; i++)
1445                 {
1446                     if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1447                     if (WIN_IsCurrentThread( list[i] ))
1448                     {
1449                         DestroyWindow( list[i] );
1450                         got_one = 1;
1451                         continue;
1452                     }
1453                     WIN_SetOwner( list[i], 0 );
1454                 }
1455                 HeapFree( GetProcessHeap(), 0, list );
1456             }
1457             if (!got_one) break;
1458         }
1459
1460         WINPOS_ActivateOtherWindow( hwnd );
1461
1462         if ((owner = GetWindow( hwnd, GW_OWNER )))
1463         {
1464             WND *ptr = WIN_FindWndPtr( owner );
1465             if (ptr)
1466             {
1467                 if (ptr->hwndLastActive == hwnd) ptr->hwndLastActive = owner;
1468                 WIN_ReleaseWndPtr( ptr );
1469             }
1470         }
1471     }
1472
1473       /* Send destroy messages */
1474
1475     WIN_SendDestroyMsg( hwnd );
1476     if (!IsWindow( hwnd )) return TRUE;
1477
1478       /* Unlink now so we won't bother with the children later on */
1479
1480     WIN_UnlinkWindow( hwnd );
1481
1482       /* Destroy the window storage */
1483
1484     WIN_DestroyWindow( hwnd );
1485     return TRUE;
1486 }
1487
1488
1489 /***********************************************************************
1490  *              CloseWindow (USER32.@)
1491  */
1492 BOOL WINAPI CloseWindow( HWND hwnd )
1493 {
1494     if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1495     ShowWindow( hwnd, SW_MINIMIZE );
1496     return TRUE;
1497 }
1498
1499
1500 /***********************************************************************
1501  *              OpenIcon (USER32.@)
1502  */
1503 BOOL WINAPI OpenIcon( HWND hwnd )
1504 {
1505     if (!IsIconic( hwnd )) return FALSE;
1506     ShowWindow( hwnd, SW_SHOWNORMAL );
1507     return TRUE;
1508 }
1509
1510
1511 /***********************************************************************
1512  *           WIN_FindWindow
1513  *
1514  * Implementation of FindWindow() and FindWindowEx().
1515  */
1516 static HWND WIN_FindWindow( HWND parent, HWND child, ATOM className, LPCWSTR title )
1517 {
1518     HWND *list = NULL;
1519     HWND retvalue = 0;
1520     int i = 0, len = 0;
1521     WCHAR *buffer = NULL;
1522
1523     if (!parent) parent = GetDesktopWindow();
1524     if (title)
1525     {
1526         len = strlenW(title) + 1;  /* one extra char to check for chars beyond the end */
1527         if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1528     }
1529
1530     if (!(list = list_window_children( parent, className, 0 ))) goto done;
1531
1532     if (child)
1533     {
1534         child = WIN_GetFullHandle( child );
1535         while (list[i] && list[i] != child) i++;
1536         if (!list[i]) goto done;
1537         i++;  /* start from next window */
1538     }
1539
1540     if (title)
1541     {
1542         while (list[i])
1543         {
1544             if (GetWindowTextW( list[i], buffer, len ) && !strcmpiW( buffer, title )) break;
1545             i++;
1546         }
1547     }
1548     retvalue = list[i];
1549
1550  done:
1551     if (list) HeapFree( GetProcessHeap(), 0, list );
1552     if (buffer) HeapFree( GetProcessHeap(), 0, buffer );
1553     return retvalue;
1554 }
1555
1556
1557
1558 /***********************************************************************
1559  *              FindWindowA (USER32.@)
1560  */
1561 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1562 {
1563     HWND ret = FindWindowExA( 0, 0, className, title );
1564     if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1565     return ret;
1566 }
1567
1568
1569 /***********************************************************************
1570  *              FindWindowExA (USER32.@)
1571  */
1572 HWND WINAPI FindWindowExA( HWND parent, HWND child,
1573                                LPCSTR className, LPCSTR title )
1574 {
1575     ATOM atom = 0;
1576     LPWSTR buffer;
1577     HWND hwnd;
1578     INT len;
1579
1580     if (className)
1581     {
1582         /* If the atom doesn't exist, then no class */
1583         /* with this name exists either. */
1584         if (!(atom = GlobalFindAtomA( className )))
1585         {
1586             SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1587             return 0;
1588         }
1589     }
1590     if (!title) return WIN_FindWindow( parent, child, atom, NULL );
1591
1592     len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
1593     if (!(buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
1594     MultiByteToWideChar( CP_ACP, 0, title, -1, buffer, len );
1595     hwnd = WIN_FindWindow( parent, child, atom, buffer );
1596     HeapFree( GetProcessHeap(), 0, buffer );
1597     return hwnd;
1598 }
1599
1600
1601 /***********************************************************************
1602  *              FindWindowExW (USER32.@)
1603  */
1604 HWND WINAPI FindWindowExW( HWND parent, HWND child,
1605                                LPCWSTR className, LPCWSTR title )
1606 {
1607     ATOM atom = 0;
1608
1609     if (className)
1610     {
1611         /* If the atom doesn't exist, then no class */
1612         /* with this name exists either. */
1613         if (!(atom = GlobalFindAtomW( className )))
1614         {
1615             SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1616             return 0;
1617         }
1618     }
1619     return WIN_FindWindow( parent, child, atom, title );
1620 }
1621
1622
1623 /***********************************************************************
1624  *              FindWindowW (USER32.@)
1625  */
1626 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
1627 {
1628     return FindWindowExW( 0, 0, className, title );
1629 }
1630
1631
1632 /**********************************************************************
1633  *              GetDesktopWindow (USER32.@)
1634  */
1635 HWND WINAPI GetDesktopWindow(void)
1636 {
1637     if (pWndDesktop) return pWndDesktop->hwndSelf;
1638     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" );
1639     ExitProcess(1);
1640     return 0;
1641 }
1642
1643
1644 /*******************************************************************
1645  *              EnableWindow (USER32.@)
1646  */
1647 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
1648 {
1649     WND *wndPtr;
1650     BOOL retvalue;
1651     LONG style;
1652     HWND full_handle;
1653
1654     if (!(full_handle = WIN_IsCurrentThread( hwnd )))
1655         return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
1656
1657     hwnd = full_handle;
1658
1659     TRACE("( %x, %d )\n", hwnd, enable);
1660
1661     if (!(wndPtr = WIN_GetPtr( hwnd ))) return FALSE;
1662     style = wndPtr->dwStyle;
1663     retvalue = ((style & WS_DISABLED) != 0);
1664     WIN_ReleasePtr( wndPtr );
1665
1666     if (enable && retvalue)
1667     {
1668         WIN_SetStyle( hwnd, style & ~WS_DISABLED );
1669         SendMessageA( hwnd, WM_ENABLE, TRUE, 0 );
1670     }
1671     else if (!enable && !retvalue)
1672     {
1673         SendMessageA( hwnd, WM_CANCELMODE, 0, 0);
1674
1675         WIN_SetStyle( hwnd, style | WS_DISABLED );
1676
1677         if (hwnd == GetFocus())
1678             SetFocus( 0 );  /* A disabled window can't have the focus */
1679
1680         if (hwnd == GetCapture())
1681             ReleaseCapture();  /* A disabled window can't capture the mouse */
1682
1683         SendMessageA( hwnd, WM_ENABLE, FALSE, 0 );
1684     }
1685     return retvalue;
1686 }
1687
1688
1689 /***********************************************************************
1690  *              IsWindowEnabled (USER32.@)
1691  */
1692 BOOL WINAPI IsWindowEnabled(HWND hWnd)
1693 {
1694     return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
1695 }
1696
1697
1698 /***********************************************************************
1699  *              IsWindowUnicode (USER32.@)
1700  */
1701 BOOL WINAPI IsWindowUnicode( HWND hwnd )
1702 {
1703     WND * wndPtr;
1704     BOOL retvalue;
1705
1706     if (!(wndPtr = WIN_FindWndPtr(hwnd))) return FALSE;
1707     retvalue = (WINPROC_GetProcType( wndPtr->winproc ) == WIN_PROC_32W);
1708     WIN_ReleaseWndPtr(wndPtr);
1709     return retvalue;
1710 }
1711
1712
1713 /**********************************************************************
1714  *              GetWindowWord (USER32.@)
1715  */
1716 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
1717 {
1718     if (offset >= 0)
1719     {
1720         WORD retvalue = 0;
1721         WND *wndPtr = WIN_GetPtr( hwnd );
1722         if (!wndPtr)
1723         {
1724             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1725             return 0;
1726         }
1727         if (wndPtr == WND_OTHER_PROCESS)
1728         {
1729             if (IsWindow( hwnd ))
1730                 FIXME( "(%d) not supported yet on other process window %x\n", offset, hwnd );
1731             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1732             return 0;
1733         }
1734         if (offset > wndPtr->cbWndExtra - sizeof(WORD))
1735         {
1736             WARN("Invalid offset %d\n", offset );
1737             SetLastError( ERROR_INVALID_INDEX );
1738         }
1739         else retvalue = *(WORD *)(((char *)wndPtr->wExtra) + offset);
1740         WIN_ReleasePtr( wndPtr );
1741         return retvalue;
1742     }
1743
1744     switch(offset)
1745     {
1746     case GWL_HWNDPARENT:
1747         return GetWindowLongW( hwnd, offset );
1748     case GWL_ID:
1749     case GWL_HINSTANCE:
1750         {
1751             LONG ret = GetWindowLongW( hwnd, offset );
1752             if (HIWORD(ret))
1753                 WARN("%d: discards high bits of 0x%08lx!\n", offset, ret );
1754             return LOWORD(ret);
1755         }
1756     default:
1757         WARN("Invalid offset %d\n", offset );
1758         return 0;
1759     }
1760 }
1761
1762
1763 /**********************************************************************
1764  *              SetWindowWord (USER32.@)
1765  */
1766 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
1767 {
1768     WORD *ptr, retval;
1769     WND * wndPtr;
1770
1771     switch(offset)
1772     {
1773     case GWL_ID:
1774     case GWL_HINSTANCE:
1775     case GWL_HWNDPARENT:
1776         return SetWindowLongW( hwnd, offset, (UINT)newval );
1777     default:
1778         if (offset < 0)
1779         {
1780             WARN("Invalid offset %d\n", offset );
1781             SetLastError( ERROR_INVALID_INDEX );
1782             return 0;
1783         }
1784     }
1785
1786     wndPtr = WIN_GetPtr( hwnd );
1787     if (wndPtr == WND_OTHER_PROCESS)
1788     {
1789         if (IsWindow(hwnd))
1790             FIXME( "set %d <- %x not supported yet on other process window %x\n",
1791                    offset, newval, hwnd );
1792         wndPtr = NULL;
1793     }
1794     if (!wndPtr)
1795     {
1796        SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1797        return 0;
1798     }
1799
1800     if (offset > wndPtr->cbWndExtra - sizeof(WORD))
1801     {
1802         WARN("Invalid offset %d\n", offset );
1803         WIN_ReleasePtr(wndPtr);
1804         SetLastError( ERROR_INVALID_INDEX );
1805         return 0;
1806     }
1807     ptr = (WORD *)(((char *)wndPtr->wExtra) + offset);
1808     retval = *ptr;
1809     *ptr = newval;
1810     WIN_ReleasePtr(wndPtr);
1811     return retval;
1812 }
1813
1814
1815 /**********************************************************************
1816  *           WIN_GetWindowLong
1817  *
1818  * Helper function for GetWindowLong().
1819  */
1820 static LONG WIN_GetWindowLong( HWND hwnd, INT offset, WINDOWPROCTYPE type )
1821 {
1822     LONG retvalue = 0;
1823     WND *wndPtr;
1824
1825     if (offset == GWL_HWNDPARENT) return (LONG)GetParent( hwnd );
1826
1827     if (!(wndPtr = WIN_GetPtr( hwnd )))
1828     {
1829         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1830         return 0;
1831     }
1832
1833     if (wndPtr == WND_OTHER_PROCESS)
1834     {
1835         if (offset >= 0)
1836         {
1837             if (IsWindow(hwnd))
1838                 FIXME( "(%d) not supported on other process window %x\n", offset, hwnd );
1839             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1840             return 0;
1841         }
1842         if (offset == GWL_WNDPROC)
1843         {
1844             SetLastError( ERROR_ACCESS_DENIED );
1845             return 0;
1846         }
1847         SERVER_START_REQ( set_window_info )
1848         {
1849             req->handle = hwnd;
1850             req->flags  = 0;  /* don't set anything, just retrieve */
1851             if (!wine_server_call_err( req ))
1852             {
1853                 switch(offset)
1854                 {
1855                 case GWL_STYLE:     retvalue = reply->old_style; break;
1856                 case GWL_EXSTYLE:   retvalue = reply->old_ex_style; break;
1857                 case GWL_ID:        retvalue = reply->old_id; break;
1858                 case GWL_HINSTANCE: retvalue = (ULONG_PTR)reply->old_instance; break;
1859                 case GWL_USERDATA:  retvalue = (ULONG_PTR)reply->old_user_data; break;
1860                 default:
1861                     SetLastError( ERROR_INVALID_INDEX );
1862                     break;
1863                 }
1864             }
1865         }
1866         SERVER_END_REQ;
1867         return retvalue;
1868     }
1869
1870     /* now we have a valid wndPtr */
1871
1872     if (offset >= 0)
1873     {
1874         if (offset > wndPtr->cbWndExtra - sizeof(LONG))
1875         {
1876             WARN("Invalid offset %d\n", offset );
1877             WIN_ReleasePtr( wndPtr );
1878             SetLastError( ERROR_INVALID_INDEX );
1879             return 0;
1880         }
1881         retvalue = *(LONG *)(((char *)wndPtr->wExtra) + offset);
1882         /* Special case for dialog window procedure */
1883         if ((offset == DWL_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
1884             retvalue = (LONG)WINPROC_GetProc( (HWINDOWPROC)retvalue, type );
1885         WIN_ReleasePtr( wndPtr );
1886         return retvalue;
1887     }
1888
1889     switch(offset)
1890     {
1891     case GWL_USERDATA:   retvalue = wndPtr->userdata; break;
1892     case GWL_STYLE:      retvalue = wndPtr->dwStyle; break;
1893     case GWL_EXSTYLE:    retvalue = wndPtr->dwExStyle; break;
1894     case GWL_ID:         retvalue = (LONG)wndPtr->wIDmenu; break;
1895     case GWL_WNDPROC:    retvalue = (LONG)WINPROC_GetProc( wndPtr->winproc, type ); break;
1896     case GWL_HINSTANCE:  retvalue = wndPtr->hInstance; break;
1897     default:
1898         WARN("Unknown offset %d\n", offset );
1899         SetLastError( ERROR_INVALID_INDEX );
1900         break;
1901     }
1902     WIN_ReleasePtr(wndPtr);
1903     return retvalue;
1904 }
1905
1906
1907 /**********************************************************************
1908  *           WIN_SetWindowLong
1909  *
1910  * Helper function for SetWindowLong().
1911  *
1912  * 0 is the failure code. However, in the case of failure SetLastError
1913  * must be set to distinguish between a 0 return value and a failure.
1914  */
1915 static LONG WIN_SetWindowLong( HWND hwnd, INT offset, LONG newval,
1916                                WINDOWPROCTYPE type )
1917 {
1918     LONG retval = 0;
1919     WND *wndPtr;
1920
1921     TRACE( "%x %d %lx %x\n", hwnd, offset, newval, type );
1922
1923     if (!WIN_IsCurrentProcess( hwnd ))
1924     {
1925         if (offset == GWL_WNDPROC)
1926         {
1927             SetLastError( ERROR_ACCESS_DENIED );
1928             return 0;
1929         }
1930         return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, offset, newval );
1931     }
1932
1933     wndPtr = WIN_GetPtr( hwnd );
1934
1935     if (offset >= 0)
1936     {
1937         LONG *ptr = (LONG *)(((char *)wndPtr->wExtra) + offset);
1938         if (offset > wndPtr->cbWndExtra - sizeof(LONG))
1939         {
1940             WARN("Invalid offset %d\n", offset );
1941             WIN_ReleasePtr( wndPtr );
1942             SetLastError( ERROR_INVALID_INDEX );
1943             return 0;
1944         }
1945         /* Special case for dialog window procedure */
1946         if ((offset == DWL_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
1947         {
1948             retval = (LONG)WINPROC_GetProc( (HWINDOWPROC)*ptr, type );
1949             WINPROC_SetProc( (HWINDOWPROC *)ptr, (WNDPROC16)newval,
1950                              type, WIN_PROC_WINDOW );
1951             WIN_ReleasePtr( wndPtr );
1952             return retval;
1953         }
1954         retval = *ptr;
1955         *ptr = newval;
1956         WIN_ReleasePtr( wndPtr );
1957     }
1958     else
1959     {
1960         STYLESTRUCT style;
1961         BOOL ok;
1962
1963         /* first some special cases */
1964         switch( offset )
1965         {
1966         case GWL_STYLE:
1967         case GWL_EXSTYLE:
1968             style.styleOld = wndPtr->dwStyle;
1969             style.styleNew = newval;
1970             WIN_ReleasePtr( wndPtr );
1971             SendMessageW( hwnd, WM_STYLECHANGING, offset, (LPARAM)&style );
1972             if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
1973             newval = style.styleNew;
1974             break;
1975         case GWL_HWNDPARENT:
1976             WIN_ReleasePtr( wndPtr );
1977             return (LONG)SetParent( hwnd, (HWND)newval );
1978         case GWL_WNDPROC:
1979             retval = (LONG)WINPROC_GetProc( wndPtr->winproc, type );
1980             WINPROC_SetProc( &wndPtr->winproc, (WNDPROC16)newval,
1981                              type, WIN_PROC_WINDOW );
1982             WIN_ReleasePtr( wndPtr );
1983             return retval;
1984         case GWL_ID:
1985         case GWL_HINSTANCE:
1986         case GWL_USERDATA:
1987             break;
1988         default:
1989             WIN_ReleasePtr( wndPtr );
1990             WARN("Invalid offset %d\n", offset );
1991             SetLastError( ERROR_INVALID_INDEX );
1992             return 0;
1993         }
1994
1995         SERVER_START_REQ( set_window_info )
1996         {
1997             req->handle = hwnd;
1998             switch(offset)
1999             {
2000             case GWL_STYLE:
2001                 req->flags = SET_WIN_STYLE;
2002                 req->style = newval;
2003                 break;
2004             case GWL_EXSTYLE:
2005                 req->flags = SET_WIN_EXSTYLE;
2006                 req->ex_style = newval;
2007                 break;
2008             case GWL_ID:
2009                 req->flags = SET_WIN_ID;
2010                 req->id = newval;
2011                 break;
2012             case GWL_HINSTANCE:
2013                 req->flags = SET_WIN_INSTANCE;
2014                 req->instance = (void *)newval;
2015                 break;
2016             case GWL_USERDATA:
2017                 req->flags = SET_WIN_USERDATA;
2018                 req->user_data = (void *)newval;
2019                 break;
2020             }
2021             if ((ok = !wine_server_call_err( req )))
2022             {
2023                 switch(offset)
2024                 {
2025                 case GWL_STYLE:
2026                     wndPtr->dwStyle = newval;
2027                     retval = reply->old_style;
2028                     break;
2029                 case GWL_EXSTYLE:
2030                     wndPtr->dwExStyle = newval;
2031                     retval = reply->old_ex_style;
2032                     break;
2033                 case GWL_ID:
2034                     wndPtr->wIDmenu = newval;
2035                     retval = reply->old_id;
2036                     break;
2037                 case GWL_HINSTANCE:
2038                     wndPtr->hInstance = newval;
2039                     retval = (HINSTANCE)reply->old_instance;
2040                     break;
2041                 case GWL_USERDATA:
2042                     wndPtr->userdata = newval;
2043                     retval = (ULONG_PTR)reply->old_user_data;
2044                     break;
2045                 }
2046             }
2047         }
2048         SERVER_END_REQ;
2049         WIN_ReleasePtr( wndPtr );
2050
2051         if (!ok) return 0;
2052
2053         if (offset == GWL_STYLE && USER_Driver.pSetWindowStyle)
2054             USER_Driver.pSetWindowStyle( hwnd, retval );
2055
2056         if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2057             SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2058
2059     }
2060     return retval;
2061 }
2062
2063
2064 /**********************************************************************
2065  *              GetWindowLong (USER.135)
2066  */
2067 LONG WINAPI GetWindowLong16( HWND16 hwnd, INT16 offset )
2068 {
2069     return WIN_GetWindowLong( WIN_Handle32(hwnd), offset, WIN_PROC_16 );
2070 }
2071
2072
2073 /**********************************************************************
2074  *              GetWindowLongA (USER32.@)
2075  */
2076 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2077 {
2078     return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32A );
2079 }
2080
2081
2082 /**********************************************************************
2083  *              GetWindowLongW (USER32.@)
2084  */
2085 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2086 {
2087     return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32W );
2088 }
2089
2090
2091 /**********************************************************************
2092  *              SetWindowLong (USER.136)
2093  */
2094 LONG WINAPI SetWindowLong16( HWND16 hwnd, INT16 offset, LONG newval )
2095 {
2096     return WIN_SetWindowLong( WIN_Handle32(hwnd), offset, newval, WIN_PROC_16 );
2097 }
2098
2099
2100 /**********************************************************************
2101  *              SetWindowLongA (USER32.@)
2102  */
2103 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2104 {
2105     return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32A );
2106 }
2107
2108
2109 /**********************************************************************
2110  *              SetWindowLongW (USER32.@) Set window attribute
2111  *
2112  * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2113  * value in a window's extra memory.
2114  *
2115  * The _hwnd_ parameter specifies the window.  is the handle to a
2116  * window that has extra memory. The _newval_ parameter contains the
2117  * new attribute or extra memory value.  If positive, the _offset_
2118  * parameter is the byte-addressed location in the window's extra
2119  * memory to set.  If negative, _offset_ specifies the window
2120  * attribute to set, and should be one of the following values:
2121  *
2122  * GWL_EXSTYLE      The window's extended window style
2123  *
2124  * GWL_STYLE        The window's window style.
2125  *
2126  * GWL_WNDPROC      Pointer to the window's window procedure.
2127  *
2128  * GWL_HINSTANCE    The window's pplication instance handle.
2129  *
2130  * GWL_ID           The window's identifier.
2131  *
2132  * GWL_USERDATA     The window's user-specified data.
2133  *
2134  * If the window is a dialog box, the _offset_ parameter can be one of
2135  * the following values:
2136  *
2137  * DWL_DLGPROC      The address of the window's dialog box procedure.
2138  *
2139  * DWL_MSGRESULT    The return value of a message
2140  *                  that the dialog box procedure processed.
2141  *
2142  * DWL_USER         Application specific information.
2143  *
2144  * RETURNS
2145  *
2146  * If successful, returns the previous value located at _offset_. Otherwise,
2147  * returns 0.
2148  *
2149  * NOTES
2150  *
2151  * Extra memory for a window class is specified by a nonzero cbWndExtra
2152  * parameter of the WNDCLASS structure passed to RegisterClass() at the
2153  * time of class creation.
2154  *
2155  * Using GWL_WNDPROC to set a new window procedure effectively creates
2156  * a window subclass. Use CallWindowProc() in the new windows procedure
2157  * to pass messages to the superclass's window procedure.
2158  *
2159  * The user data is reserved for use by the application which created
2160  * the window.
2161  *
2162  * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2163  * instead, call the EnableWindow() function to change the window's
2164  * disabled state.
2165  *
2166  * Do not use GWL_HWNDPARENT to reset the window's parent, use
2167  * SetParent() instead.
2168  *
2169  * Win95:
2170  * When offset is GWL_STYLE and the calling app's ver is 4.0,
2171  * it sends WM_STYLECHANGING before changing the settings
2172  * and WM_STYLECHANGED afterwards.
2173  * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2174  */
2175 LONG WINAPI SetWindowLongW(
2176     HWND hwnd,  /* [in] window to alter */
2177     INT offset, /* [in] offset, in bytes, of location to alter */
2178     LONG newval /* [in] new value of location */
2179 ) {
2180     return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32W );
2181 }
2182
2183
2184 /*******************************************************************
2185  *              GetWindowTextA (USER32.@)
2186  */
2187 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2188 {
2189     WCHAR *buffer;
2190
2191     if (WIN_IsCurrentProcess( hwnd ))
2192         return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2193
2194     /* when window belongs to other process, don't send a message */
2195     if (nMaxCount <= 0) return 0;
2196     if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2197     get_server_window_text( hwnd, buffer, nMaxCount );
2198     if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2199         lpString[nMaxCount-1] = 0;
2200     HeapFree( GetProcessHeap(), 0, buffer );
2201     return strlen(lpString);
2202 }
2203
2204
2205 /*******************************************************************
2206  *              InternalGetWindowText (USER32.@)
2207  */
2208 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2209 {
2210     WND *win;
2211
2212     if (nMaxCount <= 0) return 0;
2213     if (!(win = WIN_GetPtr( hwnd ))) return 0;
2214     if (win != WND_OTHER_PROCESS)
2215     {
2216         if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2217         else lpString[0] = 0;
2218         WIN_ReleasePtr( win );
2219     }
2220     else
2221     {
2222         get_server_window_text( hwnd, lpString, nMaxCount );
2223     }
2224     return strlenW(lpString);
2225 }
2226
2227
2228 /*******************************************************************
2229  *              GetWindowTextW (USER32.@)
2230  */
2231 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2232 {
2233     if (WIN_IsCurrentProcess( hwnd ))
2234         return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2235
2236     /* when window belongs to other process, don't send a message */
2237     if (nMaxCount <= 0) return 0;
2238     get_server_window_text( hwnd, lpString, nMaxCount );
2239     return strlenW(lpString);
2240 }
2241
2242
2243 /*******************************************************************
2244  *              SetWindowText  (USER32.@)
2245  *              SetWindowTextA (USER32.@)
2246  */
2247 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2248 {
2249     if (!WIN_IsCurrentProcess( hwnd ))
2250     {
2251         FIXME( "cannot set text %s of other process window %x\n", debugstr_a(lpString), hwnd );
2252         SetLastError( ERROR_ACCESS_DENIED );
2253         return FALSE;
2254     }
2255     return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2256 }
2257
2258
2259 /*******************************************************************
2260  *              SetWindowTextW (USER32.@)
2261  */
2262 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2263 {
2264     if (!WIN_IsCurrentProcess( hwnd ))
2265     {
2266         FIXME( "cannot set text %s of other process window %x\n", debugstr_w(lpString), hwnd );
2267         SetLastError( ERROR_ACCESS_DENIED );
2268         return FALSE;
2269     }
2270     return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2271 }
2272
2273
2274 /*******************************************************************
2275  *              GetWindowTextLengthA (USER32.@)
2276  */
2277 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2278 {
2279     return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2280 }
2281
2282 /*******************************************************************
2283  *              GetWindowTextLengthW (USER32.@)
2284  */
2285 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2286 {
2287     return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2288 }
2289
2290
2291 /*******************************************************************
2292  *              IsWindow (USER32.@)
2293  */
2294 BOOL WINAPI IsWindow( HWND hwnd )
2295 {
2296     WND *ptr;
2297     BOOL ret;
2298
2299     if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2300
2301     if (ptr != WND_OTHER_PROCESS)
2302     {
2303         WIN_ReleasePtr( ptr );
2304         return TRUE;
2305     }
2306
2307     /* check other processes */
2308     SERVER_START_REQ( get_window_info )
2309     {
2310         req->handle = hwnd;
2311         ret = !wine_server_call_err( req );
2312     }
2313     SERVER_END_REQ;
2314     return ret;
2315 }
2316
2317
2318 /***********************************************************************
2319  *              GetWindowThreadProcessId (USER32.@)
2320  */
2321 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2322 {
2323     WND *ptr;
2324     DWORD tid = 0;
2325
2326     if (!(ptr = WIN_GetPtr( hwnd )))
2327     {
2328         SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2329         return 0;
2330     }
2331
2332     if (ptr != WND_OTHER_PROCESS)
2333     {
2334         /* got a valid window */
2335         tid = ptr->tid;
2336         if (process) *process = GetCurrentProcessId();
2337         WIN_ReleasePtr( ptr );
2338         return tid;
2339     }
2340
2341     /* check other processes */
2342     SERVER_START_REQ( get_window_info )
2343     {
2344         req->handle = hwnd;
2345         if (!wine_server_call_err( req ))
2346         {
2347             tid = (DWORD)reply->tid;
2348             if (process) *process = (DWORD)reply->pid;
2349         }
2350     }
2351     SERVER_END_REQ;
2352     return tid;
2353 }
2354
2355
2356 /*****************************************************************
2357  *              GetParent (USER32.@)
2358  */
2359 HWND WINAPI GetParent( HWND hwnd )
2360 {
2361     WND *wndPtr;
2362     HWND retvalue = 0;
2363
2364     if (!(wndPtr = WIN_GetPtr( hwnd )))
2365     {
2366         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2367         return 0;
2368     }
2369     if (wndPtr == WND_OTHER_PROCESS)
2370     {
2371         LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2372         if (style & (WS_POPUP | WS_CHILD))
2373         {
2374             SERVER_START_REQ( get_window_tree )
2375             {
2376                 req->handle = hwnd;
2377                 if (!wine_server_call_err( req ))
2378                 {
2379                     if (style & WS_CHILD) retvalue = reply->parent;
2380                     else retvalue = reply->owner;
2381                 }
2382             }
2383             SERVER_END_REQ;
2384         }
2385     }
2386     else
2387     {
2388         if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2389         else if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2390         WIN_ReleasePtr( wndPtr );
2391     }
2392     return retvalue;
2393 }
2394
2395
2396 /*****************************************************************
2397  *              GetAncestor (USER32.@)
2398  */
2399 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2400 {
2401     WND *win;
2402     HWND *list, ret = 0;
2403
2404     if (type == GA_PARENT)
2405     {
2406         if (!(win = WIN_GetPtr( hwnd )))
2407         {
2408             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2409             return 0;
2410         }
2411         if (win != WND_OTHER_PROCESS)
2412         {
2413             ret = win->parent;
2414             WIN_ReleasePtr( win );
2415         }
2416         else /* need to query the server */
2417         {
2418             SERVER_START_REQ( get_window_tree )
2419             {
2420                 req->handle = hwnd;
2421                 if (!wine_server_call_err( req )) ret = reply->parent;
2422             }
2423             SERVER_END_REQ;
2424         }
2425         return ret;
2426     }
2427
2428     if (!(list = WIN_ListParents( hwnd ))) return 0;
2429
2430     if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd );  /* top-level window */
2431     else
2432     {
2433         int count = 2;
2434         while (list[count]) count++;
2435         ret = list[count - 2];  /* get the one before the desktop */
2436     }
2437     HeapFree( GetProcessHeap(), 0, list );
2438
2439     if (ret && type == GA_ROOTOWNER)
2440     {
2441         for (;;)
2442         {
2443             HWND owner = GetWindow( ret, GW_OWNER );
2444             if (!owner) break;
2445             ret = owner;
2446         }
2447     }
2448     return ret;
2449 }
2450
2451
2452 /*****************************************************************
2453  *              SetParent (USER32.@)
2454  */
2455 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2456 {
2457     WND *wndPtr;
2458     HWND retvalue, full_handle;
2459     BOOL was_visible;
2460
2461     if (!parent) parent = GetDesktopWindow();
2462     else parent = WIN_GetFullHandle( parent );
2463
2464     if (!IsWindow( parent ))
2465     {
2466         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2467         return 0;
2468     }
2469
2470     if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2471         return SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2472
2473     hwnd = full_handle;
2474
2475     if (USER_Driver.pSetParent)
2476         return USER_Driver.pSetParent( hwnd, parent );
2477
2478     /* Windows hides the window first, then shows it again
2479      * including the WM_SHOWWINDOW messages and all */
2480     was_visible = ShowWindow( hwnd, SW_HIDE );
2481
2482     if (!IsWindow( parent )) return 0;
2483     if (!(wndPtr = WIN_GetPtr(hwnd)) || wndPtr == WND_OTHER_PROCESS) return 0;
2484
2485     retvalue = wndPtr->parent;  /* old parent */
2486     if (parent != retvalue)
2487     {
2488         WIN_LinkWindow( hwnd, parent, HWND_TOP );
2489
2490         if (parent != GetDesktopWindow()) /* a child window */
2491         {
2492             if (!(wndPtr->dwStyle & WS_CHILD))
2493             {
2494                 HMENU menu = (HMENU)SetWindowLongW( hwnd, GWL_ID, 0 );
2495                 if (menu) DestroyMenu( menu );
2496             }
2497         }
2498     }
2499     WIN_ReleasePtr( wndPtr );
2500
2501     /* SetParent additionally needs to make hwnd the topmost window
2502        in the x-order and send the expected WM_WINDOWPOSCHANGING and
2503        WM_WINDOWPOSCHANGED notification messages.
2504     */
2505     SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0,
2506                   SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | (was_visible ? SWP_SHOWWINDOW : 0) );
2507     /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
2508      * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
2509     return retvalue;
2510 }
2511
2512
2513 /*******************************************************************
2514  *              IsChild (USER32.@)
2515  */
2516 BOOL WINAPI IsChild( HWND parent, HWND child )
2517 {
2518     HWND *list = WIN_ListParents( child );
2519     int i;
2520     BOOL ret;
2521
2522     if (!list) return FALSE;
2523     parent = WIN_GetFullHandle( parent );
2524     for (i = 0; list[i]; i++) if (list[i] == parent) break;
2525     ret = (list[i] != 0);
2526     HeapFree( GetProcessHeap(), 0, list );
2527     return ret;
2528 }
2529
2530
2531 /***********************************************************************
2532  *              IsWindowVisible (USER32.@)
2533  */
2534 BOOL WINAPI IsWindowVisible( HWND hwnd )
2535 {
2536     HWND *list;
2537     BOOL retval;
2538     int i;
2539
2540     if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2541     if (!(list = WIN_ListParents( hwnd ))) return TRUE;
2542     for (i = 0; list[i]; i++)
2543         if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2544     retval = !list[i];
2545     HeapFree( GetProcessHeap(), 0, list );
2546     return retval;
2547 }
2548
2549
2550 /***********************************************************************
2551  *           WIN_IsWindowDrawable
2552  *
2553  * hwnd is drawable when it is visible, all parents are not
2554  * minimized, and it is itself not minimized unless we are
2555  * trying to draw its default class icon.
2556  */
2557 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2558 {
2559     HWND *list;
2560     BOOL retval;
2561     int i;
2562     LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2563
2564     if (!(style & WS_VISIBLE)) return FALSE;
2565     if ((style & WS_MINIMIZE) && icon && GetClassLongA( hwnd, GCL_HICON ))  return FALSE;
2566
2567     if (!(list = WIN_ListParents( hwnd ))) return TRUE;
2568     for (i = 0; list[i]; i++)
2569         if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2570             break;
2571     retval = !list[i];
2572     HeapFree( GetProcessHeap(), 0, list );
2573     return retval;
2574 }
2575
2576
2577 /*******************************************************************
2578  *              GetTopWindow (USER32.@)
2579  */
2580 HWND WINAPI GetTopWindow( HWND hwnd )
2581 {
2582     if (!hwnd) hwnd = GetDesktopWindow();
2583     return GetWindow( hwnd, GW_CHILD );
2584 }
2585
2586
2587 /*******************************************************************
2588  *              GetWindow (USER32.@)
2589  */
2590 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2591 {
2592     HWND retval = 0;
2593
2594     if (rel == GW_OWNER)  /* this one may be available locally */
2595     {
2596         WND *wndPtr = WIN_GetPtr( hwnd );
2597         if (!wndPtr)
2598         {
2599             SetLastError( ERROR_INVALID_HANDLE );
2600             return 0;
2601         }
2602         if (wndPtr != WND_OTHER_PROCESS)
2603         {
2604             retval = wndPtr->owner;
2605             WIN_ReleasePtr( wndPtr );
2606             return retval;
2607         }
2608         /* else fall through to server call */
2609     }
2610
2611     SERVER_START_REQ( get_window_tree )
2612     {
2613         req->handle = hwnd;
2614         if (!wine_server_call_err( req ))
2615         {
2616             switch(rel)
2617             {
2618             case GW_HWNDFIRST:
2619                 retval = reply->first_sibling;
2620                 break;
2621             case GW_HWNDLAST:
2622                 retval = reply->last_sibling;
2623                 break;
2624             case GW_HWNDNEXT:
2625                 retval = reply->next_sibling;
2626                 break;
2627             case GW_HWNDPREV:
2628                 retval = reply->prev_sibling;
2629                 break;
2630             case GW_OWNER:
2631                 retval = reply->owner;
2632                 break;
2633             case GW_CHILD:
2634                 retval = reply->first_child;
2635                 break;
2636             }
2637         }
2638     }
2639     SERVER_END_REQ;
2640     return retval;
2641 }
2642
2643
2644 /***********************************************************************
2645  *           WIN_InternalShowOwnedPopups
2646  *
2647  * Internal version of ShowOwnedPopups; Wine functions should use this
2648  * to avoid interfering with application calls to ShowOwnedPopups
2649  * and to make sure the application can't prevent showing/hiding.
2650  *
2651  * Set unmanagedOnly to TRUE to show/hide unmanaged windows only.
2652  *
2653  */
2654
2655 BOOL WIN_InternalShowOwnedPopups( HWND owner, BOOL fShow, BOOL unmanagedOnly )
2656 {
2657     int count = 0;
2658     WND *pWnd;
2659     HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2660
2661     if (!win_array) return TRUE;
2662
2663     /*
2664      * Show windows Lowest first, Highest last to preserve Z-Order
2665      */
2666     while (win_array[count]) count++;
2667     while (--count >= 0)
2668     {
2669         if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2670         if (!(pWnd = WIN_FindWndPtr( win_array[count] ))) continue;
2671
2672         if (pWnd->dwStyle & WS_POPUP)
2673         {
2674             if (fShow)
2675             {
2676                 /* check in window was flagged for showing in previous WIN_InternalShowOwnedPopups call */
2677                 if (pWnd->flags & WIN_NEEDS_INTERNALSOP)
2678                 {
2679                     /*
2680                      * Call ShowWindow directly because an application can intercept WM_SHOWWINDOW messages
2681                      */
2682                     ShowWindow(pWnd->hwndSelf,SW_SHOW);
2683                     pWnd->flags &= ~WIN_NEEDS_INTERNALSOP; /* remove the flag */
2684                 }
2685             }
2686             else
2687             {
2688                 if ( IsWindowVisible(pWnd->hwndSelf) &&                   /* hide only if window is visible */
2689                      !( pWnd->flags & WIN_NEEDS_INTERNALSOP ) &&          /* don't hide if previous call already did it */
2690                      !( unmanagedOnly && (pWnd->dwExStyle & WS_EX_MANAGED) ) ) /* don't hide managed windows if unmanagedOnly is TRUE */
2691                 {
2692                     /*
2693                      * Call ShowWindow directly because an application can intercept WM_SHOWWINDOW messages
2694                      */
2695                     ShowWindow(pWnd->hwndSelf,SW_HIDE);
2696                     /* flag the window for showing on next WIN_InternalShowOwnedPopups call */
2697                     pWnd->flags |= WIN_NEEDS_INTERNALSOP;
2698                 }
2699             }
2700         }
2701         WIN_ReleaseWndPtr( pWnd );
2702     }
2703     HeapFree( GetProcessHeap(), 0, win_array );
2704
2705     return TRUE;
2706 }
2707
2708 /*******************************************************************
2709  *              ShowOwnedPopups (USER32.@)
2710  */
2711 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2712 {
2713     int count = 0;
2714     WND *pWnd;
2715     HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2716
2717     if (!win_array) return TRUE;
2718
2719     while (win_array[count]) count++;
2720     while (--count >= 0)
2721     {
2722         if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2723         if (!(pWnd = WIN_FindWndPtr( win_array[count] ))) continue;
2724
2725         if (pWnd->dwStyle & WS_POPUP)
2726         {
2727             if (fShow)
2728             {
2729                 if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2730                 {
2731                     /* In Windows, ShowOwnedPopups(TRUE) generates
2732                      * WM_SHOWWINDOW messages with SW_PARENTOPENING,
2733                      * regardless of the state of the owner
2734                      */
2735                     SendMessageA(pWnd->hwndSelf, WM_SHOWWINDOW, SW_SHOW, SW_PARENTOPENING);
2736                     pWnd->flags &= ~WIN_NEEDS_SHOW_OWNEDPOPUP;
2737                 }
2738             }
2739             else
2740             {
2741                 if (IsWindowVisible(pWnd->hwndSelf))
2742                 {
2743                     /* In Windows, ShowOwnedPopups(FALSE) generates
2744                      * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
2745                      * regardless of the state of the owner
2746                      */
2747                     SendMessageA(pWnd->hwndSelf, WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
2748                     pWnd->flags |= WIN_NEEDS_SHOW_OWNEDPOPUP;
2749                 }
2750             }
2751         }
2752         WIN_ReleaseWndPtr( pWnd );
2753     }
2754     HeapFree( GetProcessHeap(), 0, win_array );
2755     return TRUE;
2756 }
2757
2758
2759 /*******************************************************************
2760  *              GetLastActivePopup (USER32.@)
2761  */
2762 HWND WINAPI GetLastActivePopup( HWND hwnd )
2763 {
2764     HWND retval;
2765     WND *wndPtr =WIN_FindWndPtr(hwnd);
2766     if (!wndPtr) return hwnd;
2767     retval = wndPtr->hwndLastActive;
2768     if (!IsWindow( retval )) retval = wndPtr->hwndSelf;
2769     WIN_ReleaseWndPtr(wndPtr);
2770     return retval;
2771 }
2772
2773
2774 /*******************************************************************
2775  *           WIN_ListParents
2776  *
2777  * Build an array of all parents of a given window, starting with
2778  * the immediate parent. The array must be freed with HeapFree.
2779  * Returns NULL if window is a top-level window.
2780  */
2781 HWND *WIN_ListParents( HWND hwnd )
2782 {
2783     WND *win;
2784     HWND current, *list;
2785     int pos = 0, size = 16, count = 0;
2786
2787     if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
2788
2789     current = hwnd;
2790     for (;;)
2791     {
2792         if (!(win = WIN_GetPtr( current ))) goto empty;
2793         if (win == WND_OTHER_PROCESS) break;  /* need to do it the hard way */
2794         list[pos] = win->parent;
2795         WIN_ReleasePtr( win );
2796         if (!(current = list[pos]))
2797         {
2798             if (!pos) goto empty;
2799             return list;
2800         }
2801         if (++pos == size - 1)
2802         {
2803             /* need to grow the list */
2804             HWND *new_list = HeapReAlloc( GetProcessHeap(), 0, list, (size+16) * sizeof(HWND) );
2805             if (!new_list) goto empty;
2806             list = new_list;
2807             size += 16;
2808         }
2809     }
2810
2811     /* at least one parent belongs to another process, have to query the server */
2812
2813     for (;;)
2814     {
2815         count = 0;
2816         SERVER_START_REQ( get_window_parents )
2817         {
2818             req->handle = hwnd;
2819             wine_server_set_reply( req, list, (size-1) * sizeof(HWND) );
2820             if (!wine_server_call( req )) count = reply->count;
2821         }
2822         SERVER_END_REQ;
2823         if (!count) goto empty;
2824         if (size > count)
2825         {
2826             list[count] = 0;
2827             return list;
2828         }
2829         HeapFree( GetProcessHeap(), 0, list );
2830         size = count + 1;
2831         if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
2832     }
2833
2834  empty:
2835     HeapFree( GetProcessHeap(), 0, list );
2836     return NULL;
2837 }
2838
2839
2840 /*******************************************************************
2841  *           WIN_ListChildren
2842  *
2843  * Build an array of the children of a given window. The array must be
2844  * freed with HeapFree. Returns NULL when no windows are found.
2845  */
2846 HWND *WIN_ListChildren( HWND hwnd )
2847 {
2848     return list_window_children( hwnd, 0, 0 );
2849 }
2850
2851
2852 /*******************************************************************
2853  *              EnumWindows (USER32.@)
2854  */
2855 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
2856 {
2857     HWND *list;
2858     BOOL ret = TRUE;
2859     int i, iWndsLocks;
2860
2861     /* We have to build a list of all windows first, to avoid */
2862     /* unpleasant side-effects, for instance if the callback */
2863     /* function changes the Z-order of the windows.          */
2864
2865     if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
2866
2867     /* Now call the callback function for every window */
2868
2869     iWndsLocks = WIN_SuspendWndsLock();
2870     for (i = 0; list[i]; i++)
2871     {
2872         /* Make sure that the window still exists */
2873         if (!IsWindow( list[i] )) continue;
2874         if (!(ret = lpEnumFunc( list[i], lParam ))) break;
2875     }
2876     WIN_RestoreWndsLock(iWndsLocks);
2877     HeapFree( GetProcessHeap(), 0, list );
2878     return ret;
2879 }
2880
2881
2882 /**********************************************************************
2883  *              EnumThreadWindows (USER32.@)
2884  */
2885 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
2886 {
2887     HWND *list;
2888     int i, iWndsLocks;
2889
2890     if (!(list = list_window_children( GetDesktopWindow(), 0, GetCurrentThreadId() )))
2891         return TRUE ;
2892
2893     /* Now call the callback function for every window */
2894
2895     iWndsLocks = WIN_SuspendWndsLock();
2896     for (i = 0; list[i]; i++)
2897         if (!func( list[i], lParam )) break;
2898     WIN_RestoreWndsLock(iWndsLocks);
2899     HeapFree( GetProcessHeap(), 0, list );
2900     return TRUE;
2901 }
2902
2903
2904 /**********************************************************************
2905  *           WIN_EnumChildWindows
2906  *
2907  * Helper function for EnumChildWindows().
2908  */
2909 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
2910 {
2911     HWND *childList;
2912     BOOL ret = FALSE;
2913
2914     for ( ; *list; list++)
2915     {
2916         /* Make sure that the window still exists */
2917         if (!IsWindow( *list )) continue;
2918         /* skip owned windows */
2919         if (GetWindow( *list, GW_OWNER )) continue;
2920         /* Build children list first */
2921         childList = WIN_ListChildren( *list );
2922
2923         ret = func( *list, lParam );
2924
2925         if (childList)
2926         {
2927             if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
2928             HeapFree( GetProcessHeap(), 0, childList );
2929         }
2930         if (!ret) return FALSE;
2931     }
2932     return TRUE;
2933 }
2934
2935
2936 /**********************************************************************
2937  *              EnumChildWindows (USER32.@)
2938  */
2939 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
2940 {
2941     HWND *list;
2942     int iWndsLocks;
2943
2944     if (!(list = WIN_ListChildren( parent ))) return FALSE;
2945     iWndsLocks = WIN_SuspendWndsLock();
2946     WIN_EnumChildWindows( list, func, lParam );
2947     WIN_RestoreWndsLock(iWndsLocks);
2948     HeapFree( GetProcessHeap(), 0, list );
2949     return TRUE;
2950 }
2951
2952
2953 /*******************************************************************
2954  *              AnyPopup (USER.52)
2955  */
2956 BOOL16 WINAPI AnyPopup16(void)
2957 {
2958     return AnyPopup();
2959 }
2960
2961
2962 /*******************************************************************
2963  *              AnyPopup (USER32.@)
2964  */
2965 BOOL WINAPI AnyPopup(void)
2966 {
2967     int i;
2968     BOOL retvalue;
2969     HWND *list = WIN_ListChildren( GetDesktopWindow() );
2970
2971     if (!list) return FALSE;
2972     for (i = 0; list[i]; i++)
2973     {
2974         if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
2975     }
2976     retvalue = (list[i] != 0);
2977     HeapFree( GetProcessHeap(), 0, list );
2978     return retvalue;
2979 }
2980
2981
2982 /*******************************************************************
2983  *              FlashWindow (USER32.@)
2984  */
2985 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
2986 {
2987     WND *wndPtr = WIN_FindWndPtr(hWnd);
2988
2989     TRACE("%04x\n", hWnd);
2990
2991     if (!wndPtr) return FALSE;
2992     hWnd = wndPtr->hwndSelf;  /* make it a full handle */
2993
2994     if (wndPtr->dwStyle & WS_MINIMIZE)
2995     {
2996         if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
2997         {
2998             HDC hDC = GetDC(hWnd);
2999
3000             if (!SendMessageW( hWnd, WM_ERASEBKGND, (WPARAM16)hDC, 0 ))
3001                 wndPtr->flags |= WIN_NEEDS_ERASEBKGND;
3002
3003             ReleaseDC( hWnd, hDC );
3004             wndPtr->flags |= WIN_NCACTIVATED;
3005         }
3006         else
3007         {
3008             RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
3009             wndPtr->flags &= ~WIN_NCACTIVATED;
3010         }
3011         WIN_ReleaseWndPtr(wndPtr);
3012         return TRUE;
3013     }
3014     else
3015     {
3016         WPARAM16 wparam;
3017         if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3018         else wparam = (hWnd == GetActiveWindow());
3019
3020         WIN_ReleaseWndPtr(wndPtr);
3021         SendMessageW( hWnd, WM_NCACTIVATE, wparam, (LPARAM)0 );
3022         return wparam;
3023     }
3024 }
3025
3026
3027 /*******************************************************************
3028  *              GetWindowContextHelpId (USER32.@)
3029  */
3030 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3031 {
3032     DWORD retval;
3033     WND *wnd = WIN_FindWndPtr( hwnd );
3034     if (!wnd) return 0;
3035     retval = wnd->helpContext;
3036     WIN_ReleaseWndPtr(wnd);
3037     return retval;
3038 }
3039
3040
3041 /*******************************************************************
3042  *              SetWindowContextHelpId (USER32.@)
3043  */
3044 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3045 {
3046     WND *wnd = WIN_FindWndPtr( hwnd );
3047     if (!wnd) return FALSE;
3048     wnd->helpContext = id;
3049     WIN_ReleaseWndPtr(wnd);
3050     return TRUE;
3051 }
3052
3053
3054 /*******************************************************************
3055  *                      DRAG_QueryUpdate
3056  *
3057  * recursively find a child that contains spDragInfo->pt point
3058  * and send WM_QUERYDROPOBJECT
3059  */
3060 BOOL16 DRAG_QueryUpdate( HWND hQueryWnd, SEGPTR spDragInfo, BOOL bNoSend )
3061 {
3062     BOOL16 wParam, bResult = 0;
3063     POINT pt;
3064     LPDRAGINFO16 ptrDragInfo = MapSL(spDragInfo);
3065     RECT tempRect;
3066
3067     if (!ptrDragInfo) return FALSE;
3068
3069     CONV_POINT16TO32( &ptrDragInfo->pt, &pt );
3070
3071     GetWindowRect(hQueryWnd,&tempRect);
3072
3073     if( !PtInRect(&tempRect,pt) || !IsWindowEnabled(hQueryWnd)) return FALSE;
3074
3075     if (!IsIconic( hQueryWnd ))
3076     {
3077         GetClientRect( hQueryWnd, &tempRect );
3078         MapWindowPoints( hQueryWnd, 0, (LPPOINT)&tempRect, 2 );
3079
3080         if (PtInRect( &tempRect, pt))
3081         {
3082             int i;
3083             HWND *list = WIN_ListChildren( hQueryWnd );
3084
3085             wParam = 0;
3086
3087             if (list)
3088             {
3089                 for (i = 0; list[i]; i++)
3090                 {
3091                     if (GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)
3092                     {
3093                         GetWindowRect( list[i], &tempRect );
3094                         if (PtInRect( &tempRect, pt )) break;
3095                     }
3096                 }
3097                 if (list[i])
3098                 {
3099                     if (IsWindowEnabled( list[i] ))
3100                         bResult = DRAG_QueryUpdate( list[i], spDragInfo, bNoSend );
3101                 }
3102                 HeapFree( GetProcessHeap(), 0, list );
3103             }
3104             if(bResult) return bResult;
3105         }
3106         else wParam = 1;
3107     }
3108     else wParam = 1;
3109
3110     ScreenToClient16(hQueryWnd,&ptrDragInfo->pt);
3111
3112     ptrDragInfo->hScope = hQueryWnd;
3113
3114     if (bNoSend) bResult = (GetWindowLongA( hQueryWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES) != 0;
3115     else bResult = SendMessage16( hQueryWnd, WM_QUERYDROPOBJECT, (WPARAM16)wParam, spDragInfo );
3116
3117     if( !bResult ) CONV_POINT32TO16( &pt, &ptrDragInfo->pt );
3118
3119     return bResult;
3120 }
3121
3122
3123 /*******************************************************************
3124  *              DragDetect (USER32.@)
3125  */
3126 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3127 {
3128     MSG msg;
3129     RECT rect;
3130
3131     rect.left = pt.x - wDragWidth;
3132     rect.right = pt.x + wDragWidth;
3133
3134     rect.top = pt.y - wDragHeight;
3135     rect.bottom = pt.y + wDragHeight;
3136
3137     SetCapture(hWnd);
3138
3139     while(1)
3140     {
3141         while(PeekMessageA(&msg ,0 ,WM_MOUSEFIRST ,WM_MOUSELAST ,PM_REMOVE))
3142         {
3143             if( msg.message == WM_LBUTTONUP )
3144             {
3145                 ReleaseCapture();
3146                 return 0;
3147             }
3148             if( msg.message == WM_MOUSEMOVE )
3149             {
3150                 POINT tmp;
3151                 tmp.x = LOWORD(msg.lParam);
3152                 tmp.y = HIWORD(msg.lParam);
3153                 if( !PtInRect( &rect, tmp ))
3154                 {
3155                     ReleaseCapture();
3156                     return 1;
3157                 }
3158             }
3159         }
3160         WaitMessage();
3161     }
3162     return 0;
3163 }
3164
3165 /******************************************************************************
3166  *              DragObject (USER.464)
3167  */
3168 DWORD WINAPI DragObject16( HWND16 hwndScope, HWND16 hWnd, UINT16 wObj,
3169                            HANDLE16 hOfStruct, WORD szList, HCURSOR16 hCursor )
3170 {
3171     MSG msg;
3172     LPDRAGINFO16 lpDragInfo;
3173     SEGPTR      spDragInfo;
3174     HCURSOR16   hDragCursor=0, hOldCursor=0, hBummer=0;
3175     HGLOBAL16   hDragInfo  = GlobalAlloc16( GMEM_SHARE | GMEM_ZEROINIT, 2*sizeof(DRAGINFO16));
3176     HCURSOR16   hCurrentCursor = 0;
3177     HWND16      hCurrentWnd = 0;
3178
3179     lpDragInfo = (LPDRAGINFO16) GlobalLock16(hDragInfo);
3180     spDragInfo = K32WOWGlobalLock16(hDragInfo);
3181
3182     if( !lpDragInfo || !spDragInfo ) return 0L;
3183
3184     if (!(hBummer = LoadCursorA(0, MAKEINTRESOURCEA(OCR_NO))))
3185     {
3186         GlobalFree16(hDragInfo);
3187         return 0L;
3188     }
3189
3190     if(hCursor)
3191     {
3192         if( !(hDragCursor = CURSORICON_IconToCursor(hCursor, FALSE)) )
3193         {
3194             GlobalFree16(hDragInfo);
3195             return 0L;
3196         }
3197
3198         if( hDragCursor == hCursor ) hDragCursor = 0;
3199         else hCursor = hDragCursor;
3200
3201         hOldCursor = SetCursor(hDragCursor);
3202     }
3203
3204     lpDragInfo->hWnd   = hWnd;
3205     lpDragInfo->hScope = 0;
3206     lpDragInfo->wFlags = wObj;
3207     lpDragInfo->hList  = szList; /* near pointer! */
3208     lpDragInfo->hOfStruct = hOfStruct;
3209     lpDragInfo->l = 0L;
3210
3211     SetCapture(hWnd);
3212     ShowCursor( TRUE );
3213
3214     do
3215     {
3216         GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST );
3217
3218        *(lpDragInfo+1) = *lpDragInfo;
3219
3220         lpDragInfo->pt.x = msg.pt.x;
3221         lpDragInfo->pt.y = msg.pt.y;
3222
3223         /* update DRAGINFO struct */
3224         TRACE_(msg)("lpDI->hScope = %04x\n",lpDragInfo->hScope);
3225
3226         if( DRAG_QueryUpdate(hwndScope, spDragInfo, FALSE) > 0 )
3227             hCurrentCursor = hCursor;
3228         else
3229         {
3230             hCurrentCursor = hBummer;
3231             lpDragInfo->hScope = 0;
3232         }
3233         if( hCurrentCursor )
3234             SetCursor(hCurrentCursor);
3235
3236         /* send WM_DRAGLOOP */
3237         SendMessage16( hWnd, WM_DRAGLOOP, (WPARAM16)(hCurrentCursor != hBummer),
3238                                           (LPARAM) spDragInfo );
3239         /* send WM_DRAGSELECT or WM_DRAGMOVE */
3240         if( hCurrentWnd != lpDragInfo->hScope )
3241         {
3242             if( hCurrentWnd )
3243                 SendMessage16( hCurrentWnd, WM_DRAGSELECT, 0,
3244                        (LPARAM)MAKELONG(LOWORD(spDragInfo)+sizeof(DRAGINFO16),
3245                                         HIWORD(spDragInfo)) );
3246             hCurrentWnd = lpDragInfo->hScope;
3247             if( hCurrentWnd )
3248                 SendMessage16( hCurrentWnd, WM_DRAGSELECT, 1, (LPARAM)spDragInfo);
3249         }
3250         else
3251             if( hCurrentWnd )
3252                 SendMessage16( hCurrentWnd, WM_DRAGMOVE, 0, (LPARAM)spDragInfo);
3253
3254     } while( msg.message != WM_LBUTTONUP && msg.message != WM_NCLBUTTONUP );
3255
3256     ReleaseCapture();
3257     ShowCursor( FALSE );
3258
3259     if( hCursor )
3260     {
3261         SetCursor( hOldCursor );
3262         if (hDragCursor) DestroyCursor( hDragCursor );
3263     }
3264
3265     if( hCurrentCursor != hBummer )
3266         msg.lParam = SendMessage16( lpDragInfo->hScope, WM_DROPOBJECT,
3267                                    (WPARAM16)hWnd, (LPARAM)spDragInfo );
3268     else
3269         msg.lParam = 0;
3270     GlobalFree16(hDragInfo);
3271
3272     return (DWORD)(msg.lParam);
3273 }
3274
3275
3276 /******************************************************************************
3277  *              GetWindowModuleFileNameA (USER32.@)
3278  */
3279 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR lpszFileName, UINT cchFileNameMax)
3280 {
3281     FIXME("GetWindowModuleFileNameA(hwnd 0x%x, lpszFileName %p, cchFileNameMax %u) stub!\n",
3282           hwnd, lpszFileName, cchFileNameMax);
3283     return 0;
3284 }
3285
3286 /******************************************************************************
3287  *              GetWindowModuleFileNameW (USER32.@)
3288  */
3289 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPSTR lpszFileName, UINT cchFileNameMax)
3290 {
3291     FIXME("GetWindowModuleFileNameW(hwnd 0x%x, lpszFileName %p, cchFileNameMax %u) stub!\n",
3292           hwnd, lpszFileName, cchFileNameMax);
3293     return 0;
3294 }