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