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