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