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