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