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