Only allocate even-numbered window handles, MS Project depends on that
[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 focus_wnd, capture_wnd;
1756
1757         SendMessageA( hwnd, WM_CANCELMODE, 0, 0);
1758
1759         WIN_SetStyle( hwnd, style | WS_DISABLED );
1760
1761         focus_wnd = GetFocus();
1762         if (hwnd == focus_wnd || IsChild(hwnd, focus_wnd))
1763             SetFocus( 0 );  /* A disabled window can't have the focus */
1764
1765         capture_wnd = GetCapture();
1766         if (hwnd == capture_wnd || IsChild(hwnd, capture_wnd))
1767             ReleaseCapture();  /* A disabled window can't capture the mouse */
1768
1769         SendMessageA( hwnd, WM_ENABLE, FALSE, 0 );
1770     }
1771     return retvalue;
1772 }
1773
1774
1775 /***********************************************************************
1776  *              IsWindowEnabled (USER32.@)
1777  */
1778 BOOL WINAPI IsWindowEnabled(HWND hWnd)
1779 {
1780     return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
1781 }
1782
1783
1784 /***********************************************************************
1785  *              IsWindowUnicode (USER32.@)
1786  */
1787 BOOL WINAPI IsWindowUnicode( HWND hwnd )
1788 {
1789     WND * wndPtr;
1790     BOOL retvalue;
1791
1792     if (!(wndPtr = WIN_FindWndPtr(hwnd))) return FALSE;
1793     retvalue = (WINPROC_GetProcType( wndPtr->winproc ) == WIN_PROC_32W);
1794     WIN_ReleaseWndPtr(wndPtr);
1795     return retvalue;
1796 }
1797
1798
1799 /**********************************************************************
1800  *              GetWindowWord (USER32.@)
1801  */
1802 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
1803 {
1804     if (offset >= 0)
1805     {
1806         WORD retvalue = 0;
1807         WND *wndPtr = WIN_GetPtr( hwnd );
1808         if (!wndPtr)
1809         {
1810             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1811             return 0;
1812         }
1813         if (wndPtr == WND_OTHER_PROCESS)
1814         {
1815             SERVER_START_REQ( set_window_info )
1816             {
1817                 req->handle = hwnd;
1818                 req->flags  = 0;  /* don't set anything, just retrieve */
1819                 req->extra_offset = offset;
1820                 req->extra_size = sizeof(retvalue);
1821                 if (!wine_server_call_err( req ))
1822                     memcpy( &retvalue, &reply->old_extra_value, sizeof(retvalue) );
1823             }
1824             SERVER_END_REQ;
1825             return retvalue;
1826         }
1827         if (offset > (int)(wndPtr->cbWndExtra - sizeof(WORD)))
1828         {
1829             WARN("Invalid offset %d\n", offset );
1830             SetLastError( ERROR_INVALID_INDEX );
1831         }
1832         else memcpy( &retvalue,  (char *)wndPtr->wExtra + offset, sizeof(retvalue) );
1833         WIN_ReleasePtr( wndPtr );
1834         return retvalue;
1835     }
1836
1837     switch(offset)
1838     {
1839     case GWL_HWNDPARENT:
1840         return GetWindowLongW( hwnd, offset );
1841     case GWL_ID:
1842     case GWL_HINSTANCE:
1843         {
1844             LONG ret = GetWindowLongW( hwnd, offset );
1845             if (HIWORD(ret))
1846                 WARN("%d: discards high bits of 0x%08lx!\n", offset, ret );
1847             return LOWORD(ret);
1848         }
1849     default:
1850         WARN("Invalid offset %d\n", offset );
1851         return 0;
1852     }
1853 }
1854
1855
1856 /**********************************************************************
1857  *              SetWindowWord (USER32.@)
1858  */
1859 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
1860 {
1861     WORD retval = 0;
1862     WND * wndPtr;
1863
1864     switch(offset)
1865     {
1866     case GWL_ID:
1867     case GWL_HINSTANCE:
1868     case GWL_HWNDPARENT:
1869         return SetWindowLongW( hwnd, offset, (UINT)newval );
1870     default:
1871         if (offset < 0)
1872         {
1873             WARN("Invalid offset %d\n", offset );
1874             SetLastError( ERROR_INVALID_INDEX );
1875             return 0;
1876         }
1877     }
1878
1879     wndPtr = WIN_GetPtr( hwnd );
1880     if (wndPtr == WND_OTHER_PROCESS)
1881     {
1882         if (IsWindow(hwnd))
1883             FIXME( "set %d <- %x not supported yet on other process window %p\n",
1884                    offset, newval, hwnd );
1885         wndPtr = NULL;
1886     }
1887     if (!wndPtr)
1888     {
1889        SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1890        return 0;
1891     }
1892
1893     if (offset > (int)(wndPtr->cbWndExtra - sizeof(WORD)))
1894     {
1895         WARN("Invalid offset %d\n", offset );
1896         WIN_ReleasePtr(wndPtr);
1897         SetLastError( ERROR_INVALID_INDEX );
1898         return 0;
1899     }
1900
1901     SERVER_START_REQ( set_window_info )
1902     {
1903         req->handle = hwnd;
1904         req->flags = SET_WIN_EXTRA;
1905         req->extra_offset = offset;
1906         req->extra_size = sizeof(newval);
1907         memcpy( &req->extra_value, &newval, sizeof(newval) );
1908         if (!wine_server_call_err( req ))
1909         {
1910             void *ptr = (char *)wndPtr->wExtra + offset;
1911             memcpy( &retval, ptr, sizeof(retval) );
1912             memcpy( ptr, &newval, sizeof(newval) );
1913         }
1914     }
1915     SERVER_END_REQ;
1916     WIN_ReleasePtr( wndPtr );
1917     return retval;
1918 }
1919
1920
1921 /**********************************************************************
1922  *           WIN_GetWindowLong
1923  *
1924  * Helper function for GetWindowLong().
1925  */
1926 static LONG WIN_GetWindowLong( HWND hwnd, INT offset, WINDOWPROCTYPE type )
1927 {
1928     LONG retvalue = 0;
1929     WND *wndPtr;
1930
1931     if (offset == GWL_HWNDPARENT)
1932     {
1933         HWND parent = GetAncestor( hwnd, GA_PARENT );
1934         if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
1935         return (LONG)parent;
1936     }
1937
1938     if (!(wndPtr = WIN_GetPtr( hwnd )))
1939     {
1940         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1941         return 0;
1942     }
1943
1944     if (wndPtr == WND_OTHER_PROCESS)
1945     {
1946         if (offset == GWL_WNDPROC)
1947         {
1948             SetLastError( ERROR_ACCESS_DENIED );
1949             return 0;
1950         }
1951         SERVER_START_REQ( set_window_info )
1952         {
1953             req->handle = hwnd;
1954             req->flags  = 0;  /* don't set anything, just retrieve */
1955             req->extra_offset = (offset >= 0) ? offset : -1;
1956             req->extra_size = (offset >= 0) ? sizeof(retvalue) : 0;
1957             if (!wine_server_call_err( req ))
1958             {
1959                 switch(offset)
1960                 {
1961                 case GWL_STYLE:     retvalue = reply->old_style; break;
1962                 case GWL_EXSTYLE:   retvalue = reply->old_ex_style; break;
1963                 case GWL_ID:        retvalue = reply->old_id; break;
1964                 case GWL_HINSTANCE: retvalue = (ULONG_PTR)reply->old_instance; break;
1965                 case GWL_USERDATA:  retvalue = (ULONG_PTR)reply->old_user_data; break;
1966                 default:
1967                     if (offset >= 0) retvalue = reply->old_extra_value;
1968                     else SetLastError( ERROR_INVALID_INDEX );
1969                     break;
1970                 }
1971             }
1972         }
1973         SERVER_END_REQ;
1974         return retvalue;
1975     }
1976
1977     /* now we have a valid wndPtr */
1978
1979     if (offset >= 0)
1980     {
1981         if (offset > (int)(wndPtr->cbWndExtra - sizeof(LONG)))
1982         {
1983           /*
1984             * Some programs try to access last element from 16 bit
1985             * code using illegal offset value. Hopefully this is
1986             * what those programs really expect.
1987             */
1988            if (type == WIN_PROC_16 &&
1989                wndPtr->cbWndExtra >= 4 &&
1990                offset == wndPtr->cbWndExtra - sizeof(WORD))
1991            {
1992                INT offset2 = wndPtr->cbWndExtra - sizeof(LONG);
1993
1994                ERR( "- replaced invalid offset %d with %d\n",
1995                     offset, offset2 );
1996
1997                 retvalue = *(LONG *)(((char *)wndPtr->wExtra) + offset2);
1998                 WIN_ReleasePtr( wndPtr );
1999                 return retvalue;
2000             }
2001             WARN("Invalid offset %d\n", offset );
2002             WIN_ReleasePtr( wndPtr );
2003             SetLastError( ERROR_INVALID_INDEX );
2004             return 0;
2005         }
2006         retvalue = *(LONG *)(((char *)wndPtr->wExtra) + offset);
2007         /* Special case for dialog window procedure */
2008         if ((offset == DWL_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
2009             retvalue = (LONG)WINPROC_GetProc( (WNDPROC)retvalue, type );
2010         WIN_ReleasePtr( wndPtr );
2011         return retvalue;
2012     }
2013
2014     switch(offset)
2015     {
2016     case GWL_USERDATA:   retvalue = wndPtr->userdata; break;
2017     case GWL_STYLE:      retvalue = wndPtr->dwStyle; break;
2018     case GWL_EXSTYLE:    retvalue = wndPtr->dwExStyle; break;
2019     case GWL_ID:         retvalue = (LONG)wndPtr->wIDmenu; break;
2020     case GWL_WNDPROC:    retvalue = (LONG)WINPROC_GetProc( wndPtr->winproc, type ); break;
2021     case GWL_HINSTANCE:  retvalue = (LONG)wndPtr->hInstance; break;
2022     default:
2023         WARN("Unknown offset %d\n", offset );
2024         SetLastError( ERROR_INVALID_INDEX );
2025         break;
2026     }
2027     WIN_ReleasePtr(wndPtr);
2028     return retvalue;
2029 }
2030
2031
2032 /**********************************************************************
2033  *           WIN_SetWindowLong
2034  *
2035  * Helper function for SetWindowLong().
2036  *
2037  * 0 is the failure code. However, in the case of failure SetLastError
2038  * must be set to distinguish between a 0 return value and a failure.
2039  */
2040 static LONG WIN_SetWindowLong( HWND hwnd, INT offset, LONG newval,
2041                                WINDOWPROCTYPE type )
2042 {
2043     STYLESTRUCT style;
2044     BOOL ok;
2045     LONG retval = 0;
2046     WND *wndPtr;
2047
2048     TRACE( "%p %d %lx %x\n", hwnd, offset, newval, type );
2049
2050     if (is_broadcast(hwnd))
2051     {
2052         SetLastError( ERROR_INVALID_PARAMETER );
2053         return FALSE;
2054     }
2055     if (!WIN_IsCurrentProcess( hwnd ))
2056     {
2057         if (offset == GWL_WNDPROC)
2058         {
2059             SetLastError( ERROR_ACCESS_DENIED );
2060             return 0;
2061         }
2062         return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, offset, newval );
2063     }
2064
2065     wndPtr = WIN_GetPtr( hwnd );
2066     if (wndPtr->hwndSelf == GetDesktopWindow())
2067     {
2068         /* can't change anything on the desktop window */
2069         WIN_ReleasePtr( wndPtr );
2070         SetLastError( ERROR_ACCESS_DENIED );
2071         return 0;
2072     }
2073
2074     /* first some special cases */
2075     switch( offset )
2076     {
2077     case GWL_STYLE:
2078     case GWL_EXSTYLE:
2079         style.styleOld =
2080             offset == GWL_STYLE ? wndPtr->dwStyle : wndPtr->dwExStyle;
2081         style.styleNew = newval;
2082         WIN_ReleasePtr( wndPtr );
2083         SendMessageW( hwnd, WM_STYLECHANGING, offset, (LPARAM)&style );
2084         if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2085         newval = style.styleNew;
2086         break;
2087     case GWL_HWNDPARENT:
2088         if (wndPtr->parent == GetDesktopWindow())
2089         {
2090             WIN_ReleasePtr( wndPtr );
2091             return (LONG)WIN_SetOwner( hwnd, (HWND)newval );
2092         }
2093         else
2094         {
2095             WIN_ReleasePtr( wndPtr );
2096             return (LONG)SetParent( hwnd, (HWND)newval );
2097         }
2098     case GWL_WNDPROC:
2099         retval = (LONG)WINPROC_GetProc( wndPtr->winproc, type );
2100         WINPROC_SetProc( &wndPtr->winproc, (WNDPROC)newval, type, WIN_PROC_WINDOW );
2101         WIN_ReleasePtr( wndPtr );
2102         return retval;
2103     case GWL_ID:
2104     case GWL_HINSTANCE:
2105     case GWL_USERDATA:
2106         break;
2107     case DWL_DLGPROC:
2108         if ((wndPtr->cbWndExtra + sizeof(LONG) >= DWL_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
2109         {
2110             WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWL_DLGPROC);
2111             retval = (LONG)WINPROC_GetProc( *ptr, type );
2112             WINPROC_SetProc( ptr, (WNDPROC)newval, type, WIN_PROC_WINDOW );
2113             WIN_ReleasePtr( wndPtr );
2114             return retval;
2115         }
2116         /* fall through */
2117     default:
2118         if (offset < 0 || offset > (int)(wndPtr->cbWndExtra - sizeof(LONG)))
2119         {
2120             WARN("Invalid offset %d\n", offset );
2121             WIN_ReleasePtr( wndPtr );
2122             SetLastError( ERROR_INVALID_INDEX );
2123             return 0;
2124         }
2125         else
2126         {
2127             LONG *ptr = (LONG *)((char *)wndPtr->wExtra + offset);
2128             if (*ptr == newval)  /* already set to the same value */
2129             {
2130                 WIN_ReleasePtr( wndPtr );
2131                 return newval;
2132             }
2133         }
2134         break;
2135     }
2136
2137     SERVER_START_REQ( set_window_info )
2138     {
2139         req->handle = hwnd;
2140         req->extra_offset = -1;
2141         switch(offset)
2142         {
2143         case GWL_STYLE:
2144             req->flags = SET_WIN_STYLE;
2145             req->style = newval;
2146             break;
2147         case GWL_EXSTYLE:
2148             req->flags = SET_WIN_EXSTYLE;
2149             req->ex_style = newval;
2150             break;
2151         case GWL_ID:
2152             req->flags = SET_WIN_ID;
2153             req->id = newval;
2154             break;
2155         case GWL_HINSTANCE:
2156             req->flags = SET_WIN_INSTANCE;
2157             req->instance = (void *)newval;
2158             break;
2159         case GWL_USERDATA:
2160             req->flags = SET_WIN_USERDATA;
2161             req->user_data = (void *)newval;
2162             break;
2163         default:
2164             req->flags = SET_WIN_EXTRA;
2165             req->extra_offset = offset;
2166             req->extra_size = sizeof(newval);
2167             memcpy( &req->extra_value, &newval, sizeof(newval) );
2168         }
2169         if ((ok = !wine_server_call_err( req )))
2170         {
2171             switch(offset)
2172             {
2173             case GWL_STYLE:
2174                 wndPtr->dwStyle = newval;
2175                 retval = reply->old_style;
2176                 break;
2177             case GWL_EXSTYLE:
2178                 wndPtr->dwExStyle = newval;
2179                 retval = reply->old_ex_style;
2180                 break;
2181             case GWL_ID:
2182                 wndPtr->wIDmenu = newval;
2183                 retval = reply->old_id;
2184                 break;
2185             case GWL_HINSTANCE:
2186                 wndPtr->hInstance = (HINSTANCE)newval;
2187                 retval = (ULONG_PTR)reply->old_instance;
2188                 break;
2189             case GWL_USERDATA:
2190                 wndPtr->userdata = newval;
2191                 retval = (ULONG_PTR)reply->old_user_data;
2192                 break;
2193             default:
2194                 {
2195                     void *ptr = (char *)wndPtr->wExtra + offset;
2196                     memcpy( &retval, ptr, sizeof(retval) );
2197                     memcpy( ptr, &newval, sizeof(newval) );
2198                 }
2199                 break;
2200             }
2201         }
2202     }
2203     SERVER_END_REQ;
2204     WIN_ReleasePtr( wndPtr );
2205
2206     if (!ok) return 0;
2207
2208     if (offset == GWL_STYLE && USER_Driver.pSetWindowStyle)
2209         USER_Driver.pSetWindowStyle( hwnd, retval );
2210
2211     if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2212         SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2213
2214     return retval;
2215 }
2216
2217
2218 /**********************************************************************
2219  *              GetWindowLong (USER.135)
2220  */
2221 LONG WINAPI GetWindowLong16( HWND16 hwnd, INT16 offset )
2222 {
2223     return WIN_GetWindowLong( WIN_Handle32(hwnd), offset, WIN_PROC_16 );
2224 }
2225
2226
2227 /**********************************************************************
2228  *              GetWindowLongA (USER32.@)
2229  */
2230 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2231 {
2232     return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32A );
2233 }
2234
2235
2236 /**********************************************************************
2237  *              GetWindowLongW (USER32.@)
2238  */
2239 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2240 {
2241     return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32W );
2242 }
2243
2244
2245 /**********************************************************************
2246  *              SetWindowLong (USER.136)
2247  */
2248 LONG WINAPI SetWindowLong16( HWND16 hwnd, INT16 offset, LONG newval )
2249 {
2250     return WIN_SetWindowLong( WIN_Handle32(hwnd), offset, newval, WIN_PROC_16 );
2251 }
2252
2253
2254 /**********************************************************************
2255  *              SetWindowLongA (USER32.@)
2256  */
2257 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2258 {
2259     return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32A );
2260 }
2261
2262
2263 /**********************************************************************
2264  *              SetWindowLongW (USER32.@) Set window attribute
2265  *
2266  * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2267  * value in a window's extra memory.
2268  *
2269  * The _hwnd_ parameter specifies the window.  is the handle to a
2270  * window that has extra memory. The _newval_ parameter contains the
2271  * new attribute or extra memory value.  If positive, the _offset_
2272  * parameter is the byte-addressed location in the window's extra
2273  * memory to set.  If negative, _offset_ specifies the window
2274  * attribute to set, and should be one of the following values:
2275  *
2276  * GWL_EXSTYLE      The window's extended window style
2277  *
2278  * GWL_STYLE        The window's window style.
2279  *
2280  * GWL_WNDPROC      Pointer to the window's window procedure.
2281  *
2282  * GWL_HINSTANCE    The window's pplication instance handle.
2283  *
2284  * GWL_ID           The window's identifier.
2285  *
2286  * GWL_USERDATA     The window's user-specified data.
2287  *
2288  * If the window is a dialog box, the _offset_ parameter can be one of
2289  * the following values:
2290  *
2291  * DWL_DLGPROC      The address of the window's dialog box procedure.
2292  *
2293  * DWL_MSGRESULT    The return value of a message
2294  *                  that the dialog box procedure processed.
2295  *
2296  * DWL_USER         Application specific information.
2297  *
2298  * RETURNS
2299  *
2300  * If successful, returns the previous value located at _offset_. Otherwise,
2301  * returns 0.
2302  *
2303  * NOTES
2304  *
2305  * Extra memory for a window class is specified by a nonzero cbWndExtra
2306  * parameter of the WNDCLASS structure passed to RegisterClass() at the
2307  * time of class creation.
2308  *
2309  * Using GWL_WNDPROC to set a new window procedure effectively creates
2310  * a window subclass. Use CallWindowProc() in the new windows procedure
2311  * to pass messages to the superclass's window procedure.
2312  *
2313  * The user data is reserved for use by the application which created
2314  * the window.
2315  *
2316  * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2317  * instead, call the EnableWindow() function to change the window's
2318  * disabled state.
2319  *
2320  * Do not use GWL_HWNDPARENT to reset the window's parent, use
2321  * SetParent() instead.
2322  *
2323  * Win95:
2324  * When offset is GWL_STYLE and the calling app's ver is 4.0,
2325  * it sends WM_STYLECHANGING before changing the settings
2326  * and WM_STYLECHANGED afterwards.
2327  * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2328  */
2329 LONG WINAPI SetWindowLongW(
2330     HWND hwnd,  /* [in] window to alter */
2331     INT offset, /* [in] offset, in bytes, of location to alter */
2332     LONG newval /* [in] new value of location */
2333 ) {
2334     return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32W );
2335 }
2336
2337
2338 /*******************************************************************
2339  *              GetWindowTextA (USER32.@)
2340  */
2341 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2342 {
2343     WCHAR *buffer;
2344
2345     if (WIN_IsCurrentProcess( hwnd ))
2346         return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2347
2348     /* when window belongs to other process, don't send a message */
2349     if (nMaxCount <= 0) return 0;
2350     if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2351     get_server_window_text( hwnd, buffer, nMaxCount );
2352     if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2353         lpString[nMaxCount-1] = 0;
2354     HeapFree( GetProcessHeap(), 0, buffer );
2355     return strlen(lpString);
2356 }
2357
2358
2359 /*******************************************************************
2360  *              InternalGetWindowText (USER32.@)
2361  */
2362 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2363 {
2364     WND *win;
2365
2366     if (nMaxCount <= 0) return 0;
2367     if (!(win = WIN_GetPtr( hwnd ))) return 0;
2368     if (win != WND_OTHER_PROCESS)
2369     {
2370         if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2371         else lpString[0] = 0;
2372         WIN_ReleasePtr( win );
2373     }
2374     else
2375     {
2376         get_server_window_text( hwnd, lpString, nMaxCount );
2377     }
2378     return strlenW(lpString);
2379 }
2380
2381
2382 /*******************************************************************
2383  *              GetWindowTextW (USER32.@)
2384  */
2385 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2386 {
2387     if (WIN_IsCurrentProcess( hwnd ))
2388         return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2389
2390     /* when window belongs to other process, don't send a message */
2391     if (nMaxCount <= 0) return 0;
2392     get_server_window_text( hwnd, lpString, nMaxCount );
2393     return strlenW(lpString);
2394 }
2395
2396
2397 /*******************************************************************
2398  *              SetWindowText  (USER32.@)
2399  *              SetWindowTextA (USER32.@)
2400  */
2401 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2402 {
2403     if (is_broadcast(hwnd))
2404     {
2405         SetLastError( ERROR_INVALID_PARAMETER );
2406         return FALSE;
2407     }
2408     if (!WIN_IsCurrentProcess( hwnd ))
2409     {
2410         FIXME( "cannot set text %s of other process window %p\n", debugstr_a(lpString), hwnd );
2411         SetLastError( ERROR_ACCESS_DENIED );
2412         return FALSE;
2413     }
2414     return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2415 }
2416
2417
2418 /*******************************************************************
2419  *              SetWindowTextW (USER32.@)
2420  */
2421 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2422 {
2423     if (is_broadcast(hwnd))
2424     {
2425         SetLastError( ERROR_INVALID_PARAMETER );
2426         return FALSE;
2427     }
2428     if (!WIN_IsCurrentProcess( hwnd ))
2429     {
2430         FIXME( "cannot set text %s of other process window %p\n", debugstr_w(lpString), hwnd );
2431         SetLastError( ERROR_ACCESS_DENIED );
2432         return FALSE;
2433     }
2434     return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2435 }
2436
2437
2438 /*******************************************************************
2439  *              GetWindowTextLengthA (USER32.@)
2440  */
2441 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2442 {
2443     return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2444 }
2445
2446 /*******************************************************************
2447  *              GetWindowTextLengthW (USER32.@)
2448  */
2449 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2450 {
2451     return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2452 }
2453
2454
2455 /*******************************************************************
2456  *              IsWindow (USER32.@)
2457  */
2458 BOOL WINAPI IsWindow( HWND hwnd )
2459 {
2460     WND *ptr;
2461     BOOL ret;
2462
2463     if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2464
2465     if (ptr != WND_OTHER_PROCESS)
2466     {
2467         WIN_ReleasePtr( ptr );
2468         return TRUE;
2469     }
2470
2471     /* check other processes */
2472     SERVER_START_REQ( get_window_info )
2473     {
2474         req->handle = hwnd;
2475         ret = !wine_server_call_err( req );
2476     }
2477     SERVER_END_REQ;
2478     return ret;
2479 }
2480
2481
2482 /***********************************************************************
2483  *              GetWindowThreadProcessId (USER32.@)
2484  */
2485 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2486 {
2487     WND *ptr;
2488     DWORD tid = 0;
2489
2490     if (!(ptr = WIN_GetPtr( hwnd )))
2491     {
2492         SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2493         return 0;
2494     }
2495
2496     if (ptr != WND_OTHER_PROCESS)
2497     {
2498         /* got a valid window */
2499         tid = ptr->tid;
2500         if (process) *process = GetCurrentProcessId();
2501         WIN_ReleasePtr( ptr );
2502         return tid;
2503     }
2504
2505     /* check other processes */
2506     SERVER_START_REQ( get_window_info )
2507     {
2508         req->handle = hwnd;
2509         if (!wine_server_call_err( req ))
2510         {
2511             tid = (DWORD)reply->tid;
2512             if (process) *process = (DWORD)reply->pid;
2513         }
2514     }
2515     SERVER_END_REQ;
2516     return tid;
2517 }
2518
2519
2520 /*****************************************************************
2521  *              GetParent (USER32.@)
2522  */
2523 HWND WINAPI GetParent( HWND hwnd )
2524 {
2525     WND *wndPtr;
2526     HWND retvalue = 0;
2527
2528     if (!(wndPtr = WIN_GetPtr( hwnd )))
2529     {
2530         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2531         return 0;
2532     }
2533     if (wndPtr == WND_OTHER_PROCESS)
2534     {
2535         LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2536         if (style & (WS_POPUP | WS_CHILD))
2537         {
2538             SERVER_START_REQ( get_window_tree )
2539             {
2540                 req->handle = hwnd;
2541                 if (!wine_server_call_err( req ))
2542                 {
2543                     if (style & WS_POPUP) retvalue = reply->owner;
2544                     else if (style & WS_CHILD) retvalue = reply->parent;
2545                 }
2546             }
2547             SERVER_END_REQ;
2548         }
2549     }
2550     else
2551     {
2552         if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2553         else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2554         WIN_ReleasePtr( wndPtr );
2555     }
2556     return retvalue;
2557 }
2558
2559
2560 /*****************************************************************
2561  *              GetAncestor (USER32.@)
2562  */
2563 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2564 {
2565     WND *win;
2566     HWND *list, ret = 0;
2567
2568     switch(type)
2569     {
2570     case GA_PARENT:
2571         if (!(win = WIN_GetPtr( hwnd )))
2572         {
2573             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2574             return 0;
2575         }
2576         if (win != WND_OTHER_PROCESS)
2577         {
2578             ret = win->parent;
2579             WIN_ReleasePtr( win );
2580         }
2581         else /* need to query the server */
2582         {
2583             SERVER_START_REQ( get_window_tree )
2584             {
2585                 req->handle = hwnd;
2586                 if (!wine_server_call_err( req )) ret = reply->parent;
2587             }
2588             SERVER_END_REQ;
2589         }
2590         break;
2591
2592     case GA_ROOT:
2593         if (!(list = WIN_ListParents( hwnd ))) return 0;
2594
2595         if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd );  /* top-level window */
2596         else
2597         {
2598             int count = 2;
2599             while (list[count]) count++;
2600             ret = list[count - 2];  /* get the one before the desktop */
2601         }
2602         HeapFree( GetProcessHeap(), 0, list );
2603         break;
2604
2605     case GA_ROOTOWNER:
2606         if ((ret = WIN_GetFullHandle( hwnd )) == GetDesktopWindow()) return 0;
2607         for (;;)
2608         {
2609             HWND parent = GetParent( ret );
2610             if (!parent) break;
2611             ret = parent;
2612         }
2613         break;
2614     }
2615     return ret;
2616 }
2617
2618
2619 /*****************************************************************
2620  *              SetParent (USER32.@)
2621  */
2622 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2623 {
2624     WND *wndPtr;
2625     HWND retvalue, full_handle;
2626     BOOL was_visible;
2627
2628     if (is_broadcast(hwnd) || is_broadcast(parent))
2629     {
2630         SetLastError(ERROR_INVALID_PARAMETER);
2631         return 0;
2632     }
2633
2634     if (!parent) parent = GetDesktopWindow();
2635     else parent = WIN_GetFullHandle( parent );
2636
2637     if (!IsWindow( parent ))
2638     {
2639         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2640         return 0;
2641     }
2642
2643     if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2644         return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2645
2646     hwnd = full_handle;
2647
2648     if (USER_Driver.pSetParent)
2649         return USER_Driver.pSetParent( hwnd, parent );
2650
2651     /* Windows hides the window first, then shows it again
2652      * including the WM_SHOWWINDOW messages and all */
2653     was_visible = ShowWindow( hwnd, SW_HIDE );
2654
2655     if (!IsWindow( parent )) return 0;
2656     if (!(wndPtr = WIN_GetPtr(hwnd)) || wndPtr == WND_OTHER_PROCESS) return 0;
2657
2658     retvalue = wndPtr->parent;  /* old parent */
2659     if (parent != retvalue)
2660     {
2661         WIN_LinkWindow( hwnd, parent, HWND_TOP );
2662
2663         if (parent != GetDesktopWindow()) /* a child window */
2664         {
2665             if (!(wndPtr->dwStyle & WS_CHILD))
2666             {
2667                 HMENU menu = (HMENU)SetWindowLongW( hwnd, GWL_ID, 0 );
2668                 if (menu) DestroyMenu( menu );
2669             }
2670         }
2671     }
2672     WIN_ReleasePtr( wndPtr );
2673
2674     /* SetParent additionally needs to make hwnd the topmost window
2675        in the x-order and send the expected WM_WINDOWPOSCHANGING and
2676        WM_WINDOWPOSCHANGED notification messages.
2677     */
2678     SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0,
2679                   SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | (was_visible ? SWP_SHOWWINDOW : 0) );
2680     /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
2681      * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
2682     return retvalue;
2683 }
2684
2685
2686 /*******************************************************************
2687  *              IsChild (USER32.@)
2688  */
2689 BOOL WINAPI IsChild( HWND parent, HWND child )
2690 {
2691     HWND *list = WIN_ListParents( child );
2692     int i;
2693     BOOL ret;
2694
2695     if (!list) return FALSE;
2696     parent = WIN_GetFullHandle( parent );
2697     for (i = 0; list[i]; i++) if (list[i] == parent) break;
2698     ret = (list[i] != 0);
2699     HeapFree( GetProcessHeap(), 0, list );
2700     return ret;
2701 }
2702
2703
2704 /***********************************************************************
2705  *              IsWindowVisible (USER32.@)
2706  */
2707 BOOL WINAPI IsWindowVisible( HWND hwnd )
2708 {
2709     HWND *list;
2710     BOOL retval;
2711     int i;
2712
2713     if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2714     if (!(list = WIN_ListParents( hwnd ))) return TRUE;
2715     for (i = 0; list[i]; i++)
2716         if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2717     retval = !list[i];
2718     HeapFree( GetProcessHeap(), 0, list );
2719     return retval;
2720 }
2721
2722
2723 /***********************************************************************
2724  *           WIN_IsWindowDrawable
2725  *
2726  * hwnd is drawable when it is visible, all parents are not
2727  * minimized, and it is itself not minimized unless we are
2728  * trying to draw its default class icon.
2729  */
2730 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2731 {
2732     HWND *list;
2733     BOOL retval;
2734     int i;
2735     LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2736
2737     if (!(style & WS_VISIBLE)) return FALSE;
2738     if ((style & WS_MINIMIZE) && icon && GetClassLongA( hwnd, GCL_HICON ))  return FALSE;
2739
2740     if (!(list = WIN_ListParents( hwnd ))) return TRUE;
2741     for (i = 0; list[i]; i++)
2742         if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2743             break;
2744     retval = !list[i];
2745     HeapFree( GetProcessHeap(), 0, list );
2746     return retval;
2747 }
2748
2749
2750 /*******************************************************************
2751  *              GetTopWindow (USER32.@)
2752  */
2753 HWND WINAPI GetTopWindow( HWND hwnd )
2754 {
2755     if (!hwnd) hwnd = GetDesktopWindow();
2756     return GetWindow( hwnd, GW_CHILD );
2757 }
2758
2759
2760 /*******************************************************************
2761  *              GetWindow (USER32.@)
2762  */
2763 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2764 {
2765     HWND retval = 0;
2766
2767     if (rel == GW_OWNER)  /* this one may be available locally */
2768     {
2769         WND *wndPtr = WIN_GetPtr( hwnd );
2770         if (!wndPtr)
2771         {
2772             SetLastError( ERROR_INVALID_HANDLE );
2773             return 0;
2774         }
2775         if (wndPtr != WND_OTHER_PROCESS)
2776         {
2777             retval = wndPtr->owner;
2778             WIN_ReleasePtr( wndPtr );
2779             return retval;
2780         }
2781         /* else fall through to server call */
2782     }
2783
2784     SERVER_START_REQ( get_window_tree )
2785     {
2786         req->handle = hwnd;
2787         if (!wine_server_call_err( req ))
2788         {
2789             switch(rel)
2790             {
2791             case GW_HWNDFIRST:
2792                 retval = reply->first_sibling;
2793                 break;
2794             case GW_HWNDLAST:
2795                 retval = reply->last_sibling;
2796                 break;
2797             case GW_HWNDNEXT:
2798                 retval = reply->next_sibling;
2799                 break;
2800             case GW_HWNDPREV:
2801                 retval = reply->prev_sibling;
2802                 break;
2803             case GW_OWNER:
2804                 retval = reply->owner;
2805                 break;
2806             case GW_CHILD:
2807                 retval = reply->first_child;
2808                 break;
2809             }
2810         }
2811     }
2812     SERVER_END_REQ;
2813     return retval;
2814 }
2815
2816
2817 /***********************************************************************
2818  *           WIN_InternalShowOwnedPopups
2819  *
2820  * Internal version of ShowOwnedPopups; Wine functions should use this
2821  * to avoid interfering with application calls to ShowOwnedPopups
2822  * and to make sure the application can't prevent showing/hiding.
2823  *
2824  * Set unmanagedOnly to TRUE to show/hide unmanaged windows only.
2825  *
2826  */
2827
2828 BOOL WIN_InternalShowOwnedPopups( HWND owner, BOOL fShow, BOOL unmanagedOnly )
2829 {
2830     int count = 0;
2831     WND *pWnd;
2832     HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2833
2834     if (!win_array) return TRUE;
2835
2836     /*
2837      * Show windows Lowest first, Highest last to preserve Z-Order
2838      */
2839     while (win_array[count]) count++;
2840     while (--count >= 0)
2841     {
2842         if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2843         if (!(pWnd = WIN_FindWndPtr( win_array[count] ))) continue;
2844
2845         if (pWnd->dwStyle & WS_POPUP)
2846         {
2847             if (fShow)
2848             {
2849                 /* check in window was flagged for showing in previous WIN_InternalShowOwnedPopups call */
2850                 if (pWnd->flags & WIN_NEEDS_INTERNALSOP)
2851                 {
2852                     /*
2853                      * Call ShowWindow directly because an application can intercept WM_SHOWWINDOW messages
2854                      */
2855                     ShowWindow(pWnd->hwndSelf,SW_SHOW);
2856                     pWnd->flags &= ~WIN_NEEDS_INTERNALSOP; /* remove the flag */
2857                 }
2858             }
2859             else
2860             {
2861                 if ( IsWindowVisible(pWnd->hwndSelf) &&                   /* hide only if window is visible */
2862                      !( pWnd->flags & WIN_NEEDS_INTERNALSOP ) &&          /* don't hide if previous call already did it */
2863                      !( unmanagedOnly && (pWnd->dwExStyle & WS_EX_MANAGED) ) ) /* don't hide managed windows if unmanagedOnly is TRUE */
2864                 {
2865                     /*
2866                      * Call ShowWindow directly because an application can intercept WM_SHOWWINDOW messages
2867                      */
2868                     ShowWindow(pWnd->hwndSelf,SW_HIDE);
2869                     /* flag the window for showing on next WIN_InternalShowOwnedPopups call */
2870                     pWnd->flags |= WIN_NEEDS_INTERNALSOP;
2871                 }
2872             }
2873         }
2874         WIN_ReleaseWndPtr( pWnd );
2875     }
2876     HeapFree( GetProcessHeap(), 0, win_array );
2877
2878     return TRUE;
2879 }
2880
2881 /*******************************************************************
2882  *              ShowOwnedPopups (USER32.@)
2883  */
2884 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2885 {
2886     int count = 0;
2887     WND *pWnd;
2888     HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2889
2890     if (!win_array) return TRUE;
2891
2892     while (win_array[count]) count++;
2893     while (--count >= 0)
2894     {
2895         if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2896         if (!(pWnd = WIN_FindWndPtr( win_array[count] ))) continue;
2897
2898         if (pWnd->dwStyle & WS_POPUP)
2899         {
2900             if (fShow)
2901             {
2902                 if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2903                 {
2904                     /* In Windows, ShowOwnedPopups(TRUE) generates
2905                      * WM_SHOWWINDOW messages with SW_PARENTOPENING,
2906                      * regardless of the state of the owner
2907                      */
2908                     SendMessageA(pWnd->hwndSelf, WM_SHOWWINDOW, SW_SHOW, SW_PARENTOPENING);
2909                     pWnd->flags &= ~WIN_NEEDS_SHOW_OWNEDPOPUP;
2910                 }
2911             }
2912             else
2913             {
2914                 if (IsWindowVisible(pWnd->hwndSelf))
2915                 {
2916                     /* In Windows, ShowOwnedPopups(FALSE) generates
2917                      * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
2918                      * regardless of the state of the owner
2919                      */
2920                     SendMessageA(pWnd->hwndSelf, WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
2921                     pWnd->flags |= WIN_NEEDS_SHOW_OWNEDPOPUP;
2922                 }
2923             }
2924         }
2925         WIN_ReleaseWndPtr( pWnd );
2926     }
2927     HeapFree( GetProcessHeap(), 0, win_array );
2928     return TRUE;
2929 }
2930
2931
2932 /*******************************************************************
2933  *              GetLastActivePopup (USER32.@)
2934  */
2935 HWND WINAPI GetLastActivePopup( HWND hwnd )
2936 {
2937     HWND retval = hwnd;
2938
2939     SERVER_START_REQ( get_window_info )
2940     {
2941         req->handle = hwnd;
2942         if (!wine_server_call_err( req )) retval = reply->last_active;
2943     }
2944     SERVER_END_REQ;
2945     return retval;
2946 }
2947
2948
2949 /*******************************************************************
2950  *           WIN_ListParents
2951  *
2952  * Build an array of all parents of a given window, starting with
2953  * the immediate parent. The array must be freed with HeapFree.
2954  * Returns NULL if window is a top-level window.
2955  */
2956 HWND *WIN_ListParents( HWND hwnd )
2957 {
2958     WND *win;
2959     HWND current, *list;
2960     int pos = 0, size = 16, count = 0;
2961
2962     if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
2963
2964     current = hwnd;
2965     for (;;)
2966     {
2967         if (!(win = WIN_GetPtr( current ))) goto empty;
2968         if (win == WND_OTHER_PROCESS) break;  /* need to do it the hard way */
2969         list[pos] = win->parent;
2970         WIN_ReleasePtr( win );
2971         if (!(current = list[pos]))
2972         {
2973             if (!pos) goto empty;
2974             return list;
2975         }
2976         if (++pos == size - 1)
2977         {
2978             /* need to grow the list */
2979             HWND *new_list = HeapReAlloc( GetProcessHeap(), 0, list, (size+16) * sizeof(HWND) );
2980             if (!new_list) goto empty;
2981             list = new_list;
2982             size += 16;
2983         }
2984     }
2985
2986     /* at least one parent belongs to another process, have to query the server */
2987
2988     for (;;)
2989     {
2990         count = 0;
2991         SERVER_START_REQ( get_window_parents )
2992         {
2993             req->handle = hwnd;
2994             wine_server_set_reply( req, list, (size-1) * sizeof(HWND) );
2995             if (!wine_server_call( req )) count = reply->count;
2996         }
2997         SERVER_END_REQ;
2998         if (!count) goto empty;
2999         if (size > count)
3000         {
3001             list[count] = 0;
3002             return list;
3003         }
3004         HeapFree( GetProcessHeap(), 0, list );
3005         size = count + 1;
3006         if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
3007     }
3008
3009  empty:
3010     HeapFree( GetProcessHeap(), 0, list );
3011     return NULL;
3012 }
3013
3014
3015 /*******************************************************************
3016  *           WIN_ListChildren
3017  *
3018  * Build an array of the children of a given window. The array must be
3019  * freed with HeapFree. Returns NULL when no windows are found.
3020  */
3021 HWND *WIN_ListChildren( HWND hwnd )
3022 {
3023     return list_window_children( hwnd, 0, 0 );
3024 }
3025
3026
3027 /*******************************************************************
3028  *              EnumWindows (USER32.@)
3029  */
3030 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
3031 {
3032     HWND *list;
3033     BOOL ret = TRUE;
3034     int i, iWndsLocks;
3035
3036     /* We have to build a list of all windows first, to avoid */
3037     /* unpleasant side-effects, for instance if the callback */
3038     /* function changes the Z-order of the windows.          */
3039
3040     if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
3041
3042     /* Now call the callback function for every window */
3043
3044     iWndsLocks = WIN_SuspendWndsLock();
3045     for (i = 0; list[i]; i++)
3046     {
3047         /* Make sure that the window still exists */
3048         if (!IsWindow( list[i] )) continue;
3049         if (!(ret = lpEnumFunc( list[i], lParam ))) break;
3050     }
3051     WIN_RestoreWndsLock(iWndsLocks);
3052     HeapFree( GetProcessHeap(), 0, list );
3053     return ret;
3054 }
3055
3056
3057 /**********************************************************************
3058  *              EnumThreadWindows (USER32.@)
3059  */
3060 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
3061 {
3062     HWND *list;
3063     int i, iWndsLocks;
3064
3065     if (!(list = list_window_children( GetDesktopWindow(), 0, id ))) return TRUE;
3066
3067     /* Now call the callback function for every window */
3068
3069     iWndsLocks = WIN_SuspendWndsLock();
3070     for (i = 0; list[i]; i++)
3071         if (!func( list[i], lParam )) break;
3072     WIN_RestoreWndsLock(iWndsLocks);
3073     HeapFree( GetProcessHeap(), 0, list );
3074     return TRUE;
3075 }
3076
3077
3078 /**********************************************************************
3079  *           WIN_EnumChildWindows
3080  *
3081  * Helper function for EnumChildWindows().
3082  */
3083 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
3084 {
3085     HWND *childList;
3086     BOOL ret = FALSE;
3087
3088     for ( ; *list; list++)
3089     {
3090         /* Make sure that the window still exists */
3091         if (!IsWindow( *list )) continue;
3092         /* skip owned windows */
3093         if (GetWindow( *list, GW_OWNER )) continue;
3094         /* Build children list first */
3095         childList = WIN_ListChildren( *list );
3096
3097         ret = func( *list, lParam );
3098
3099         if (childList)
3100         {
3101             if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
3102             HeapFree( GetProcessHeap(), 0, childList );
3103         }
3104         if (!ret) return FALSE;
3105     }
3106     return TRUE;
3107 }
3108
3109
3110 /**********************************************************************
3111  *              EnumChildWindows (USER32.@)
3112  */
3113 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
3114 {
3115     HWND *list;
3116     int iWndsLocks;
3117
3118     if (!(list = WIN_ListChildren( parent ))) return FALSE;
3119     iWndsLocks = WIN_SuspendWndsLock();
3120     WIN_EnumChildWindows( list, func, lParam );
3121     WIN_RestoreWndsLock(iWndsLocks);
3122     HeapFree( GetProcessHeap(), 0, list );
3123     return TRUE;
3124 }
3125
3126
3127 /*******************************************************************
3128  *              AnyPopup (USER.52)
3129  */
3130 BOOL16 WINAPI AnyPopup16(void)
3131 {
3132     return AnyPopup();
3133 }
3134
3135
3136 /*******************************************************************
3137  *              AnyPopup (USER32.@)
3138  */
3139 BOOL WINAPI AnyPopup(void)
3140 {
3141     int i;
3142     BOOL retvalue;
3143     HWND *list = WIN_ListChildren( GetDesktopWindow() );
3144
3145     if (!list) return FALSE;
3146     for (i = 0; list[i]; i++)
3147     {
3148         if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
3149     }
3150     retvalue = (list[i] != 0);
3151     HeapFree( GetProcessHeap(), 0, list );
3152     return retvalue;
3153 }
3154
3155
3156 /*******************************************************************
3157  *              FlashWindow (USER32.@)
3158  */
3159 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3160 {
3161     WND *wndPtr = WIN_FindWndPtr(hWnd);
3162
3163     TRACE("%p\n", hWnd);
3164
3165     if (!wndPtr) return FALSE;
3166     hWnd = wndPtr->hwndSelf;  /* make it a full handle */
3167
3168     if (wndPtr->dwStyle & WS_MINIMIZE)
3169     {
3170         if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
3171         {
3172             HDC hDC = GetDC(hWnd);
3173
3174             if (!SendMessageW( hWnd, WM_ERASEBKGND, (WPARAM)hDC, 0 ))
3175                 wndPtr->flags |= WIN_NEEDS_ERASEBKGND;
3176
3177             ReleaseDC( hWnd, hDC );
3178             wndPtr->flags |= WIN_NCACTIVATED;
3179         }
3180         else
3181         {
3182             RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
3183             wndPtr->flags &= ~WIN_NCACTIVATED;
3184         }
3185         WIN_ReleaseWndPtr(wndPtr);
3186         return TRUE;
3187     }
3188     else
3189     {
3190         WPARAM16 wparam;
3191         if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3192         else wparam = (hWnd == GetForegroundWindow());
3193
3194         WIN_ReleaseWndPtr(wndPtr);
3195         SendMessageW( hWnd, WM_NCACTIVATE, wparam, (LPARAM)0 );
3196         return wparam;
3197     }
3198 }
3199
3200 /*******************************************************************
3201  *              FlashWindowEx (USER32.@)
3202  */
3203 BOOL WINAPI FlashWindowEx( PFLASHWINFO pfwi )
3204 {
3205     FIXME("%p\n", pfwi);
3206     return TRUE;
3207 }
3208
3209 /*******************************************************************
3210  *              GetWindowContextHelpId (USER32.@)
3211  */
3212 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3213 {
3214     DWORD retval;
3215     WND *wnd = WIN_FindWndPtr( hwnd );
3216     if (!wnd) return 0;
3217     retval = wnd->helpContext;
3218     WIN_ReleaseWndPtr(wnd);
3219     return retval;
3220 }
3221
3222
3223 /*******************************************************************
3224  *              SetWindowContextHelpId (USER32.@)
3225  */
3226 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3227 {
3228     WND *wnd = WIN_FindWndPtr( hwnd );
3229     if (!wnd) return FALSE;
3230     wnd->helpContext = id;
3231     WIN_ReleaseWndPtr(wnd);
3232     return TRUE;
3233 }
3234
3235
3236 /*******************************************************************
3237  *              DragDetect (USER32.@)
3238  */
3239 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3240 {
3241     MSG msg;
3242     RECT rect;
3243
3244     rect.left = pt.x - wDragWidth;
3245     rect.right = pt.x + wDragWidth;
3246
3247     rect.top = pt.y - wDragHeight;
3248     rect.bottom = pt.y + wDragHeight;
3249
3250     SetCapture(hWnd);
3251
3252     while(1)
3253     {
3254         while(PeekMessageA(&msg ,0 ,WM_MOUSEFIRST ,WM_MOUSELAST ,PM_REMOVE))
3255         {
3256             if( msg.message == WM_LBUTTONUP )
3257             {
3258                 ReleaseCapture();
3259                 return 0;
3260             }
3261             if( msg.message == WM_MOUSEMOVE )
3262             {
3263                 POINT tmp;
3264                 tmp.x = LOWORD(msg.lParam);
3265                 tmp.y = HIWORD(msg.lParam);
3266                 if( !PtInRect( &rect, tmp ))
3267                 {
3268                     ReleaseCapture();
3269                     return 1;
3270                 }
3271             }
3272         }
3273         WaitMessage();
3274     }
3275     return 0;
3276 }
3277
3278 /******************************************************************************
3279  *              GetWindowModuleFileNameA (USER32.@)
3280  */
3281 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR lpszFileName, UINT cchFileNameMax)
3282 {
3283     FIXME("GetWindowModuleFileNameA(hwnd %p, lpszFileName %p, cchFileNameMax %u) stub!\n",
3284           hwnd, lpszFileName, cchFileNameMax);
3285     return 0;
3286 }
3287
3288 /******************************************************************************
3289  *              GetWindowModuleFileNameW (USER32.@)
3290  */
3291 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR lpszFileName, UINT cchFileNameMax)
3292 {
3293     FIXME("GetWindowModuleFileNameW(hwnd %p, lpszFileName %p, cchFileNameMax %u) stub!\n",
3294           hwnd, lpszFileName, cchFileNameMax);
3295     return 0;
3296 }
3297
3298 /******************************************************************************
3299  *              GetWindowInfo (USER32.@)
3300  *
3301  * Note: tests show that Windows doesn't check cbSize of the structure.
3302  */
3303 BOOL WINAPI GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3304 {
3305     if (!pwi) return FALSE;
3306     if (!IsWindow(hwnd)) return FALSE;
3307
3308     GetWindowRect(hwnd, &pwi->rcWindow);
3309     GetClientRect(hwnd, &pwi->rcClient);
3310     /* translate to screen coordinates */
3311     MapWindowPoints(hwnd, 0, (LPPOINT)&pwi->rcClient, 2);
3312
3313     pwi->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
3314     pwi->dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3315     pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3316
3317     pwi->cxWindowBorders = pwi->rcClient.left - pwi->rcWindow.left;
3318     pwi->cyWindowBorders = pwi->rcWindow.bottom - pwi->rcClient.bottom;
3319
3320     pwi->atomWindowType = GetClassLongW( hwnd, GCW_ATOM );
3321     pwi->wCreatorVersion = 0x0400;
3322
3323     return TRUE;
3324 }