Change return code from ExitWindowsEx() (and with that related
[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)) return;
201     if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOPARENTNOTIFY) return;
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 style - stage 1
1109      *
1110      * These are patches that appear to affect both the style loaded into the
1111      * WIN structure and passed in the CreateStruct to the WM_CREATE etc.
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     /* Create the window structure */
1128
1129     if (!(wndPtr = create_window_handle( parent, owner, classAtom, cs->hInstance, type )))
1130     {
1131         TRACE("out of memory\n" );
1132         return 0;
1133     }
1134     hwnd = wndPtr->hwndSelf;
1135
1136     /* Fill the window structure */
1137
1138     wndPtr->tid            = GetCurrentThreadId();
1139     wndPtr->owner          = owner;
1140     wndPtr->parent         = parent;
1141     wndPtr->hInstance      = cs->hInstance;
1142     wndPtr->text           = NULL;
1143     wndPtr->hrgnUpdate     = 0;
1144     wndPtr->hrgnWnd        = 0;
1145     wndPtr->dwStyle        = cs->style & ~WS_VISIBLE;
1146     wndPtr->dwExStyle      = cs->dwExStyle;
1147     wndPtr->wIDmenu        = 0;
1148     wndPtr->helpContext    = 0;
1149     wndPtr->flags          = (type == WIN_PROC_16) ? 0 : WIN_ISWIN32;
1150     wndPtr->pVScroll       = NULL;
1151     wndPtr->pHScroll       = NULL;
1152     wndPtr->userdata       = 0;
1153     wndPtr->hIcon          = 0;
1154     wndPtr->hIconSmall     = 0;
1155     wndPtr->hSysMenu       = (wndPtr->dwStyle & WS_SYSMENU) ? MENU_GetSysMenu( hwnd, 0 ) : 0;
1156
1157     /* Correct the window style - stage 2 */
1158
1159     if (!(cs->style & WS_CHILD))
1160     {
1161         wndPtr->dwStyle |= WS_CLIPSIBLINGS;
1162         if (!(cs->style & WS_POPUP))
1163         {
1164             wndPtr->dwStyle |= WS_CAPTION;
1165             wndPtr->flags |= WIN_NEED_SIZE;
1166         }
1167     }
1168     SERVER_START_REQ( set_window_info )
1169     {
1170         req->handle    = hwnd;
1171         req->flags     = SET_WIN_STYLE | SET_WIN_EXSTYLE | SET_WIN_INSTANCE;
1172         req->style     = wndPtr->dwStyle;
1173         req->ex_style  = wndPtr->dwExStyle;
1174         req->instance  = (void *)wndPtr->hInstance;
1175         req->extra_offset = -1;
1176         wine_server_call( req );
1177     }
1178     SERVER_END_REQ;
1179
1180     /* Get class or window DC if needed */
1181
1182     if (wndPtr->clsStyle & CS_OWNDC) wndPtr->dce = DCE_AllocDCE(hwnd,DCE_WINDOW_DC);
1183
1184     /* Set the window menu */
1185
1186     if (((wndPtr->dwStyle & (WS_CAPTION|WS_CHILD)) == WS_CAPTION) ||
1187         (wndPtr->dwExStyle & WS_EX_APPWINDOW))
1188     {
1189         if (cs->hMenu) SetMenu(hwnd, cs->hMenu);
1190         else
1191         {
1192             LPCSTR menuName = (LPCSTR)GetClassLongA( hwnd, GCL_MENUNAME );
1193             if (menuName)
1194             {
1195                 if (HIWORD(cs->hInstance))
1196                     cs->hMenu = LoadMenuA(cs->hInstance,menuName);
1197                 else
1198                     cs->hMenu = HMENU_32(LoadMenu16(HINSTANCE_16(cs->hInstance),menuName));
1199
1200                 if (cs->hMenu) SetMenu( hwnd, cs->hMenu );
1201             }
1202         }
1203     }
1204     else SetWindowLongW( hwnd, GWL_ID, (UINT)cs->hMenu );
1205     WIN_ReleaseWndPtr( wndPtr );
1206
1207     if (!USER_Driver.pCreateWindow( hwnd, cs, unicode))
1208     {
1209         WIN_DestroyWindow( hwnd );
1210         return 0;
1211     }
1212
1213     /* Notify the parent window only */
1214
1215     send_parent_notify( hwnd, WM_CREATE );
1216     if (!IsWindow( hwnd )) return 0;
1217
1218     if (cs->dwExStyle & WS_EX_MDICHILD)
1219     {
1220         if (top_child)
1221         {
1222             /* Restore current maximized child */
1223             if((cs->style & WS_VISIBLE) && IsZoomed(top_child))
1224             {
1225                 TRACE("Restoring current maximized child %p\n", top_child);
1226                 ShowWindow(top_child, SW_SHOWNOACTIVATE);
1227             }
1228         }
1229
1230         SendMessageW(cs->hwndParent, WM_MDIREFRESHMENU, 0, 0);
1231     }
1232
1233     if (cs->style & WS_VISIBLE)
1234     {
1235         /* in case WS_VISIBLE got set in the meantime */
1236         if (!(wndPtr = WIN_GetPtr( hwnd ))) return 0;
1237         WIN_SetStyle( hwnd, wndPtr->dwStyle & ~WS_VISIBLE );
1238         WIN_ReleasePtr( wndPtr );
1239         ShowWindow( hwnd, sw );
1240     }
1241
1242     /* Call WH_SHELL hook */
1243
1244     if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1245         HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0, TRUE );
1246
1247     TRACE("created window %p\n", hwnd);
1248     return hwnd;
1249 }
1250
1251
1252 /***********************************************************************
1253  *              CreateWindow (USER.41)
1254  */
1255 HWND16 WINAPI CreateWindow16( LPCSTR className, LPCSTR windowName,
1256                               DWORD style, INT16 x, INT16 y, INT16 width,
1257                               INT16 height, HWND16 parent, HMENU16 menu,
1258                               HINSTANCE16 instance, LPVOID data )
1259 {
1260     return CreateWindowEx16( 0, className, windowName, style,
1261                            x, y, width, height, parent, menu, instance, data );
1262 }
1263
1264
1265 /***********************************************************************
1266  *              CreateWindowEx (USER.452)
1267  */
1268 HWND16 WINAPI CreateWindowEx16( DWORD exStyle, LPCSTR className,
1269                                 LPCSTR windowName, DWORD style, INT16 x,
1270                                 INT16 y, INT16 width, INT16 height,
1271                                 HWND16 parent, HMENU16 menu,
1272                                 HINSTANCE16 instance, LPVOID data )
1273 {
1274     ATOM classAtom;
1275     CREATESTRUCTA cs;
1276     char buffer[256];
1277
1278     /* Find the class atom */
1279
1280     if (HIWORD(className))
1281     {
1282         if (!(classAtom = GlobalFindAtomA( className )))
1283         {
1284             ERR( "bad class name %s\n", debugstr_a(className) );
1285             return 0;
1286         }
1287     }
1288     else
1289     {
1290         classAtom = LOWORD(className);
1291         if (!GlobalGetAtomNameA( classAtom, buffer, sizeof(buffer) ))
1292         {
1293             ERR( "bad atom %x\n", classAtom);
1294             return 0;
1295         }
1296         className = buffer;
1297     }
1298
1299     /* Fix the coordinates */
1300
1301     cs.x  = (x == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)x;
1302     cs.y  = (y == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)y;
1303     cs.cx = (width == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)width;
1304     cs.cy = (height == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)height;
1305
1306     /* Create the window */
1307
1308     cs.lpCreateParams = data;
1309     cs.hInstance      = HINSTANCE_32(instance);
1310     cs.hMenu          = HMENU_32(menu);
1311     cs.hwndParent     = WIN_Handle32( parent );
1312     cs.style          = style;
1313     cs.lpszName       = windowName;
1314     cs.lpszClass      = className;
1315     cs.dwExStyle      = exStyle;
1316
1317     return HWND_16( WIN_CreateWindowEx( &cs, classAtom, WIN_PROC_16 ));
1318 }
1319
1320
1321 /***********************************************************************
1322  *              CreateWindowExA (USER32.@)
1323  */
1324 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1325                                  LPCSTR windowName, DWORD style, INT x,
1326                                  INT y, INT width, INT height,
1327                                  HWND parent, HMENU menu,
1328                                  HINSTANCE instance, LPVOID data )
1329 {
1330     ATOM classAtom;
1331     CREATESTRUCTA cs;
1332     char buffer[256];
1333
1334     /* Find the class atom */
1335
1336     if (HIWORD(className))
1337     {
1338         if (!(classAtom = GlobalFindAtomA( className )))
1339         {
1340             ERR( "bad class name %s\n", debugstr_a(className) );
1341             return 0;
1342         }
1343     }
1344     else
1345     {
1346         classAtom = LOWORD(className);
1347         if (!GlobalGetAtomNameA( classAtom, buffer, sizeof(buffer) ))
1348         {
1349             ERR( "bad atom %x\n", classAtom);
1350             return 0;
1351         }
1352         className = buffer;
1353     }
1354
1355     /* Create the window */
1356
1357     cs.lpCreateParams = data;
1358     cs.hInstance      = instance;
1359     cs.hMenu          = menu;
1360     cs.hwndParent     = parent;
1361     cs.x              = x;
1362     cs.y              = y;
1363     cs.cx             = width;
1364     cs.cy             = height;
1365     cs.style          = style;
1366     cs.lpszName       = windowName;
1367     cs.lpszClass      = className;
1368     cs.dwExStyle      = exStyle;
1369
1370     return WIN_CreateWindowEx( &cs, classAtom, WIN_PROC_32A );
1371 }
1372
1373
1374 /***********************************************************************
1375  *              CreateWindowExW (USER32.@)
1376  */
1377 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1378                                  LPCWSTR windowName, DWORD style, INT x,
1379                                  INT y, INT width, INT height,
1380                                  HWND parent, HMENU menu,
1381                                  HINSTANCE instance, LPVOID data )
1382 {
1383     ATOM classAtom;
1384     CREATESTRUCTW cs;
1385     WCHAR buffer[256];
1386
1387     /* Find the class atom */
1388
1389     if (HIWORD(className))
1390     {
1391         if (!(classAtom = GlobalFindAtomW( className )))
1392         {
1393             ERR( "bad class name %s\n", debugstr_w(className) );
1394             return 0;
1395         }
1396     }
1397     else
1398     {
1399         classAtom = LOWORD(className);
1400         if (!GlobalGetAtomNameW( classAtom, buffer, sizeof(buffer)/sizeof(WCHAR) ))
1401         {
1402             ERR( "bad atom %x\n", classAtom);
1403             return 0;
1404         }
1405         className = buffer;
1406     }
1407
1408     /* Create the window */
1409
1410     cs.lpCreateParams = data;
1411     cs.hInstance      = instance;
1412     cs.hMenu          = menu;
1413     cs.hwndParent     = parent;
1414     cs.x              = x;
1415     cs.y              = y;
1416     cs.cx             = width;
1417     cs.cy             = height;
1418     cs.style          = style;
1419     cs.lpszName       = windowName;
1420     cs.lpszClass      = className;
1421     cs.dwExStyle      = exStyle;
1422
1423     /* Note: we rely on the fact that CREATESTRUCTA and */
1424     /* CREATESTRUCTW have the same layout. */
1425     return WIN_CreateWindowEx( (CREATESTRUCTA *)&cs, classAtom, WIN_PROC_32W );
1426 }
1427
1428
1429 /***********************************************************************
1430  *           WIN_SendDestroyMsg
1431  */
1432 static void WIN_SendDestroyMsg( HWND hwnd )
1433 {
1434     GUITHREADINFO info;
1435
1436     if (GetGUIThreadInfo( GetCurrentThreadId(), &info ))
1437     {
1438         if (hwnd == info.hwndCaret) DestroyCaret();
1439     }
1440     if (USER_Driver.pResetSelectionOwner)
1441         USER_Driver.pResetSelectionOwner( hwnd, TRUE );
1442
1443     /*
1444      * Send the WM_DESTROY to the window.
1445      */
1446     SendMessageA( hwnd, WM_DESTROY, 0, 0);
1447
1448     /*
1449      * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1450      * make sure that the window still exists when we come back.
1451      */
1452     if (IsWindow(hwnd))
1453     {
1454         HWND* pWndArray;
1455         int i;
1456
1457         if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1458
1459         /* start from the end (FIXME: is this needed?) */
1460         for (i = 0; pWndArray[i]; i++) ;
1461
1462         while (--i >= 0)
1463         {
1464             if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1465         }
1466         HeapFree( GetProcessHeap(), 0, pWndArray );
1467     }
1468     else
1469       WARN("\tdestroyed itself while in WM_DESTROY!\n");
1470 }
1471
1472
1473 /***********************************************************************
1474  *              DestroyWindow (USER32.@)
1475  */
1476 BOOL WINAPI DestroyWindow( HWND hwnd )
1477 {
1478     BOOL is_child;
1479     HWND h;
1480
1481     if (!(hwnd = WIN_IsCurrentThread( hwnd )) || (hwnd == GetDesktopWindow()))
1482     {
1483         SetLastError( ERROR_ACCESS_DENIED );
1484         return FALSE;
1485     }
1486
1487     TRACE("(%p)\n", hwnd);
1488
1489     /* Look whether the focus is within the tree of windows we will
1490      * be destroying.
1491      */
1492     h = GetFocus();
1493     if (h == hwnd || IsChild( hwnd, h ))
1494     {
1495         HWND parent = GetAncestor( hwnd, GA_PARENT );
1496         if (parent == GetDesktopWindow()) parent = 0;
1497         SetFocus( parent );
1498     }
1499
1500     if (GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_MDICHILD)
1501         SendMessageW(GetAncestor(hwnd, GA_PARENT), WM_MDIREFRESHMENU, 0, 0);
1502
1503       /* Call hooks */
1504
1505     if (HOOK_CallHooks( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0, TRUE )) return FALSE;
1506
1507     is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;
1508
1509     if (is_child)
1510     {
1511         if (!USER_IsExitingThread( GetCurrentThreadId() ))
1512             send_parent_notify( hwnd, WM_DESTROY );
1513     }
1514     else if (!GetWindow( hwnd, GW_OWNER ))
1515     {
1516         HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
1517         /* FIXME: clean up palette - see "Internals" p.352 */
1518     }
1519
1520     if (!IsWindow(hwnd)) return TRUE;
1521
1522     if (USER_Driver.pResetSelectionOwner)
1523         USER_Driver.pResetSelectionOwner( hwnd, FALSE ); /* before the window is unmapped */
1524
1525       /* Hide the window */
1526
1527     if (!ShowWindow( hwnd, SW_HIDE ))
1528     {
1529         if (hwnd == GetActiveWindow()) WINPOS_ActivateOtherWindow( hwnd );
1530     }
1531     if (!IsWindow(hwnd)) return TRUE;
1532
1533       /* Recursively destroy owned windows */
1534
1535     if (!is_child)
1536     {
1537         for (;;)
1538         {
1539             int i, got_one = 0;
1540             HWND *list = WIN_ListChildren( GetDesktopWindow() );
1541             if (list)
1542             {
1543                 for (i = 0; list[i]; i++)
1544                 {
1545                     if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1546                     if (WIN_IsCurrentThread( list[i] ))
1547                     {
1548                         DestroyWindow( list[i] );
1549                         got_one = 1;
1550                         continue;
1551                     }
1552                     WIN_SetOwner( list[i], 0 );
1553                 }
1554                 HeapFree( GetProcessHeap(), 0, list );
1555             }
1556             if (!got_one) break;
1557         }
1558     }
1559
1560       /* Send destroy messages */
1561
1562     WIN_SendDestroyMsg( hwnd );
1563     if (!IsWindow( hwnd )) return TRUE;
1564
1565     if (GetClipboardOwner() == hwnd)
1566         CLIPBOARD_ReleaseOwner();
1567
1568       /* Unlink now so we won't bother with the children later on */
1569
1570     WIN_UnlinkWindow( hwnd );
1571
1572       /* Destroy the window storage */
1573
1574     WIN_DestroyWindow( hwnd );
1575     return TRUE;
1576 }
1577
1578
1579 /***********************************************************************
1580  *              CloseWindow (USER32.@)
1581  */
1582 BOOL WINAPI CloseWindow( HWND hwnd )
1583 {
1584     if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1585     ShowWindow( hwnd, SW_MINIMIZE );
1586     return TRUE;
1587 }
1588
1589
1590 /***********************************************************************
1591  *              OpenIcon (USER32.@)
1592  */
1593 BOOL WINAPI OpenIcon( HWND hwnd )
1594 {
1595     if (!IsIconic( hwnd )) return FALSE;
1596     ShowWindow( hwnd, SW_SHOWNORMAL );
1597     return TRUE;
1598 }
1599
1600
1601 /***********************************************************************
1602  *           WIN_FindWindow
1603  *
1604  * Implementation of FindWindow() and FindWindowEx().
1605  */
1606 static HWND WIN_FindWindow( HWND parent, HWND child, ATOM className, LPCWSTR title )
1607 {
1608     HWND *list = NULL;
1609     HWND retvalue = 0;
1610     int i = 0, len = 0;
1611     WCHAR *buffer = NULL;
1612
1613     if (!parent) parent = GetDesktopWindow();
1614     if (title)
1615     {
1616         len = strlenW(title) + 1;  /* one extra char to check for chars beyond the end */
1617         if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1618     }
1619
1620     if (!(list = list_window_children( parent, className, 0 ))) goto done;
1621
1622     if (child)
1623     {
1624         child = WIN_GetFullHandle( child );
1625         while (list[i] && list[i] != child) i++;
1626         if (!list[i]) goto done;
1627         i++;  /* start from next window */
1628     }
1629
1630     if (title)
1631     {
1632         while (list[i])
1633         {
1634             if (GetWindowTextW( list[i], buffer, len + 1 ) && !strcmpiW( buffer, title )) break;
1635             i++;
1636         }
1637     }
1638     retvalue = list[i];
1639
1640  done:
1641     if (list) HeapFree( GetProcessHeap(), 0, list );
1642     if (buffer) HeapFree( GetProcessHeap(), 0, buffer );
1643     return retvalue;
1644 }
1645
1646
1647
1648 /***********************************************************************
1649  *              FindWindowA (USER32.@)
1650  */
1651 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1652 {
1653     HWND ret = FindWindowExA( 0, 0, className, title );
1654     if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1655     return ret;
1656 }
1657
1658
1659 /***********************************************************************
1660  *              FindWindowExA (USER32.@)
1661  */
1662 HWND WINAPI FindWindowExA( HWND parent, HWND child,
1663                                LPCSTR className, LPCSTR title )
1664 {
1665     ATOM atom = 0;
1666     LPWSTR buffer;
1667     HWND hwnd;
1668     INT len;
1669
1670     if (className)
1671     {
1672         /* If the atom doesn't exist, then no class */
1673         /* with this name exists either. */
1674         if (!(atom = GlobalFindAtomA( className )))
1675         {
1676             SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1677             return 0;
1678         }
1679     }
1680     if (!title) return WIN_FindWindow( parent, child, atom, NULL );
1681
1682     len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
1683     if (!(buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
1684     MultiByteToWideChar( CP_ACP, 0, title, -1, buffer, len );
1685     hwnd = WIN_FindWindow( parent, child, atom, buffer );
1686     HeapFree( GetProcessHeap(), 0, buffer );
1687     return hwnd;
1688 }
1689
1690
1691 /***********************************************************************
1692  *              FindWindowExW (USER32.@)
1693  */
1694 HWND WINAPI FindWindowExW( HWND parent, HWND child,
1695                                LPCWSTR className, LPCWSTR title )
1696 {
1697     ATOM atom = 0;
1698
1699     if (className)
1700     {
1701         /* If the atom doesn't exist, then no class */
1702         /* with this name exists either. */
1703         if (!(atom = GlobalFindAtomW( className )))
1704         {
1705             SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1706             return 0;
1707         }
1708     }
1709     return WIN_FindWindow( parent, child, atom, title );
1710 }
1711
1712
1713 /***********************************************************************
1714  *              FindWindowW (USER32.@)
1715  */
1716 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
1717 {
1718     return FindWindowExW( 0, 0, className, title );
1719 }
1720
1721
1722 /**********************************************************************
1723  *              GetDesktopWindow (USER32.@)
1724  */
1725 HWND WINAPI GetDesktopWindow(void)
1726 {
1727     if (pWndDesktop) return pWndDesktop->hwndSelf;
1728     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" );
1729     ExitProcess(1);
1730     return 0;
1731 }
1732
1733
1734 /*******************************************************************
1735  *              EnableWindow (USER32.@)
1736  */
1737 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
1738 {
1739     WND *wndPtr;
1740     BOOL retvalue;
1741     LONG style;
1742     HWND full_handle;
1743
1744     if (is_broadcast(hwnd))
1745     {
1746         SetLastError( ERROR_INVALID_PARAMETER );
1747         return FALSE;
1748     }
1749
1750     if (!(full_handle = WIN_IsCurrentThread( hwnd )))
1751         return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
1752
1753     hwnd = full_handle;
1754
1755     TRACE("( %p, %d )\n", hwnd, enable);
1756
1757     if (!(wndPtr = WIN_GetPtr( hwnd ))) return FALSE;
1758     style = wndPtr->dwStyle;
1759     retvalue = ((style & WS_DISABLED) != 0);
1760     WIN_ReleasePtr( wndPtr );
1761
1762     if (enable && retvalue)
1763     {
1764         WIN_SetStyle( hwnd, style & ~WS_DISABLED );
1765         SendMessageA( hwnd, WM_ENABLE, TRUE, 0 );
1766     }
1767     else if (!enable && !retvalue)
1768     {
1769         HWND focus_wnd, capture_wnd;
1770
1771         SendMessageA( hwnd, WM_CANCELMODE, 0, 0);
1772
1773         WIN_SetStyle( hwnd, style | WS_DISABLED );
1774
1775         focus_wnd = GetFocus();
1776         if (hwnd == focus_wnd || IsChild(hwnd, focus_wnd))
1777             SetFocus( 0 );  /* A disabled window can't have the focus */
1778
1779         capture_wnd = GetCapture();
1780         if (hwnd == capture_wnd || IsChild(hwnd, capture_wnd))
1781             ReleaseCapture();  /* A disabled window can't capture the mouse */
1782
1783         SendMessageA( hwnd, WM_ENABLE, FALSE, 0 );
1784     }
1785     return retvalue;
1786 }
1787
1788
1789 /***********************************************************************
1790  *              IsWindowEnabled (USER32.@)
1791  */
1792 BOOL WINAPI IsWindowEnabled(HWND hWnd)
1793 {
1794     return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
1795 }
1796
1797
1798 /***********************************************************************
1799  *              IsWindowUnicode (USER32.@)
1800  */
1801 BOOL WINAPI IsWindowUnicode( HWND hwnd )
1802 {
1803     WND * wndPtr;
1804     BOOL retvalue;
1805
1806     if (!(wndPtr = WIN_FindWndPtr(hwnd))) return FALSE;
1807     retvalue = (WINPROC_GetProcType( wndPtr->winproc ) == WIN_PROC_32W);
1808     WIN_ReleaseWndPtr(wndPtr);
1809     return retvalue;
1810 }
1811
1812
1813 /**********************************************************************
1814  *              GetWindowWord (USER32.@)
1815  */
1816 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
1817 {
1818     if (offset >= 0)
1819     {
1820         WORD retvalue = 0;
1821         WND *wndPtr = WIN_GetPtr( hwnd );
1822         if (!wndPtr)
1823         {
1824             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1825             return 0;
1826         }
1827         if (wndPtr == WND_OTHER_PROCESS)
1828         {
1829             SERVER_START_REQ( set_window_info )
1830             {
1831                 req->handle = hwnd;
1832                 req->flags  = 0;  /* don't set anything, just retrieve */
1833                 req->extra_offset = offset;
1834                 req->extra_size = sizeof(retvalue);
1835                 if (!wine_server_call_err( req ))
1836                     memcpy( &retvalue, &reply->old_extra_value, sizeof(retvalue) );
1837             }
1838             SERVER_END_REQ;
1839             return retvalue;
1840         }
1841         if (offset > (int)(wndPtr->cbWndExtra - sizeof(WORD)))
1842         {
1843             WARN("Invalid offset %d\n", offset );
1844             SetLastError( ERROR_INVALID_INDEX );
1845         }
1846         else memcpy( &retvalue,  (char *)wndPtr->wExtra + offset, sizeof(retvalue) );
1847         WIN_ReleasePtr( wndPtr );
1848         return retvalue;
1849     }
1850
1851     switch(offset)
1852     {
1853     case GWL_HWNDPARENT:
1854         return GetWindowLongW( hwnd, offset );
1855     case GWL_ID:
1856     case GWL_HINSTANCE:
1857         {
1858             LONG ret = GetWindowLongW( hwnd, offset );
1859             if (HIWORD(ret))
1860                 WARN("%d: discards high bits of 0x%08lx!\n", offset, ret );
1861             return LOWORD(ret);
1862         }
1863     default:
1864         WARN("Invalid offset %d\n", offset );
1865         return 0;
1866     }
1867 }
1868
1869
1870 /**********************************************************************
1871  *              SetWindowWord (USER32.@)
1872  */
1873 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
1874 {
1875     WORD retval = 0;
1876     WND * wndPtr;
1877
1878     switch(offset)
1879     {
1880     case GWL_ID:
1881     case GWL_HINSTANCE:
1882     case GWL_HWNDPARENT:
1883         return SetWindowLongW( hwnd, offset, (UINT)newval );
1884     default:
1885         if (offset < 0)
1886         {
1887             WARN("Invalid offset %d\n", offset );
1888             SetLastError( ERROR_INVALID_INDEX );
1889             return 0;
1890         }
1891     }
1892
1893     wndPtr = WIN_GetPtr( hwnd );
1894     if (wndPtr == WND_OTHER_PROCESS)
1895     {
1896         if (IsWindow(hwnd))
1897             FIXME( "set %d <- %x not supported yet on other process window %p\n",
1898                    offset, newval, hwnd );
1899         wndPtr = NULL;
1900     }
1901     if (!wndPtr)
1902     {
1903        SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1904        return 0;
1905     }
1906
1907     if (offset > (int)(wndPtr->cbWndExtra - sizeof(WORD)))
1908     {
1909         WARN("Invalid offset %d\n", offset );
1910         WIN_ReleasePtr(wndPtr);
1911         SetLastError( ERROR_INVALID_INDEX );
1912         return 0;
1913     }
1914
1915     SERVER_START_REQ( set_window_info )
1916     {
1917         req->handle = hwnd;
1918         req->flags = SET_WIN_EXTRA;
1919         req->extra_offset = offset;
1920         req->extra_size = sizeof(newval);
1921         memcpy( &req->extra_value, &newval, sizeof(newval) );
1922         if (!wine_server_call_err( req ))
1923         {
1924             void *ptr = (char *)wndPtr->wExtra + offset;
1925             memcpy( &retval, ptr, sizeof(retval) );
1926             memcpy( ptr, &newval, sizeof(newval) );
1927         }
1928     }
1929     SERVER_END_REQ;
1930     WIN_ReleasePtr( wndPtr );
1931     return retval;
1932 }
1933
1934
1935 /**********************************************************************
1936  *           WIN_GetWindowLong
1937  *
1938  * Helper function for GetWindowLong().
1939  */
1940 static LONG WIN_GetWindowLong( HWND hwnd, INT offset, WINDOWPROCTYPE type )
1941 {
1942     LONG retvalue = 0;
1943     WND *wndPtr;
1944
1945     if (offset == GWL_HWNDPARENT)
1946     {
1947         HWND parent = GetAncestor( hwnd, GA_PARENT );
1948         if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
1949         return (LONG)parent;
1950     }
1951
1952     if (!(wndPtr = WIN_GetPtr( hwnd )))
1953     {
1954         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1955         return 0;
1956     }
1957
1958     if (wndPtr == WND_OTHER_PROCESS)
1959     {
1960         if (offset == GWL_WNDPROC)
1961         {
1962             SetLastError( ERROR_ACCESS_DENIED );
1963             return 0;
1964         }
1965         SERVER_START_REQ( set_window_info )
1966         {
1967             req->handle = hwnd;
1968             req->flags  = 0;  /* don't set anything, just retrieve */
1969             req->extra_offset = (offset >= 0) ? offset : -1;
1970             req->extra_size = (offset >= 0) ? sizeof(retvalue) : 0;
1971             if (!wine_server_call_err( req ))
1972             {
1973                 switch(offset)
1974                 {
1975                 case GWL_STYLE:     retvalue = reply->old_style; break;
1976                 case GWL_EXSTYLE:   retvalue = reply->old_ex_style; break;
1977                 case GWL_ID:        retvalue = reply->old_id; break;
1978                 case GWL_HINSTANCE: retvalue = (ULONG_PTR)reply->old_instance; break;
1979                 case GWL_USERDATA:  retvalue = (ULONG_PTR)reply->old_user_data; break;
1980                 default:
1981                     if (offset >= 0) retvalue = reply->old_extra_value;
1982                     else SetLastError( ERROR_INVALID_INDEX );
1983                     break;
1984                 }
1985             }
1986         }
1987         SERVER_END_REQ;
1988         return retvalue;
1989     }
1990
1991     /* now we have a valid wndPtr */
1992
1993     if (offset >= 0)
1994     {
1995         if (offset > (int)(wndPtr->cbWndExtra - sizeof(LONG)))
1996         {
1997           /*
1998             * Some programs try to access last element from 16 bit
1999             * code using illegal offset value. Hopefully this is
2000             * what those programs really expect.
2001             */
2002            if (type == WIN_PROC_16 &&
2003                wndPtr->cbWndExtra >= 4 &&
2004                offset == wndPtr->cbWndExtra - sizeof(WORD))
2005            {
2006                INT offset2 = wndPtr->cbWndExtra - sizeof(LONG);
2007
2008                ERR( "- replaced invalid offset %d with %d\n",
2009                     offset, offset2 );
2010
2011                 retvalue = *(LONG *)(((char *)wndPtr->wExtra) + offset2);
2012                 WIN_ReleasePtr( wndPtr );
2013                 return retvalue;
2014             }
2015             WARN("Invalid offset %d\n", offset );
2016             WIN_ReleasePtr( wndPtr );
2017             SetLastError( ERROR_INVALID_INDEX );
2018             return 0;
2019         }
2020         retvalue = *(LONG *)(((char *)wndPtr->wExtra) + offset);
2021         /* Special case for dialog window procedure */
2022         if ((offset == DWL_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
2023             retvalue = (LONG)WINPROC_GetProc( (WNDPROC)retvalue, type );
2024         WIN_ReleasePtr( wndPtr );
2025         return retvalue;
2026     }
2027
2028     switch(offset)
2029     {
2030     case GWL_USERDATA:   retvalue = wndPtr->userdata; break;
2031     case GWL_STYLE:      retvalue = wndPtr->dwStyle; break;
2032     case GWL_EXSTYLE:    retvalue = wndPtr->dwExStyle; break;
2033     case GWL_ID:         retvalue = (LONG)wndPtr->wIDmenu; break;
2034     case GWL_WNDPROC:    retvalue = (LONG)WINPROC_GetProc( wndPtr->winproc, type ); break;
2035     case GWL_HINSTANCE:  retvalue = (LONG)wndPtr->hInstance; break;
2036     default:
2037         WARN("Unknown offset %d\n", offset );
2038         SetLastError( ERROR_INVALID_INDEX );
2039         break;
2040     }
2041     WIN_ReleasePtr(wndPtr);
2042     return retvalue;
2043 }
2044
2045
2046 /**********************************************************************
2047  *           WIN_SetWindowLong
2048  *
2049  * Helper function for SetWindowLong().
2050  *
2051  * 0 is the failure code. However, in the case of failure SetLastError
2052  * must be set to distinguish between a 0 return value and a failure.
2053  */
2054 static LONG WIN_SetWindowLong( HWND hwnd, INT offset, LONG newval,
2055                                WINDOWPROCTYPE type )
2056 {
2057     STYLESTRUCT style;
2058     BOOL ok;
2059     LONG retval = 0;
2060     WND *wndPtr;
2061
2062     TRACE( "%p %d %lx %x\n", hwnd, offset, newval, type );
2063
2064     if (is_broadcast(hwnd))
2065     {
2066         SetLastError( ERROR_INVALID_PARAMETER );
2067         return FALSE;
2068     }
2069     if (!WIN_IsCurrentProcess( hwnd ))
2070     {
2071         if (offset == GWL_WNDPROC)
2072         {
2073             SetLastError( ERROR_ACCESS_DENIED );
2074             return 0;
2075         }
2076         return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, offset, newval );
2077     }
2078
2079     wndPtr = WIN_GetPtr( hwnd );
2080     if (wndPtr->hwndSelf == GetDesktopWindow())
2081     {
2082         /* can't change anything on the desktop window */
2083         WIN_ReleasePtr( wndPtr );
2084         SetLastError( ERROR_ACCESS_DENIED );
2085         return 0;
2086     }
2087
2088     /* first some special cases */
2089     switch( offset )
2090     {
2091     case GWL_STYLE:
2092     case GWL_EXSTYLE:
2093         style.styleOld =
2094             offset == GWL_STYLE ? wndPtr->dwStyle : wndPtr->dwExStyle;
2095         style.styleNew = newval;
2096         WIN_ReleasePtr( wndPtr );
2097         SendMessageW( hwnd, WM_STYLECHANGING, offset, (LPARAM)&style );
2098         if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2099         newval = style.styleNew;
2100         break;
2101     case GWL_HWNDPARENT:
2102         if (wndPtr->parent == GetDesktopWindow())
2103         {
2104             WIN_ReleasePtr( wndPtr );
2105             return (LONG)WIN_SetOwner( hwnd, (HWND)newval );
2106         }
2107         else
2108         {
2109             WIN_ReleasePtr( wndPtr );
2110             return (LONG)SetParent( hwnd, (HWND)newval );
2111         }
2112     case GWL_WNDPROC:
2113         retval = (LONG)WINPROC_GetProc( wndPtr->winproc, type );
2114         WINPROC_SetProc( &wndPtr->winproc, (WNDPROC)newval, type, WIN_PROC_WINDOW );
2115         WIN_ReleasePtr( wndPtr );
2116         return retval;
2117     case GWL_ID:
2118     case GWL_HINSTANCE:
2119     case GWL_USERDATA:
2120         break;
2121     case DWL_DLGPROC:
2122         if ((wndPtr->cbWndExtra + sizeof(LONG) >= DWL_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
2123         {
2124             WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWL_DLGPROC);
2125             retval = (LONG)WINPROC_GetProc( *ptr, type );
2126             WINPROC_SetProc( ptr, (WNDPROC)newval, type, WIN_PROC_WINDOW );
2127             WIN_ReleasePtr( wndPtr );
2128             return retval;
2129         }
2130         /* fall through */
2131     default:
2132         if (offset < 0 || offset > (int)(wndPtr->cbWndExtra - sizeof(LONG)))
2133         {
2134             WARN("Invalid offset %d\n", offset );
2135             WIN_ReleasePtr( wndPtr );
2136             SetLastError( ERROR_INVALID_INDEX );
2137             return 0;
2138         }
2139         else
2140         {
2141             LONG *ptr = (LONG *)((char *)wndPtr->wExtra + offset);
2142             if (*ptr == newval)  /* already set to the same value */
2143             {
2144                 WIN_ReleasePtr( wndPtr );
2145                 return newval;
2146             }
2147         }
2148         break;
2149     }
2150
2151     SERVER_START_REQ( set_window_info )
2152     {
2153         req->handle = hwnd;
2154         req->extra_offset = -1;
2155         switch(offset)
2156         {
2157         case GWL_STYLE:
2158             req->flags = SET_WIN_STYLE;
2159             req->style = newval;
2160             break;
2161         case GWL_EXSTYLE:
2162             req->flags = SET_WIN_EXSTYLE;
2163             req->ex_style = newval;
2164             break;
2165         case GWL_ID:
2166             req->flags = SET_WIN_ID;
2167             req->id = newval;
2168             break;
2169         case GWL_HINSTANCE:
2170             req->flags = SET_WIN_INSTANCE;
2171             req->instance = (void *)newval;
2172             break;
2173         case GWL_USERDATA:
2174             req->flags = SET_WIN_USERDATA;
2175             req->user_data = (void *)newval;
2176             break;
2177         default:
2178             req->flags = SET_WIN_EXTRA;
2179             req->extra_offset = offset;
2180             req->extra_size = sizeof(newval);
2181             memcpy( &req->extra_value, &newval, sizeof(newval) );
2182         }
2183         if ((ok = !wine_server_call_err( req )))
2184         {
2185             switch(offset)
2186             {
2187             case GWL_STYLE:
2188                 wndPtr->dwStyle = newval;
2189                 retval = reply->old_style;
2190                 break;
2191             case GWL_EXSTYLE:
2192                 wndPtr->dwExStyle = newval;
2193                 retval = reply->old_ex_style;
2194                 break;
2195             case GWL_ID:
2196                 wndPtr->wIDmenu = newval;
2197                 retval = reply->old_id;
2198                 break;
2199             case GWL_HINSTANCE:
2200                 wndPtr->hInstance = (HINSTANCE)newval;
2201                 retval = (ULONG_PTR)reply->old_instance;
2202                 break;
2203             case GWL_USERDATA:
2204                 wndPtr->userdata = newval;
2205                 retval = (ULONG_PTR)reply->old_user_data;
2206                 break;
2207             default:
2208                 {
2209                     void *ptr = (char *)wndPtr->wExtra + offset;
2210                     memcpy( &retval, ptr, sizeof(retval) );
2211                     memcpy( ptr, &newval, sizeof(newval) );
2212                 }
2213                 break;
2214             }
2215         }
2216     }
2217     SERVER_END_REQ;
2218     WIN_ReleasePtr( wndPtr );
2219
2220     if (!ok) return 0;
2221
2222     if (offset == GWL_STYLE && USER_Driver.pSetWindowStyle)
2223         USER_Driver.pSetWindowStyle( hwnd, retval );
2224
2225     if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2226         SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2227
2228     return retval;
2229 }
2230
2231
2232 /**********************************************************************
2233  *              GetWindowLong (USER.135)
2234  */
2235 LONG WINAPI GetWindowLong16( HWND16 hwnd, INT16 offset )
2236 {
2237     return WIN_GetWindowLong( WIN_Handle32(hwnd), offset, WIN_PROC_16 );
2238 }
2239
2240
2241 /**********************************************************************
2242  *              GetWindowLongA (USER32.@)
2243  */
2244 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2245 {
2246     return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32A );
2247 }
2248
2249
2250 /**********************************************************************
2251  *              GetWindowLongW (USER32.@)
2252  */
2253 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2254 {
2255     return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32W );
2256 }
2257
2258
2259 /**********************************************************************
2260  *              SetWindowLong (USER.136)
2261  */
2262 LONG WINAPI SetWindowLong16( HWND16 hwnd, INT16 offset, LONG newval )
2263 {
2264     return WIN_SetWindowLong( WIN_Handle32(hwnd), offset, newval, WIN_PROC_16 );
2265 }
2266
2267
2268 /**********************************************************************
2269  *              SetWindowLongA (USER32.@)
2270  */
2271 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2272 {
2273     return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32A );
2274 }
2275
2276
2277 /**********************************************************************
2278  *              SetWindowLongW (USER32.@) Set window attribute
2279  *
2280  * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2281  * value in a window's extra memory.
2282  *
2283  * The _hwnd_ parameter specifies the window.  is the handle to a
2284  * window that has extra memory. The _newval_ parameter contains the
2285  * new attribute or extra memory value.  If positive, the _offset_
2286  * parameter is the byte-addressed location in the window's extra
2287  * memory to set.  If negative, _offset_ specifies the window
2288  * attribute to set, and should be one of the following values:
2289  *
2290  * GWL_EXSTYLE      The window's extended window style
2291  *
2292  * GWL_STYLE        The window's window style.
2293  *
2294  * GWL_WNDPROC      Pointer to the window's window procedure.
2295  *
2296  * GWL_HINSTANCE    The window's pplication instance handle.
2297  *
2298  * GWL_ID           The window's identifier.
2299  *
2300  * GWL_USERDATA     The window's user-specified data.
2301  *
2302  * If the window is a dialog box, the _offset_ parameter can be one of
2303  * the following values:
2304  *
2305  * DWL_DLGPROC      The address of the window's dialog box procedure.
2306  *
2307  * DWL_MSGRESULT    The return value of a message
2308  *                  that the dialog box procedure processed.
2309  *
2310  * DWL_USER         Application specific information.
2311  *
2312  * RETURNS
2313  *
2314  * If successful, returns the previous value located at _offset_. Otherwise,
2315  * returns 0.
2316  *
2317  * NOTES
2318  *
2319  * Extra memory for a window class is specified by a nonzero cbWndExtra
2320  * parameter of the WNDCLASS structure passed to RegisterClass() at the
2321  * time of class creation.
2322  *
2323  * Using GWL_WNDPROC to set a new window procedure effectively creates
2324  * a window subclass. Use CallWindowProc() in the new windows procedure
2325  * to pass messages to the superclass's window procedure.
2326  *
2327  * The user data is reserved for use by the application which created
2328  * the window.
2329  *
2330  * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2331  * instead, call the EnableWindow() function to change the window's
2332  * disabled state.
2333  *
2334  * Do not use GWL_HWNDPARENT to reset the window's parent, use
2335  * SetParent() instead.
2336  *
2337  * Win95:
2338  * When offset is GWL_STYLE and the calling app's ver is 4.0,
2339  * it sends WM_STYLECHANGING before changing the settings
2340  * and WM_STYLECHANGED afterwards.
2341  * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2342  */
2343 LONG WINAPI SetWindowLongW(
2344     HWND hwnd,  /* [in] window to alter */
2345     INT offset, /* [in] offset, in bytes, of location to alter */
2346     LONG newval /* [in] new value of location */
2347 ) {
2348     return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32W );
2349 }
2350
2351
2352 /*******************************************************************
2353  *              GetWindowTextA (USER32.@)
2354  */
2355 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2356 {
2357     WCHAR *buffer;
2358
2359     if (WIN_IsCurrentProcess( hwnd ))
2360         return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2361
2362     /* when window belongs to other process, don't send a message */
2363     if (nMaxCount <= 0) return 0;
2364     if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2365     get_server_window_text( hwnd, buffer, nMaxCount );
2366     if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2367         lpString[nMaxCount-1] = 0;
2368     HeapFree( GetProcessHeap(), 0, buffer );
2369     return strlen(lpString);
2370 }
2371
2372
2373 /*******************************************************************
2374  *              InternalGetWindowText (USER32.@)
2375  */
2376 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2377 {
2378     WND *win;
2379
2380     if (nMaxCount <= 0) return 0;
2381     if (!(win = WIN_GetPtr( hwnd ))) return 0;
2382     if (win != WND_OTHER_PROCESS)
2383     {
2384         if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2385         else lpString[0] = 0;
2386         WIN_ReleasePtr( win );
2387     }
2388     else
2389     {
2390         get_server_window_text( hwnd, lpString, nMaxCount );
2391     }
2392     return strlenW(lpString);
2393 }
2394
2395
2396 /*******************************************************************
2397  *              GetWindowTextW (USER32.@)
2398  */
2399 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2400 {
2401     if (WIN_IsCurrentProcess( hwnd ))
2402         return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2403
2404     /* when window belongs to other process, don't send a message */
2405     if (nMaxCount <= 0) return 0;
2406     get_server_window_text( hwnd, lpString, nMaxCount );
2407     return strlenW(lpString);
2408 }
2409
2410
2411 /*******************************************************************
2412  *              SetWindowText  (USER32.@)
2413  *              SetWindowTextA (USER32.@)
2414  */
2415 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2416 {
2417     if (is_broadcast(hwnd))
2418     {
2419         SetLastError( ERROR_INVALID_PARAMETER );
2420         return FALSE;
2421     }
2422     if (!WIN_IsCurrentProcess( hwnd ))
2423     {
2424         FIXME( "cannot set text %s of other process window %p\n", debugstr_a(lpString), hwnd );
2425         SetLastError( ERROR_ACCESS_DENIED );
2426         return FALSE;
2427     }
2428     return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2429 }
2430
2431
2432 /*******************************************************************
2433  *              SetWindowTextW (USER32.@)
2434  */
2435 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2436 {
2437     if (is_broadcast(hwnd))
2438     {
2439         SetLastError( ERROR_INVALID_PARAMETER );
2440         return FALSE;
2441     }
2442     if (!WIN_IsCurrentProcess( hwnd ))
2443     {
2444         FIXME( "cannot set text %s of other process window %p\n", debugstr_w(lpString), hwnd );
2445         SetLastError( ERROR_ACCESS_DENIED );
2446         return FALSE;
2447     }
2448     return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2449 }
2450
2451
2452 /*******************************************************************
2453  *              GetWindowTextLengthA (USER32.@)
2454  */
2455 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2456 {
2457     return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2458 }
2459
2460 /*******************************************************************
2461  *              GetWindowTextLengthW (USER32.@)
2462  */
2463 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2464 {
2465     return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2466 }
2467
2468
2469 /*******************************************************************
2470  *              IsWindow (USER32.@)
2471  */
2472 BOOL WINAPI IsWindow( HWND hwnd )
2473 {
2474     WND *ptr;
2475     BOOL ret;
2476
2477     if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2478
2479     if (ptr != WND_OTHER_PROCESS)
2480     {
2481         WIN_ReleasePtr( ptr );
2482         return TRUE;
2483     }
2484
2485     /* check other processes */
2486     SERVER_START_REQ( get_window_info )
2487     {
2488         req->handle = hwnd;
2489         ret = !wine_server_call_err( req );
2490     }
2491     SERVER_END_REQ;
2492     return ret;
2493 }
2494
2495
2496 /***********************************************************************
2497  *              GetWindowThreadProcessId (USER32.@)
2498  */
2499 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2500 {
2501     WND *ptr;
2502     DWORD tid = 0;
2503
2504     if (!(ptr = WIN_GetPtr( hwnd )))
2505     {
2506         SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2507         return 0;
2508     }
2509
2510     if (ptr != WND_OTHER_PROCESS)
2511     {
2512         /* got a valid window */
2513         tid = ptr->tid;
2514         if (process) *process = GetCurrentProcessId();
2515         WIN_ReleasePtr( ptr );
2516         return tid;
2517     }
2518
2519     /* check other processes */
2520     SERVER_START_REQ( get_window_info )
2521     {
2522         req->handle = hwnd;
2523         if (!wine_server_call_err( req ))
2524         {
2525             tid = (DWORD)reply->tid;
2526             if (process) *process = (DWORD)reply->pid;
2527         }
2528     }
2529     SERVER_END_REQ;
2530     return tid;
2531 }
2532
2533
2534 /*****************************************************************
2535  *              GetParent (USER32.@)
2536  */
2537 HWND WINAPI GetParent( HWND hwnd )
2538 {
2539     WND *wndPtr;
2540     HWND retvalue = 0;
2541
2542     if (!(wndPtr = WIN_GetPtr( hwnd )))
2543     {
2544         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2545         return 0;
2546     }
2547     if (wndPtr == WND_OTHER_PROCESS)
2548     {
2549         LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2550         if (style & (WS_POPUP | WS_CHILD))
2551         {
2552             SERVER_START_REQ( get_window_tree )
2553             {
2554                 req->handle = hwnd;
2555                 if (!wine_server_call_err( req ))
2556                 {
2557                     if (style & WS_POPUP) retvalue = reply->owner;
2558                     else if (style & WS_CHILD) retvalue = reply->parent;
2559                 }
2560             }
2561             SERVER_END_REQ;
2562         }
2563     }
2564     else
2565     {
2566         if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2567         else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2568         WIN_ReleasePtr( wndPtr );
2569     }
2570     return retvalue;
2571 }
2572
2573
2574 /*****************************************************************
2575  *              GetAncestor (USER32.@)
2576  */
2577 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2578 {
2579     WND *win;
2580     HWND *list, ret = 0;
2581
2582     switch(type)
2583     {
2584     case GA_PARENT:
2585         if (!(win = WIN_GetPtr( hwnd )))
2586         {
2587             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2588             return 0;
2589         }
2590         if (win != WND_OTHER_PROCESS)
2591         {
2592             ret = win->parent;
2593             WIN_ReleasePtr( win );
2594         }
2595         else /* need to query the server */
2596         {
2597             SERVER_START_REQ( get_window_tree )
2598             {
2599                 req->handle = hwnd;
2600                 if (!wine_server_call_err( req )) ret = reply->parent;
2601             }
2602             SERVER_END_REQ;
2603         }
2604         break;
2605
2606     case GA_ROOT:
2607         if (!(list = WIN_ListParents( hwnd ))) return 0;
2608
2609         if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd );  /* top-level window */
2610         else
2611         {
2612             int count = 2;
2613             while (list[count]) count++;
2614             ret = list[count - 2];  /* get the one before the desktop */
2615         }
2616         HeapFree( GetProcessHeap(), 0, list );
2617         break;
2618
2619     case GA_ROOTOWNER:
2620         if ((ret = WIN_GetFullHandle( hwnd )) == GetDesktopWindow()) return 0;
2621         for (;;)
2622         {
2623             HWND parent = GetParent( ret );
2624             if (!parent) break;
2625             ret = parent;
2626         }
2627         break;
2628     }
2629     return ret;
2630 }
2631
2632
2633 /*****************************************************************
2634  *              SetParent (USER32.@)
2635  */
2636 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2637 {
2638     WND *wndPtr;
2639     HWND retvalue, full_handle;
2640     BOOL was_visible;
2641
2642     if (is_broadcast(hwnd) || is_broadcast(parent))
2643     {
2644         SetLastError(ERROR_INVALID_PARAMETER);
2645         return 0;
2646     }
2647
2648     if (!parent) parent = GetDesktopWindow();
2649     else parent = WIN_GetFullHandle( parent );
2650
2651     if (!IsWindow( parent ))
2652     {
2653         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2654         return 0;
2655     }
2656
2657     if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2658         return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2659
2660     hwnd = full_handle;
2661
2662     if (USER_Driver.pSetParent)
2663         return USER_Driver.pSetParent( hwnd, parent );
2664
2665     /* Windows hides the window first, then shows it again
2666      * including the WM_SHOWWINDOW messages and all */
2667     was_visible = ShowWindow( hwnd, SW_HIDE );
2668
2669     if (!IsWindow( parent )) return 0;
2670     if (!(wndPtr = WIN_GetPtr(hwnd)) || wndPtr == WND_OTHER_PROCESS) return 0;
2671
2672     retvalue = wndPtr->parent;  /* old parent */
2673     if (parent != retvalue)
2674     {
2675         WIN_LinkWindow( hwnd, parent, HWND_TOP );
2676
2677         if (parent != GetDesktopWindow()) /* a child window */
2678         {
2679             if (!(wndPtr->dwStyle & WS_CHILD))
2680             {
2681                 HMENU menu = (HMENU)SetWindowLongW( hwnd, GWL_ID, 0 );
2682                 if (menu) DestroyMenu( menu );
2683             }
2684         }
2685     }
2686     WIN_ReleasePtr( wndPtr );
2687
2688     /* SetParent additionally needs to make hwnd the topmost window
2689        in the x-order and send the expected WM_WINDOWPOSCHANGING and
2690        WM_WINDOWPOSCHANGED notification messages.
2691     */
2692     SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0,
2693                   SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | (was_visible ? SWP_SHOWWINDOW : 0) );
2694     /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
2695      * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
2696     return retvalue;
2697 }
2698
2699
2700 /*******************************************************************
2701  *              IsChild (USER32.@)
2702  */
2703 BOOL WINAPI IsChild( HWND parent, HWND child )
2704 {
2705     HWND *list = WIN_ListParents( child );
2706     int i;
2707     BOOL ret;
2708
2709     if (!list) return FALSE;
2710     parent = WIN_GetFullHandle( parent );
2711     for (i = 0; list[i]; i++) if (list[i] == parent) break;
2712     ret = (list[i] != 0);
2713     HeapFree( GetProcessHeap(), 0, list );
2714     return ret;
2715 }
2716
2717
2718 /***********************************************************************
2719  *              IsWindowVisible (USER32.@)
2720  */
2721 BOOL WINAPI IsWindowVisible( HWND hwnd )
2722 {
2723     HWND *list;
2724     BOOL retval;
2725     int i;
2726
2727     if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2728     if (!(list = WIN_ListParents( hwnd ))) return TRUE;
2729     for (i = 0; list[i]; i++)
2730         if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2731     retval = !list[i];
2732     HeapFree( GetProcessHeap(), 0, list );
2733     return retval;
2734 }
2735
2736
2737 /***********************************************************************
2738  *           WIN_IsWindowDrawable
2739  *
2740  * hwnd is drawable when it is visible, all parents are not
2741  * minimized, and it is itself not minimized unless we are
2742  * trying to draw its default class icon.
2743  */
2744 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2745 {
2746     HWND *list;
2747     BOOL retval;
2748     int i;
2749     LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2750
2751     if (!(style & WS_VISIBLE)) return FALSE;
2752     if ((style & WS_MINIMIZE) && icon && GetClassLongA( hwnd, GCL_HICON ))  return FALSE;
2753
2754     if (!(list = WIN_ListParents( hwnd ))) return TRUE;
2755     for (i = 0; list[i]; i++)
2756         if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2757             break;
2758     retval = !list[i];
2759     HeapFree( GetProcessHeap(), 0, list );
2760     return retval;
2761 }
2762
2763
2764 /*******************************************************************
2765  *              GetTopWindow (USER32.@)
2766  */
2767 HWND WINAPI GetTopWindow( HWND hwnd )
2768 {
2769     if (!hwnd) hwnd = GetDesktopWindow();
2770     return GetWindow( hwnd, GW_CHILD );
2771 }
2772
2773
2774 /*******************************************************************
2775  *              GetWindow (USER32.@)
2776  */
2777 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2778 {
2779     HWND retval = 0;
2780
2781     if (rel == GW_OWNER)  /* this one may be available locally */
2782     {
2783         WND *wndPtr = WIN_GetPtr( hwnd );
2784         if (!wndPtr)
2785         {
2786             SetLastError( ERROR_INVALID_HANDLE );
2787             return 0;
2788         }
2789         if (wndPtr != WND_OTHER_PROCESS)
2790         {
2791             retval = wndPtr->owner;
2792             WIN_ReleasePtr( wndPtr );
2793             return retval;
2794         }
2795         /* else fall through to server call */
2796     }
2797
2798     SERVER_START_REQ( get_window_tree )
2799     {
2800         req->handle = hwnd;
2801         if (!wine_server_call_err( req ))
2802         {
2803             switch(rel)
2804             {
2805             case GW_HWNDFIRST:
2806                 retval = reply->first_sibling;
2807                 break;
2808             case GW_HWNDLAST:
2809                 retval = reply->last_sibling;
2810                 break;
2811             case GW_HWNDNEXT:
2812                 retval = reply->next_sibling;
2813                 break;
2814             case GW_HWNDPREV:
2815                 retval = reply->prev_sibling;
2816                 break;
2817             case GW_OWNER:
2818                 retval = reply->owner;
2819                 break;
2820             case GW_CHILD:
2821                 retval = reply->first_child;
2822                 break;
2823             }
2824         }
2825     }
2826     SERVER_END_REQ;
2827     return retval;
2828 }
2829
2830
2831 /***********************************************************************
2832  *           WIN_InternalShowOwnedPopups
2833  *
2834  * Internal version of ShowOwnedPopups; Wine functions should use this
2835  * to avoid interfering with application calls to ShowOwnedPopups
2836  * and to make sure the application can't prevent showing/hiding.
2837  *
2838  * Set unmanagedOnly to TRUE to show/hide unmanaged windows only.
2839  *
2840  */
2841
2842 BOOL WIN_InternalShowOwnedPopups( HWND owner, BOOL fShow, BOOL unmanagedOnly )
2843 {
2844     int count = 0;
2845     WND *pWnd;
2846     HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2847
2848     if (!win_array) return TRUE;
2849
2850     /*
2851      * Show windows Lowest first, Highest last to preserve Z-Order
2852      */
2853     while (win_array[count]) count++;
2854     while (--count >= 0)
2855     {
2856         if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2857         if (!(pWnd = WIN_FindWndPtr( win_array[count] ))) continue;
2858
2859         if (pWnd->dwStyle & WS_POPUP)
2860         {
2861             if (fShow)
2862             {
2863                 /* check in window was flagged for showing in previous WIN_InternalShowOwnedPopups call */
2864                 if (pWnd->flags & WIN_NEEDS_INTERNALSOP)
2865                 {
2866                     /*
2867                      * Call ShowWindow directly because an application can intercept WM_SHOWWINDOW messages
2868                      */
2869                     ShowWindow(pWnd->hwndSelf,SW_SHOW);
2870                     pWnd->flags &= ~WIN_NEEDS_INTERNALSOP; /* remove the flag */
2871                 }
2872             }
2873             else
2874             {
2875                 if ( IsWindowVisible(pWnd->hwndSelf) &&                   /* hide only if window is visible */
2876                      !( pWnd->flags & WIN_NEEDS_INTERNALSOP ) &&          /* don't hide if previous call already did it */
2877                      !( unmanagedOnly && (pWnd->dwExStyle & WS_EX_MANAGED) ) ) /* don't hide managed windows if unmanagedOnly is TRUE */
2878                 {
2879                     /*
2880                      * Call ShowWindow directly because an application can intercept WM_SHOWWINDOW messages
2881                      */
2882                     ShowWindow(pWnd->hwndSelf,SW_HIDE);
2883                     /* flag the window for showing on next WIN_InternalShowOwnedPopups call */
2884                     pWnd->flags |= WIN_NEEDS_INTERNALSOP;
2885                 }
2886             }
2887         }
2888         WIN_ReleaseWndPtr( pWnd );
2889     }
2890     HeapFree( GetProcessHeap(), 0, win_array );
2891
2892     return TRUE;
2893 }
2894
2895 /*******************************************************************
2896  *              ShowOwnedPopups (USER32.@)
2897  */
2898 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2899 {
2900     int count = 0;
2901     WND *pWnd;
2902     HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2903
2904     if (!win_array) return TRUE;
2905
2906     while (win_array[count]) count++;
2907     while (--count >= 0)
2908     {
2909         if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2910         if (!(pWnd = WIN_FindWndPtr( win_array[count] ))) continue;
2911
2912         if (pWnd->dwStyle & WS_POPUP)
2913         {
2914             if (fShow)
2915             {
2916                 if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2917                 {
2918                     /* In Windows, ShowOwnedPopups(TRUE) generates
2919                      * WM_SHOWWINDOW messages with SW_PARENTOPENING,
2920                      * regardless of the state of the owner
2921                      */
2922                     SendMessageA(pWnd->hwndSelf, WM_SHOWWINDOW, SW_SHOW, SW_PARENTOPENING);
2923                     pWnd->flags &= ~WIN_NEEDS_SHOW_OWNEDPOPUP;
2924                 }
2925             }
2926             else
2927             {
2928                 if (IsWindowVisible(pWnd->hwndSelf))
2929                 {
2930                     /* In Windows, ShowOwnedPopups(FALSE) generates
2931                      * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
2932                      * regardless of the state of the owner
2933                      */
2934                     SendMessageA(pWnd->hwndSelf, WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
2935                     pWnd->flags |= WIN_NEEDS_SHOW_OWNEDPOPUP;
2936                 }
2937             }
2938         }
2939         WIN_ReleaseWndPtr( pWnd );
2940     }
2941     HeapFree( GetProcessHeap(), 0, win_array );
2942     return TRUE;
2943 }
2944
2945
2946 /*******************************************************************
2947  *              GetLastActivePopup (USER32.@)
2948  */
2949 HWND WINAPI GetLastActivePopup( HWND hwnd )
2950 {
2951     HWND retval = hwnd;
2952
2953     SERVER_START_REQ( get_window_info )
2954     {
2955         req->handle = hwnd;
2956         if (!wine_server_call_err( req )) retval = reply->last_active;
2957     }
2958     SERVER_END_REQ;
2959     return retval;
2960 }
2961
2962
2963 /*******************************************************************
2964  *           WIN_ListParents
2965  *
2966  * Build an array of all parents of a given window, starting with
2967  * the immediate parent. The array must be freed with HeapFree.
2968  * Returns NULL if window is a top-level window.
2969  */
2970 HWND *WIN_ListParents( HWND hwnd )
2971 {
2972     WND *win;
2973     HWND current, *list;
2974     int pos = 0, size = 16, count = 0;
2975
2976     if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
2977
2978     current = hwnd;
2979     for (;;)
2980     {
2981         if (!(win = WIN_GetPtr( current ))) goto empty;
2982         if (win == WND_OTHER_PROCESS) break;  /* need to do it the hard way */
2983         list[pos] = win->parent;
2984         WIN_ReleasePtr( win );
2985         if (!(current = list[pos]))
2986         {
2987             if (!pos) goto empty;
2988             return list;
2989         }
2990         if (++pos == size - 1)
2991         {
2992             /* need to grow the list */
2993             HWND *new_list = HeapReAlloc( GetProcessHeap(), 0, list, (size+16) * sizeof(HWND) );
2994             if (!new_list) goto empty;
2995             list = new_list;
2996             size += 16;
2997         }
2998     }
2999
3000     /* at least one parent belongs to another process, have to query the server */
3001
3002     for (;;)
3003     {
3004         count = 0;
3005         SERVER_START_REQ( get_window_parents )
3006         {
3007             req->handle = hwnd;
3008             wine_server_set_reply( req, list, (size-1) * sizeof(HWND) );
3009             if (!wine_server_call( req )) count = reply->count;
3010         }
3011         SERVER_END_REQ;
3012         if (!count) goto empty;
3013         if (size > count)
3014         {
3015             list[count] = 0;
3016             return list;
3017         }
3018         HeapFree( GetProcessHeap(), 0, list );
3019         size = count + 1;
3020         if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
3021     }
3022
3023  empty:
3024     HeapFree( GetProcessHeap(), 0, list );
3025     return NULL;
3026 }
3027
3028
3029 /*******************************************************************
3030  *           WIN_ListChildren
3031  *
3032  * Build an array of the children of a given window. The array must be
3033  * freed with HeapFree. Returns NULL when no windows are found.
3034  */
3035 HWND *WIN_ListChildren( HWND hwnd )
3036 {
3037     return list_window_children( hwnd, 0, 0 );
3038 }
3039
3040
3041 /*******************************************************************
3042  *              EnumWindows (USER32.@)
3043  */
3044 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
3045 {
3046     HWND *list;
3047     BOOL ret = TRUE;
3048     int i, iWndsLocks;
3049
3050     /* We have to build a list of all windows first, to avoid */
3051     /* unpleasant side-effects, for instance if the callback */
3052     /* function changes the Z-order of the windows.          */
3053
3054     if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
3055
3056     /* Now call the callback function for every window */
3057
3058     iWndsLocks = WIN_SuspendWndsLock();
3059     for (i = 0; list[i]; i++)
3060     {
3061         /* Make sure that the window still exists */
3062         if (!IsWindow( list[i] )) continue;
3063         if (!(ret = lpEnumFunc( list[i], lParam ))) break;
3064     }
3065     WIN_RestoreWndsLock(iWndsLocks);
3066     HeapFree( GetProcessHeap(), 0, list );
3067     return ret;
3068 }
3069
3070
3071 /**********************************************************************
3072  *              EnumThreadWindows (USER32.@)
3073  */
3074 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
3075 {
3076     HWND *list;
3077     int i, iWndsLocks;
3078
3079     if (!(list = list_window_children( GetDesktopWindow(), 0, id ))) return TRUE;
3080
3081     /* Now call the callback function for every window */
3082
3083     iWndsLocks = WIN_SuspendWndsLock();
3084     for (i = 0; list[i]; i++)
3085         if (!func( list[i], lParam )) break;
3086     WIN_RestoreWndsLock(iWndsLocks);
3087     HeapFree( GetProcessHeap(), 0, list );
3088     return TRUE;
3089 }
3090
3091
3092 /**********************************************************************
3093  *           WIN_EnumChildWindows
3094  *
3095  * Helper function for EnumChildWindows().
3096  */
3097 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
3098 {
3099     HWND *childList;
3100     BOOL ret = FALSE;
3101
3102     for ( ; *list; list++)
3103     {
3104         /* Make sure that the window still exists */
3105         if (!IsWindow( *list )) continue;
3106         /* skip owned windows */
3107         if (GetWindow( *list, GW_OWNER )) continue;
3108         /* Build children list first */
3109         childList = WIN_ListChildren( *list );
3110
3111         ret = func( *list, lParam );
3112
3113         if (childList)
3114         {
3115             if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
3116             HeapFree( GetProcessHeap(), 0, childList );
3117         }
3118         if (!ret) return FALSE;
3119     }
3120     return TRUE;
3121 }
3122
3123
3124 /**********************************************************************
3125  *              EnumChildWindows (USER32.@)
3126  */
3127 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
3128 {
3129     HWND *list;
3130     int iWndsLocks;
3131
3132     if (!(list = WIN_ListChildren( parent ))) return FALSE;
3133     iWndsLocks = WIN_SuspendWndsLock();
3134     WIN_EnumChildWindows( list, func, lParam );
3135     WIN_RestoreWndsLock(iWndsLocks);
3136     HeapFree( GetProcessHeap(), 0, list );
3137     return TRUE;
3138 }
3139
3140
3141 /*******************************************************************
3142  *              AnyPopup (USER.52)
3143  */
3144 BOOL16 WINAPI AnyPopup16(void)
3145 {
3146     return AnyPopup();
3147 }
3148
3149
3150 /*******************************************************************
3151  *              AnyPopup (USER32.@)
3152  */
3153 BOOL WINAPI AnyPopup(void)
3154 {
3155     int i;
3156     BOOL retvalue;
3157     HWND *list = WIN_ListChildren( GetDesktopWindow() );
3158
3159     if (!list) return FALSE;
3160     for (i = 0; list[i]; i++)
3161     {
3162         if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
3163     }
3164     retvalue = (list[i] != 0);
3165     HeapFree( GetProcessHeap(), 0, list );
3166     return retvalue;
3167 }
3168
3169
3170 /*******************************************************************
3171  *              FlashWindow (USER32.@)
3172  */
3173 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3174 {
3175     WND *wndPtr = WIN_FindWndPtr(hWnd);
3176
3177     TRACE("%p\n", hWnd);
3178
3179     if (!wndPtr) return FALSE;
3180     hWnd = wndPtr->hwndSelf;  /* make it a full handle */
3181
3182     if (wndPtr->dwStyle & WS_MINIMIZE)
3183     {
3184         if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
3185         {
3186             HDC hDC = GetDC(hWnd);
3187
3188             if (!SendMessageW( hWnd, WM_ERASEBKGND, (WPARAM)hDC, 0 ))
3189                 wndPtr->flags |= WIN_NEEDS_ERASEBKGND;
3190
3191             ReleaseDC( hWnd, hDC );
3192             wndPtr->flags |= WIN_NCACTIVATED;
3193         }
3194         else
3195         {
3196             RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
3197             wndPtr->flags &= ~WIN_NCACTIVATED;
3198         }
3199         WIN_ReleaseWndPtr(wndPtr);
3200         return TRUE;
3201     }
3202     else
3203     {
3204         WPARAM16 wparam;
3205         if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3206         else wparam = (hWnd == GetForegroundWindow());
3207
3208         WIN_ReleaseWndPtr(wndPtr);
3209         SendMessageW( hWnd, WM_NCACTIVATE, wparam, (LPARAM)0 );
3210         return wparam;
3211     }
3212 }
3213
3214 /*******************************************************************
3215  *              FlashWindowEx (USER32.@)
3216  */
3217 BOOL WINAPI FlashWindowEx( PFLASHWINFO pfwi )
3218 {
3219     FIXME("%p\n", pfwi);
3220     return TRUE;
3221 }
3222
3223 /*******************************************************************
3224  *              GetWindowContextHelpId (USER32.@)
3225  */
3226 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3227 {
3228     DWORD retval;
3229     WND *wnd = WIN_FindWndPtr( hwnd );
3230     if (!wnd) return 0;
3231     retval = wnd->helpContext;
3232     WIN_ReleaseWndPtr(wnd);
3233     return retval;
3234 }
3235
3236
3237 /*******************************************************************
3238  *              SetWindowContextHelpId (USER32.@)
3239  */
3240 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3241 {
3242     WND *wnd = WIN_FindWndPtr( hwnd );
3243     if (!wnd) return FALSE;
3244     wnd->helpContext = id;
3245     WIN_ReleaseWndPtr(wnd);
3246     return TRUE;
3247 }
3248
3249
3250 /*******************************************************************
3251  *              DragDetect (USER32.@)
3252  */
3253 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3254 {
3255     MSG msg;
3256     RECT rect;
3257
3258     rect.left = pt.x - wDragWidth;
3259     rect.right = pt.x + wDragWidth;
3260
3261     rect.top = pt.y - wDragHeight;
3262     rect.bottom = pt.y + wDragHeight;
3263
3264     SetCapture(hWnd);
3265
3266     while(1)
3267     {
3268         while(PeekMessageA(&msg ,0 ,WM_MOUSEFIRST ,WM_MOUSELAST ,PM_REMOVE))
3269         {
3270             if( msg.message == WM_LBUTTONUP )
3271             {
3272                 ReleaseCapture();
3273                 return 0;
3274             }
3275             if( msg.message == WM_MOUSEMOVE )
3276             {
3277                 POINT tmp;
3278                 tmp.x = LOWORD(msg.lParam);
3279                 tmp.y = HIWORD(msg.lParam);
3280                 if( !PtInRect( &rect, tmp ))
3281                 {
3282                     ReleaseCapture();
3283                     return 1;
3284                 }
3285             }
3286         }
3287         WaitMessage();
3288     }
3289     return 0;
3290 }
3291
3292 /******************************************************************************
3293  *              GetWindowModuleFileNameA (USER32.@)
3294  */
3295 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR lpszFileName, UINT cchFileNameMax)
3296 {
3297     FIXME("GetWindowModuleFileNameA(hwnd %p, lpszFileName %p, cchFileNameMax %u) stub!\n",
3298           hwnd, lpszFileName, cchFileNameMax);
3299     return 0;
3300 }
3301
3302 /******************************************************************************
3303  *              GetWindowModuleFileNameW (USER32.@)
3304  */
3305 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR lpszFileName, UINT cchFileNameMax)
3306 {
3307     FIXME("GetWindowModuleFileNameW(hwnd %p, lpszFileName %p, cchFileNameMax %u) stub!\n",
3308           hwnd, lpszFileName, cchFileNameMax);
3309     return 0;
3310 }
3311
3312 /******************************************************************************
3313  *              GetWindowInfo (USER32.@)
3314  * hwnd: in
3315  * pwi:  out.
3316  * MS Documentation mentions that pwi->cbSize must be set to SIZEOF(WINDOWINFO)
3317  *    this may be because this structure changed over time. If this is the
3318  *    the case, then please: FIXME.
3319  *    Using the structure described in MSDN for 98/ME/NT(4.0 SP3)/2000/XP.
3320  */
3321 BOOL WINAPI GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3322 {
3323     if (!pwi) return FALSE;
3324     if (pwi->cbSize != sizeof(WINDOWINFO))
3325     {
3326         FIXME("windowinfo->cbSize != sizeof(WINDOWINFO). Please report\n");
3327         return FALSE;
3328     }
3329     if (!IsWindow(hwnd)) return FALSE;
3330
3331     GetWindowRect(hwnd, &pwi->rcWindow);
3332     GetClientRect(hwnd, &pwi->rcClient);
3333     /* translate to screen coordinates */
3334     MapWindowPoints(hwnd, 0, (LPPOINT)&pwi->rcClient, 2);
3335
3336     pwi->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
3337     pwi->dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3338     pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3339
3340     pwi->cxWindowBorders = pwi->rcClient.left - pwi->rcWindow.left;
3341     pwi->cyWindowBorders = pwi->rcWindow.bottom - pwi->rcClient.bottom;
3342
3343     pwi->atomWindowType = GetClassLongW( hwnd, GCW_ATOM );
3344     pwi->wCreatorVersion = 0x0400;
3345
3346     return TRUE;
3347 }