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