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