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