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