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