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