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