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