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