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