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