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