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