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