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