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