user32: Implemented UpdateLayeredWindow and UpdateLayeredWindowIndirect.
[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))) return 0;
1235     if (!(wndPtr->flags & WIN_NEED_SIZE))
1236     {
1237         rect = wndPtr->rectClient;
1238         WIN_ReleasePtr( wndPtr );
1239         SendMessageW( hwnd, WM_SIZE, SIZE_RESTORED,
1240                       MAKELONG(rect.right-rect.left, rect.bottom-rect.top));
1241         SendMessageW( hwnd, WM_MOVE, 0, MAKELONG( rect.left, rect.top ) );
1242     }
1243     else WIN_ReleasePtr( wndPtr );
1244
1245     /* Show the window, maximizing or minimizing if needed */
1246
1247     style = WIN_SetStyle( hwnd, 0, WS_MAXIMIZE | WS_MINIMIZE );
1248     if (style & (WS_MINIMIZE | WS_MAXIMIZE))
1249     {
1250         RECT newPos;
1251         UINT swFlag = (style & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;
1252
1253         swFlag = WINPOS_MinMaximize( hwnd, swFlag, &newPos );
1254         swFlag |= SWP_FRAMECHANGED; /* Frame always gets changed */
1255         if (!(style & WS_VISIBLE) || (style & WS_CHILD) || GetActiveWindow()) swFlag |= SWP_NOACTIVATE;
1256         SetWindowPos( hwnd, 0, newPos.left, newPos.top, newPos.right - newPos.left,
1257                       newPos.bottom - newPos.top, swFlag );
1258     }
1259
1260     /* Notify the parent window only */
1261
1262     send_parent_notify( hwnd, WM_CREATE );
1263     if (!IsWindow( hwnd )) return 0;
1264
1265     if (cs->style & WS_VISIBLE)
1266     {
1267         if (cs->style & WS_MAXIMIZE)
1268             sw = SW_SHOW;
1269         else if (cs->style & WS_MINIMIZE)
1270             sw = SW_SHOWMINIMIZED;
1271
1272         ShowWindow( hwnd, sw );
1273         if (cs->dwExStyle & WS_EX_MDICHILD)
1274         {
1275             SendMessageW(cs->hwndParent, WM_MDIREFRESHMENU, 0, 0);
1276             /* ShowWindow won't activate child windows */
1277             SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE );
1278         }
1279     }
1280
1281     /* Call WH_SHELL hook */
1282
1283     if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1284         HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0, TRUE );
1285
1286     TRACE("created window %p\n", hwnd);
1287     return hwnd;
1288
1289 failed:
1290     WIN_DestroyWindow( hwnd );
1291     return 0;
1292 }
1293
1294
1295 /***********************************************************************
1296  *              CreateWindow (USER.41)
1297  */
1298 HWND16 WINAPI CreateWindow16( LPCSTR className, LPCSTR windowName,
1299                               DWORD style, INT16 x, INT16 y, INT16 width,
1300                               INT16 height, HWND16 parent, HMENU16 menu,
1301                               HINSTANCE16 instance, LPVOID data )
1302 {
1303     return CreateWindowEx16( 0, className, windowName, style,
1304                              x, y, width, height, parent, menu, instance, data );
1305 }
1306
1307
1308 /***********************************************************************
1309  *              CreateWindowEx (USER.452)
1310  */
1311 HWND16 WINAPI CreateWindowEx16( DWORD exStyle, LPCSTR className,
1312                                 LPCSTR windowName, DWORD style, INT16 x,
1313                                 INT16 y, INT16 width, INT16 height,
1314                                 HWND16 parent, HMENU16 menu,
1315                                 HINSTANCE16 instance, LPVOID data )
1316 {
1317     CREATESTRUCTA cs;
1318     char buffer[256];
1319
1320     /* Fix the coordinates */
1321
1322     cs.x  = (x == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)x;
1323     cs.y  = (y == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)y;
1324     cs.cx = (width == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)width;
1325     cs.cy = (height == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)height;
1326
1327     /* Create the window */
1328
1329     cs.lpCreateParams = data;
1330     cs.hInstance      = HINSTANCE_32(instance);
1331     cs.hMenu          = HMENU_32(menu);
1332     cs.hwndParent     = WIN_Handle32( parent );
1333     cs.style          = style;
1334     cs.lpszName       = windowName;
1335     cs.lpszClass      = className;
1336     cs.dwExStyle      = exStyle;
1337
1338     if (!IS_INTRESOURCE(className))
1339     {
1340         WCHAR bufferW[256];
1341
1342         if (!MultiByteToWideChar( CP_ACP, 0, className, -1, bufferW, sizeof(bufferW)/sizeof(WCHAR) ))
1343             return 0;
1344         return HWND_16( WIN_CreateWindowEx( &cs, bufferW, 0 ));
1345     }
1346     else
1347     {
1348         if (!GlobalGetAtomNameA( LOWORD(className), buffer, sizeof(buffer) ))
1349         {
1350             ERR( "bad atom %x\n", LOWORD(className));
1351             return 0;
1352         }
1353         cs.lpszClass = buffer;
1354         return HWND_16( WIN_CreateWindowEx( &cs, (LPCWSTR)className, 0 ));
1355     }
1356 }
1357
1358
1359 /***********************************************************************
1360  *              CreateWindowExA (USER32.@)
1361  */
1362 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1363                                  LPCSTR windowName, DWORD style, INT x,
1364                                  INT y, INT width, INT height,
1365                                  HWND parent, HMENU menu,
1366                                  HINSTANCE instance, LPVOID data )
1367 {
1368     CREATESTRUCTA cs;
1369
1370     cs.lpCreateParams = data;
1371     cs.hInstance      = instance;
1372     cs.hMenu          = menu;
1373     cs.hwndParent     = parent;
1374     cs.x              = x;
1375     cs.y              = y;
1376     cs.cx             = width;
1377     cs.cy             = height;
1378     cs.style          = style;
1379     cs.lpszName       = windowName;
1380     cs.lpszClass      = className;
1381     cs.dwExStyle      = exStyle;
1382
1383     if (!IS_INTRESOURCE(className))
1384     {
1385         WCHAR bufferW[256];
1386         if (!MultiByteToWideChar( CP_ACP, 0, className, -1, bufferW, sizeof(bufferW)/sizeof(WCHAR) ))
1387             return 0;
1388         return WIN_CreateWindowEx( &cs, bufferW, WIN_ISWIN32 );
1389     }
1390     return WIN_CreateWindowEx( &cs, (LPCWSTR)className, WIN_ISWIN32 );
1391 }
1392
1393
1394 /***********************************************************************
1395  *              CreateWindowExW (USER32.@)
1396  */
1397 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1398                                  LPCWSTR windowName, DWORD style, INT x,
1399                                  INT y, INT width, INT height,
1400                                  HWND parent, HMENU menu,
1401                                  HINSTANCE instance, LPVOID data )
1402 {
1403     CREATESTRUCTW cs;
1404
1405     cs.lpCreateParams = data;
1406     cs.hInstance      = instance;
1407     cs.hMenu          = menu;
1408     cs.hwndParent     = parent;
1409     cs.x              = x;
1410     cs.y              = y;
1411     cs.cx             = width;
1412     cs.cy             = height;
1413     cs.style          = style;
1414     cs.lpszName       = windowName;
1415     cs.lpszClass      = className;
1416     cs.dwExStyle      = exStyle;
1417
1418     /* Note: we rely on the fact that CREATESTRUCTA and */
1419     /* CREATESTRUCTW have the same layout. */
1420     return WIN_CreateWindowEx( (CREATESTRUCTA *)&cs, className, WIN_ISWIN32 | WIN_ISUNICODE );
1421 }
1422
1423
1424 /***********************************************************************
1425  *           WIN_SendDestroyMsg
1426  */
1427 static void WIN_SendDestroyMsg( HWND hwnd )
1428 {
1429     GUITHREADINFO info;
1430
1431     if (GetGUIThreadInfo( GetCurrentThreadId(), &info ))
1432     {
1433         if (hwnd == info.hwndCaret) DestroyCaret();
1434         if (hwnd == info.hwndActive) WINPOS_ActivateOtherWindow( hwnd );
1435     }
1436
1437     /*
1438      * Send the WM_DESTROY to the window.
1439      */
1440     SendMessageW( hwnd, WM_DESTROY, 0, 0);
1441
1442     /*
1443      * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1444      * make sure that the window still exists when we come back.
1445      */
1446     if (IsWindow(hwnd))
1447     {
1448         HWND* pWndArray;
1449         int i;
1450
1451         if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1452
1453         for (i = 0; pWndArray[i]; i++)
1454         {
1455             if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1456         }
1457         HeapFree( GetProcessHeap(), 0, pWndArray );
1458     }
1459     else
1460       WARN("\tdestroyed itself while in WM_DESTROY!\n");
1461 }
1462
1463
1464 /***********************************************************************
1465  *              DestroyWindow (USER32.@)
1466  */
1467 BOOL WINAPI DestroyWindow( HWND hwnd )
1468 {
1469     BOOL is_child;
1470
1471     if (!(hwnd = WIN_IsCurrentThread( hwnd )) || is_desktop_window( hwnd ))
1472     {
1473         SetLastError( ERROR_ACCESS_DENIED );
1474         return FALSE;
1475     }
1476
1477     TRACE("(%p)\n", hwnd);
1478
1479       /* Call hooks */
1480
1481     if (HOOK_CallHooks( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0, TRUE )) return FALSE;
1482
1483     if (MENU_IsMenuActive() == hwnd)
1484         EndMenu();
1485
1486     is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;
1487
1488     if (is_child)
1489     {
1490         if (!USER_IsExitingThread( GetCurrentThreadId() ))
1491             send_parent_notify( hwnd, WM_DESTROY );
1492     }
1493     else if (!GetWindow( hwnd, GW_OWNER ))
1494     {
1495         HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
1496         /* FIXME: clean up palette - see "Internals" p.352 */
1497     }
1498
1499     if (!IsWindow(hwnd)) return TRUE;
1500
1501       /* Hide the window */
1502     if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)
1503     {
1504         /* Only child windows receive WM_SHOWWINDOW in DestroyWindow() */
1505         if (is_child)
1506             ShowWindow( hwnd, SW_HIDE );
1507         else
1508             SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE |
1509                           SWP_NOZORDER | SWP_NOACTIVATE | SWP_HIDEWINDOW );
1510     }
1511
1512     if (!IsWindow(hwnd)) return TRUE;
1513
1514       /* Recursively destroy owned windows */
1515
1516     if (!is_child)
1517     {
1518         for (;;)
1519         {
1520             int i, got_one = 0;
1521             HWND *list = WIN_ListChildren( GetDesktopWindow() );
1522             if (list)
1523             {
1524                 for (i = 0; list[i]; i++)
1525                 {
1526                     if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1527                     if (WIN_IsCurrentThread( list[i] ))
1528                     {
1529                         DestroyWindow( list[i] );
1530                         got_one = 1;
1531                         continue;
1532                     }
1533                     WIN_SetOwner( list[i], 0 );
1534                 }
1535                 HeapFree( GetProcessHeap(), 0, list );
1536             }
1537             if (!got_one) break;
1538         }
1539     }
1540
1541       /* Send destroy messages */
1542
1543     WIN_SendDestroyMsg( hwnd );
1544     if (!IsWindow( hwnd )) return TRUE;
1545
1546     if (GetClipboardOwner() == hwnd)
1547         CLIPBOARD_ReleaseOwner();
1548
1549       /* Destroy the window storage */
1550
1551     WIN_DestroyWindow( hwnd );
1552     return TRUE;
1553 }
1554
1555
1556 /***********************************************************************
1557  *              CloseWindow (USER32.@)
1558  */
1559 BOOL WINAPI CloseWindow( HWND hwnd )
1560 {
1561     if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1562     ShowWindow( hwnd, SW_MINIMIZE );
1563     return TRUE;
1564 }
1565
1566
1567 /***********************************************************************
1568  *              OpenIcon (USER32.@)
1569  */
1570 BOOL WINAPI OpenIcon( HWND hwnd )
1571 {
1572     if (!IsIconic( hwnd )) return FALSE;
1573     ShowWindow( hwnd, SW_SHOWNORMAL );
1574     return TRUE;
1575 }
1576
1577
1578 /***********************************************************************
1579  *              FindWindowExW (USER32.@)
1580  */
1581 HWND WINAPI FindWindowExW( HWND parent, HWND child, LPCWSTR className, LPCWSTR title )
1582 {
1583     HWND *list = NULL;
1584     HWND retvalue = 0;
1585     int i = 0, len = 0;
1586     WCHAR *buffer = NULL;
1587
1588     if (!parent && child) parent = GetDesktopWindow();
1589     else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
1590
1591     if (title)
1592     {
1593         len = strlenW(title) + 1;  /* one extra char to check for chars beyond the end */
1594         if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1595     }
1596
1597     if (!(list = list_window_children( 0, parent, className, 0 ))) goto done;
1598
1599     if (child)
1600     {
1601         child = WIN_GetFullHandle( child );
1602         while (list[i] && list[i] != child) i++;
1603         if (!list[i]) goto done;
1604         i++;  /* start from next window */
1605     }
1606
1607     if (title)
1608     {
1609         while (list[i])
1610         {
1611             if (GetWindowTextW( list[i], buffer, len + 1 ) && !strcmpiW( buffer, title )) break;
1612             i++;
1613         }
1614     }
1615     retvalue = list[i];
1616
1617  done:
1618     HeapFree( GetProcessHeap(), 0, list );
1619     HeapFree( GetProcessHeap(), 0, buffer );
1620     return retvalue;
1621 }
1622
1623
1624
1625 /***********************************************************************
1626  *              FindWindowA (USER32.@)
1627  */
1628 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1629 {
1630     HWND ret = FindWindowExA( 0, 0, className, title );
1631     if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1632     return ret;
1633 }
1634
1635
1636 /***********************************************************************
1637  *              FindWindowExA (USER32.@)
1638  */
1639 HWND WINAPI FindWindowExA( HWND parent, HWND child, LPCSTR className, LPCSTR title )
1640 {
1641     LPWSTR titleW = NULL;
1642     HWND hwnd = 0;
1643
1644     if (title)
1645     {
1646         DWORD len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
1647         if (!(titleW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
1648         MultiByteToWideChar( CP_ACP, 0, title, -1, titleW, len );
1649     }
1650
1651     if (!IS_INTRESOURCE(className))
1652     {
1653         WCHAR classW[256];
1654         if (MultiByteToWideChar( CP_ACP, 0, className, -1, classW, sizeof(classW)/sizeof(WCHAR) ))
1655             hwnd = FindWindowExW( parent, child, classW, titleW );
1656     }
1657     else
1658     {
1659         hwnd = FindWindowExW( parent, child, (LPCWSTR)className, titleW );
1660     }
1661
1662     HeapFree( GetProcessHeap(), 0, titleW );
1663     return hwnd;
1664 }
1665
1666
1667 /***********************************************************************
1668  *              FindWindowW (USER32.@)
1669  */
1670 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
1671 {
1672     return FindWindowExW( 0, 0, className, title );
1673 }
1674
1675
1676 /**********************************************************************
1677  *              GetDesktopWindow (USER32.@)
1678  */
1679 HWND WINAPI GetDesktopWindow(void)
1680 {
1681     struct user_thread_info *thread_info = get_user_thread_info();
1682
1683     if (thread_info->top_window) return thread_info->top_window;
1684
1685     SERVER_START_REQ( get_desktop_window )
1686     {
1687         req->force = 0;
1688         if (!wine_server_call( req ))
1689         {
1690             thread_info->top_window = reply->top_window;
1691             thread_info->msg_window = reply->msg_window;
1692         }
1693     }
1694     SERVER_END_REQ;
1695
1696     if (!thread_info->top_window)
1697     {
1698         USEROBJECTFLAGS flags;
1699         if (!GetUserObjectInformationW( GetProcessWindowStation(), UOI_FLAGS, &flags,
1700                                         sizeof(flags), NULL ) || (flags.dwFlags & WSF_VISIBLE))
1701         {
1702             static const WCHAR command_line[] = {'\\','e','x','p','l','o','r','e','r','.','e','x','e',' ','/','d','e','s','k','t','o','p',0};
1703             STARTUPINFOW si;
1704             PROCESS_INFORMATION pi;
1705             WCHAR cmdline[MAX_PATH + sizeof(command_line)/sizeof(WCHAR)];
1706
1707             memset( &si, 0, sizeof(si) );
1708             si.cb = sizeof(si);
1709             si.dwFlags = STARTF_USESTDHANDLES;
1710             si.hStdInput  = 0;
1711             si.hStdOutput = 0;
1712             si.hStdError  = GetStdHandle( STD_ERROR_HANDLE );
1713
1714             GetSystemDirectoryW( cmdline, MAX_PATH );
1715             lstrcatW( cmdline, command_line );
1716             if (CreateProcessW( NULL, cmdline, NULL, NULL, FALSE, DETACHED_PROCESS,
1717                                 NULL, NULL, &si, &pi ))
1718             {
1719                 TRACE( "started explorer pid %04x tid %04x\n", pi.dwProcessId, pi.dwThreadId );
1720                 WaitForInputIdle( pi.hProcess, 10000 );
1721                 CloseHandle( pi.hThread );
1722                 CloseHandle( pi.hProcess );
1723             }
1724             else WARN( "failed to start explorer, err %d\n", GetLastError() );
1725         }
1726         else TRACE( "not starting explorer since winstation is not visible\n" );
1727
1728         SERVER_START_REQ( get_desktop_window )
1729         {
1730             req->force = 1;
1731             if (!wine_server_call( req ))
1732             {
1733                 thread_info->top_window = reply->top_window;
1734                 thread_info->msg_window = reply->msg_window;
1735             }
1736         }
1737         SERVER_END_REQ;
1738     }
1739
1740     if (!thread_info->top_window || !USER_Driver->pCreateDesktopWindow( thread_info->top_window ))
1741         ERR( "failed to create desktop window\n" );
1742
1743     return thread_info->top_window;
1744 }
1745
1746
1747 /*******************************************************************
1748  *              EnableWindow (USER32.@)
1749  */
1750 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
1751 {
1752     BOOL retvalue;
1753     HWND full_handle;
1754
1755     if (is_broadcast(hwnd))
1756     {
1757         SetLastError( ERROR_INVALID_PARAMETER );
1758         return FALSE;
1759     }
1760
1761     if (!(full_handle = WIN_IsCurrentThread( hwnd )))
1762         return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
1763
1764     hwnd = full_handle;
1765
1766     TRACE("( %p, %d )\n", hwnd, enable);
1767
1768     retvalue = !IsWindowEnabled( hwnd );
1769
1770     if (enable && retvalue)
1771     {
1772         WIN_SetStyle( hwnd, 0, WS_DISABLED );
1773         SendMessageW( hwnd, WM_ENABLE, TRUE, 0 );
1774     }
1775     else if (!enable && !retvalue)
1776     {
1777         HWND capture_wnd;
1778
1779         SendMessageW( hwnd, WM_CANCELMODE, 0, 0);
1780
1781         WIN_SetStyle( hwnd, WS_DISABLED, 0 );
1782
1783         if (hwnd == GetFocus())
1784             SetFocus( 0 );  /* A disabled window can't have the focus */
1785
1786         capture_wnd = GetCapture();
1787         if (hwnd == capture_wnd || IsChild(hwnd, capture_wnd))
1788             ReleaseCapture();  /* A disabled window can't capture the mouse */
1789
1790         SendMessageW( hwnd, WM_ENABLE, FALSE, 0 );
1791     }
1792     return retvalue;
1793 }
1794
1795
1796 /***********************************************************************
1797  *              IsWindowEnabled (USER32.@)
1798  */
1799 BOOL WINAPI IsWindowEnabled(HWND hWnd)
1800 {
1801     return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
1802 }
1803
1804
1805 /***********************************************************************
1806  *              IsWindowUnicode (USER32.@)
1807  */
1808 BOOL WINAPI IsWindowUnicode( HWND hwnd )
1809 {
1810     WND * wndPtr;
1811     BOOL retvalue = FALSE;
1812
1813     if (!(wndPtr = WIN_GetPtr(hwnd))) return FALSE;
1814
1815     if (wndPtr == WND_DESKTOP) return TRUE;
1816
1817     if (wndPtr != WND_OTHER_PROCESS)
1818     {
1819         retvalue = (wndPtr->flags & WIN_ISUNICODE) != 0;
1820         WIN_ReleasePtr( wndPtr );
1821     }
1822     else
1823     {
1824         SERVER_START_REQ( get_window_info )
1825         {
1826             req->handle = hwnd;
1827             if (!wine_server_call_err( req )) retvalue = reply->is_unicode;
1828         }
1829         SERVER_END_REQ;
1830     }
1831     return retvalue;
1832 }
1833
1834
1835 /**********************************************************************
1836  *           WIN_GetWindowLong
1837  *
1838  * Helper function for GetWindowLong().
1839  */
1840 static LONG_PTR WIN_GetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicode )
1841 {
1842     LONG_PTR retvalue = 0;
1843     WND *wndPtr;
1844
1845     if (offset == GWLP_HWNDPARENT)
1846     {
1847         HWND parent = GetAncestor( hwnd, GA_PARENT );
1848         if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
1849         return (ULONG_PTR)parent;
1850     }
1851
1852     if (!(wndPtr = WIN_GetPtr( hwnd )))
1853     {
1854         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1855         return 0;
1856     }
1857
1858     if (wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP)
1859     {
1860         if (offset == GWLP_WNDPROC)
1861         {
1862             SetLastError( ERROR_ACCESS_DENIED );
1863             return 0;
1864         }
1865         SERVER_START_REQ( set_window_info )
1866         {
1867             req->handle = hwnd;
1868             req->flags  = 0;  /* don't set anything, just retrieve */
1869             req->extra_offset = (offset >= 0) ? offset : -1;
1870             req->extra_size = (offset >= 0) ? size : 0;
1871             if (!wine_server_call_err( req ))
1872             {
1873                 switch(offset)
1874                 {
1875                 case GWL_STYLE:      retvalue = reply->old_style; break;
1876                 case GWL_EXSTYLE:    retvalue = reply->old_ex_style; break;
1877                 case GWLP_ID:        retvalue = reply->old_id; break;
1878                 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)reply->old_instance; break;
1879                 case GWLP_USERDATA:  retvalue = reply->old_user_data; break;
1880                 default:
1881                     if (offset >= 0) retvalue = get_win_data( &reply->old_extra_value, size );
1882                     else SetLastError( ERROR_INVALID_INDEX );
1883                     break;
1884                 }
1885             }
1886         }
1887         SERVER_END_REQ;
1888         return retvalue;
1889     }
1890
1891     /* now we have a valid wndPtr */
1892
1893     if (offset >= 0)
1894     {
1895         if (offset > (int)(wndPtr->cbWndExtra - size))
1896         {
1897             WARN("Invalid offset %d\n", offset );
1898             WIN_ReleasePtr( wndPtr );
1899             SetLastError( ERROR_INVALID_INDEX );
1900             return 0;
1901         }
1902         retvalue = get_win_data( (char *)wndPtr->wExtra + offset, size );
1903
1904         /* Special case for dialog window procedure */
1905         if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && (wndPtr->flags & WIN_ISDIALOG))
1906             retvalue = (LONG_PTR)WINPROC_GetProc( (WNDPROC)retvalue, unicode );
1907         WIN_ReleasePtr( wndPtr );
1908         return retvalue;
1909     }
1910
1911     switch(offset)
1912     {
1913     case GWLP_USERDATA:  retvalue = wndPtr->userdata; break;
1914     case GWL_STYLE:      retvalue = wndPtr->dwStyle; break;
1915     case GWL_EXSTYLE:    retvalue = wndPtr->dwExStyle; break;
1916     case GWLP_ID:        retvalue = wndPtr->wIDmenu; break;
1917     case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hInstance; break;
1918     case GWLP_WNDPROC:
1919         /* This looks like a hack only for the edit control (see tests). This makes these controls
1920          * more tolerant to A/W mismatches. The lack of W->A->W conversion for such a mismatch suggests
1921          * that the hack is in GetWindowLongPtr[AW], not in winprocs.
1922          */
1923         if (wndPtr->winproc == EDIT_winproc_handle && (!unicode != !(wndPtr->flags & WIN_ISUNICODE)))
1924             retvalue = (ULONG_PTR)wndPtr->winproc;
1925         else
1926             retvalue = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, unicode );
1927         break;
1928     default:
1929         WARN("Unknown offset %d\n", offset );
1930         SetLastError( ERROR_INVALID_INDEX );
1931         break;
1932     }
1933     WIN_ReleasePtr(wndPtr);
1934     return retvalue;
1935 }
1936
1937
1938 /**********************************************************************
1939  *           WIN_SetWindowLong
1940  *
1941  * Helper function for SetWindowLong().
1942  *
1943  * 0 is the failure code. However, in the case of failure SetLastError
1944  * must be set to distinguish between a 0 return value and a failure.
1945  */
1946 LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, UINT size, LONG_PTR newval, BOOL unicode )
1947 {
1948     STYLESTRUCT style;
1949     BOOL ok;
1950     LONG_PTR retval = 0;
1951     WND *wndPtr;
1952
1953     TRACE( "%p %d %lx %c\n", hwnd, offset, newval, unicode ? 'W' : 'A' );
1954
1955     if (is_broadcast(hwnd))
1956     {
1957         SetLastError( ERROR_INVALID_PARAMETER );
1958         return FALSE;
1959     }
1960
1961     if (!(wndPtr = WIN_GetPtr( hwnd )))
1962     {
1963         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1964         return 0;
1965     }
1966     if (wndPtr == WND_DESKTOP)
1967     {
1968         /* can't change anything on the desktop window */
1969         SetLastError( ERROR_ACCESS_DENIED );
1970         return 0;
1971     }
1972     if (wndPtr == WND_OTHER_PROCESS)
1973     {
1974         if (offset == GWLP_WNDPROC)
1975         {
1976             SetLastError( ERROR_ACCESS_DENIED );
1977             return 0;
1978         }
1979         if (offset > 32767 || offset < -32767)
1980         {
1981             SetLastError( ERROR_INVALID_INDEX );
1982             return 0;
1983         }
1984         return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, MAKEWPARAM( offset, size ), newval );
1985     }
1986
1987     /* first some special cases */
1988     switch( offset )
1989     {
1990     case GWL_STYLE:
1991     case GWL_EXSTYLE:
1992         style.styleOld =
1993             offset == GWL_STYLE ? wndPtr->dwStyle : wndPtr->dwExStyle;
1994         style.styleNew = newval;
1995         WIN_ReleasePtr( wndPtr );
1996         SendMessageW( hwnd, WM_STYLECHANGING, offset, (LPARAM)&style );
1997         if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
1998         newval = style.styleNew;
1999         break;
2000     case GWLP_HWNDPARENT:
2001         if (wndPtr->parent == GetDesktopWindow())
2002         {
2003             WIN_ReleasePtr( wndPtr );
2004             return (ULONG_PTR)WIN_SetOwner( hwnd, (HWND)newval );
2005         }
2006         else
2007         {
2008             WIN_ReleasePtr( wndPtr );
2009             return (ULONG_PTR)SetParent( hwnd, (HWND)newval );
2010         }
2011     case GWLP_WNDPROC:
2012     {
2013         WNDPROC proc;
2014         UINT old_flags = wndPtr->flags;
2015         retval = WIN_GetWindowLong( hwnd, offset, size, unicode );
2016         if (unicode) proc = WINPROC_AllocProc( NULL, (WNDPROC)newval );
2017         else proc = WINPROC_AllocProc( (WNDPROC)newval, NULL );
2018         if (proc) wndPtr->winproc = proc;
2019         if (WINPROC_IsUnicode( proc, unicode )) wndPtr->flags |= WIN_ISUNICODE;
2020         else wndPtr->flags &= ~WIN_ISUNICODE;
2021         if (!((old_flags ^ wndPtr->flags) & WIN_ISUNICODE))
2022         {
2023             WIN_ReleasePtr( wndPtr );
2024             return retval;
2025         }
2026         /* update is_unicode flag on the server side */
2027         break;
2028     }
2029     case GWLP_ID:
2030     case GWLP_HINSTANCE:
2031     case GWLP_USERDATA:
2032         break;
2033     case DWLP_DLGPROC:
2034         if ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
2035             (size == sizeof(LONG_PTR)) && (wndPtr->flags & WIN_ISDIALOG))
2036         {
2037             WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWLP_DLGPROC);
2038             retval = (ULONG_PTR)WINPROC_GetProc( *ptr, unicode );
2039             if (unicode) *ptr = WINPROC_AllocProc( NULL, (WNDPROC)newval );
2040             else *ptr = WINPROC_AllocProc( (WNDPROC)newval, NULL );
2041             WIN_ReleasePtr( wndPtr );
2042             return retval;
2043         }
2044         /* fall through */
2045     default:
2046         if (offset < 0 || offset > (int)(wndPtr->cbWndExtra - size))
2047         {
2048             WARN("Invalid offset %d\n", offset );
2049             WIN_ReleasePtr( wndPtr );
2050             SetLastError( ERROR_INVALID_INDEX );
2051             return 0;
2052         }
2053         else if (get_win_data( (char *)wndPtr->wExtra + offset, size ) == newval)
2054         {
2055             /* already set to the same value */
2056             WIN_ReleasePtr( wndPtr );
2057             return newval;
2058         }
2059         break;
2060     }
2061
2062     SERVER_START_REQ( set_window_info )
2063     {
2064         req->handle = hwnd;
2065         req->extra_offset = -1;
2066         switch(offset)
2067         {
2068         case GWL_STYLE:
2069             req->flags = SET_WIN_STYLE;
2070             req->style = newval;
2071             break;
2072         case GWL_EXSTYLE:
2073             req->flags = SET_WIN_EXSTYLE;
2074             /* WS_EX_TOPMOST can only be changed through SetWindowPos */
2075             newval = (newval & ~WS_EX_TOPMOST) | (wndPtr->dwExStyle & WS_EX_TOPMOST);
2076             req->ex_style = newval;
2077             break;
2078         case GWLP_ID:
2079             req->flags = SET_WIN_ID;
2080             req->id = newval;
2081             break;
2082         case GWLP_HINSTANCE:
2083             req->flags = SET_WIN_INSTANCE;
2084             req->instance = (void *)newval;
2085             break;
2086         case GWLP_WNDPROC:
2087             req->flags = SET_WIN_UNICODE;
2088             req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
2089             break;
2090         case GWLP_USERDATA:
2091             req->flags = SET_WIN_USERDATA;
2092             req->user_data = newval;
2093             break;
2094         default:
2095             req->flags = SET_WIN_EXTRA;
2096             req->extra_offset = offset;
2097             req->extra_size = size;
2098             set_win_data( &req->extra_value, newval, size );
2099         }
2100         if ((ok = !wine_server_call_err( req )))
2101         {
2102             switch(offset)
2103             {
2104             case GWL_STYLE:
2105                 wndPtr->dwStyle = newval;
2106                 retval = reply->old_style;
2107                 break;
2108             case GWL_EXSTYLE:
2109                 wndPtr->dwExStyle = newval;
2110                 retval = reply->old_ex_style;
2111                 break;
2112             case GWLP_ID:
2113                 wndPtr->wIDmenu = newval;
2114                 retval = reply->old_id;
2115                 break;
2116             case GWLP_HINSTANCE:
2117                 wndPtr->hInstance = (HINSTANCE)newval;
2118                 retval = (ULONG_PTR)reply->old_instance;
2119                 break;
2120             case GWLP_WNDPROC:
2121                 break;
2122             case GWLP_USERDATA:
2123                 wndPtr->userdata = newval;
2124                 retval = reply->old_user_data;
2125                 break;
2126             default:
2127                 retval = get_win_data( (char *)wndPtr->wExtra + offset, size );
2128                 set_win_data( (char *)wndPtr->wExtra + offset, newval, size );
2129                 break;
2130             }
2131         }
2132     }
2133     SERVER_END_REQ;
2134     WIN_ReleasePtr( wndPtr );
2135
2136     if (!ok) return 0;
2137
2138     if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2139     {
2140         USER_Driver->pSetWindowStyle( hwnd, offset, &style );
2141         SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2142     }
2143
2144     return retval;
2145 }
2146
2147
2148 /**********************************************************************
2149  *              GetWindowLong (USER.135)
2150  */
2151 LONG WINAPI GetWindowLong16( HWND16 hwnd, INT16 offset )
2152 {
2153     WND *wndPtr;
2154     LONG_PTR retvalue;
2155     BOOL is_winproc = (offset == GWLP_WNDPROC);
2156
2157     if (offset >= 0)
2158     {
2159         if (!(wndPtr = WIN_GetPtr( WIN_Handle32(hwnd) )))
2160         {
2161             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2162             return 0;
2163         }
2164         if (wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
2165         {
2166             if (offset > (int)(wndPtr->cbWndExtra - sizeof(LONG)))
2167             {
2168                 /*
2169                  * Some programs try to access last element from 16 bit
2170                  * code using illegal offset value. Hopefully this is
2171                  * what those programs really expect.
2172                  */
2173                 if (wndPtr->cbWndExtra >= 4 && offset == wndPtr->cbWndExtra - sizeof(WORD))
2174                 {
2175                     INT offset2 = wndPtr->cbWndExtra - sizeof(LONG);
2176                     ERR( "- replaced invalid offset %d with %d\n", offset, offset2 );
2177                     offset = offset2;
2178                 }
2179                 else
2180                 {
2181                     WARN("Invalid offset %d\n", offset );
2182                     WIN_ReleasePtr( wndPtr );
2183                     SetLastError( ERROR_INVALID_INDEX );
2184                     return 0;
2185                 }
2186             }
2187             is_winproc = ((offset == DWLP_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG));
2188             WIN_ReleasePtr( wndPtr );
2189         }
2190     }
2191     retvalue = GetWindowLongA( WIN_Handle32(hwnd), offset );
2192     if (is_winproc) retvalue = (LONG_PTR)WINPROC_GetProc16( (WNDPROC)retvalue, FALSE );
2193     return retvalue;
2194 }
2195
2196
2197 /**********************************************************************
2198  *              GetWindowWord (USER32.@)
2199  */
2200 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
2201 {
2202     switch(offset)
2203     {
2204     case GWLP_ID:
2205     case GWLP_HINSTANCE:
2206     case GWLP_HWNDPARENT:
2207         break;
2208     default:
2209         if (offset < 0)
2210         {
2211             WARN("Invalid offset %d\n", offset );
2212             SetLastError( ERROR_INVALID_INDEX );
2213             return 0;
2214         }
2215         break;
2216     }
2217     return WIN_GetWindowLong( hwnd, offset, sizeof(WORD), FALSE );
2218 }
2219
2220
2221 /**********************************************************************
2222  *              GetWindowLongA (USER32.@)
2223  */
2224 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2225 {
2226     return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), FALSE );
2227 }
2228
2229
2230 /**********************************************************************
2231  *              GetWindowLongW (USER32.@)
2232  */
2233 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2234 {
2235     return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), TRUE );
2236 }
2237
2238
2239 /**********************************************************************
2240  *              SetWindowLong (USER.136)
2241  */
2242 LONG WINAPI SetWindowLong16( HWND16 hwnd, INT16 offset, LONG newval )
2243 {
2244     WND *wndPtr;
2245     BOOL is_winproc = (offset == GWLP_WNDPROC);
2246
2247     if (offset == DWLP_DLGPROC)
2248     {
2249         if (!(wndPtr = WIN_GetPtr( WIN_Handle32(hwnd) )))
2250         {
2251             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2252             return 0;
2253         }
2254         if (wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
2255         {
2256             is_winproc = ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
2257                           (wndPtr->flags & WIN_ISDIALOG));
2258             WIN_ReleasePtr( wndPtr );
2259         }
2260     }
2261
2262     if (is_winproc)
2263     {
2264         WNDPROC new_proc = WINPROC_AllocProc16( (WNDPROC16)newval );
2265         WNDPROC old_proc = (WNDPROC)SetWindowLongPtrA( WIN_Handle32(hwnd), offset, (LONG_PTR)new_proc );
2266         return (LONG)WINPROC_GetProc16( old_proc, FALSE );
2267     }
2268     else return SetWindowLongA( WIN_Handle32(hwnd), offset, newval );
2269 }
2270
2271
2272 /**********************************************************************
2273  *              SetWindowWord (USER32.@)
2274  */
2275 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
2276 {
2277     switch(offset)
2278     {
2279     case GWLP_ID:
2280     case GWLP_HINSTANCE:
2281     case GWLP_HWNDPARENT:
2282         break;
2283     default:
2284         if (offset < 0)
2285         {
2286             WARN("Invalid offset %d\n", offset );
2287             SetLastError( ERROR_INVALID_INDEX );
2288             return 0;
2289         }
2290         break;
2291     }
2292     return WIN_SetWindowLong( hwnd, offset, sizeof(WORD), newval, FALSE );
2293 }
2294
2295
2296 /**********************************************************************
2297  *              SetWindowLongA (USER32.@)
2298  *
2299  * See SetWindowLongW.
2300  */
2301 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2302 {
2303     return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, FALSE );
2304 }
2305
2306
2307 /**********************************************************************
2308  *              SetWindowLongW (USER32.@) Set window attribute
2309  *
2310  * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2311  * value in a window's extra memory.
2312  *
2313  * The _hwnd_ parameter specifies the window.  is the handle to a
2314  * window that has extra memory. The _newval_ parameter contains the
2315  * new attribute or extra memory value.  If positive, the _offset_
2316  * parameter is the byte-addressed location in the window's extra
2317  * memory to set.  If negative, _offset_ specifies the window
2318  * attribute to set, and should be one of the following values:
2319  *
2320  * GWL_EXSTYLE      The window's extended window style
2321  *
2322  * GWL_STYLE        The window's window style.
2323  *
2324  * GWLP_WNDPROC     Pointer to the window's window procedure.
2325  *
2326  * GWLP_HINSTANCE   The window's pplication instance handle.
2327  *
2328  * GWLP_ID          The window's identifier.
2329  *
2330  * GWLP_USERDATA    The window's user-specified data.
2331  *
2332  * If the window is a dialog box, the _offset_ parameter can be one of
2333  * the following values:
2334  *
2335  * DWLP_DLGPROC     The address of the window's dialog box procedure.
2336  *
2337  * DWLP_MSGRESULT   The return value of a message
2338  *                  that the dialog box procedure processed.
2339  *
2340  * DWLP_USER        Application specific information.
2341  *
2342  * RETURNS
2343  *
2344  * If successful, returns the previous value located at _offset_. Otherwise,
2345  * returns 0.
2346  *
2347  * NOTES
2348  *
2349  * Extra memory for a window class is specified by a nonzero cbWndExtra
2350  * parameter of the WNDCLASS structure passed to RegisterClass() at the
2351  * time of class creation.
2352  *
2353  * Using GWL_WNDPROC to set a new window procedure effectively creates
2354  * a window subclass. Use CallWindowProc() in the new windows procedure
2355  * to pass messages to the superclass's window procedure.
2356  *
2357  * The user data is reserved for use by the application which created
2358  * the window.
2359  *
2360  * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2361  * instead, call the EnableWindow() function to change the window's
2362  * disabled state.
2363  *
2364  * Do not use GWL_HWNDPARENT to reset the window's parent, use
2365  * SetParent() instead.
2366  *
2367  * Win95:
2368  * When offset is GWL_STYLE and the calling app's ver is 4.0,
2369  * it sends WM_STYLECHANGING before changing the settings
2370  * and WM_STYLECHANGED afterwards.
2371  * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2372  */
2373 LONG WINAPI SetWindowLongW(
2374     HWND hwnd,  /* [in] window to alter */
2375     INT offset, /* [in] offset, in bytes, of location to alter */
2376     LONG newval /* [in] new value of location */
2377 ) {
2378     return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, TRUE );
2379 }
2380
2381
2382 /*******************************************************************
2383  *              GetWindowTextA (USER32.@)
2384  */
2385 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2386 {
2387     WCHAR *buffer;
2388
2389     if (!lpString) return 0;
2390
2391     if (WIN_IsCurrentProcess( hwnd ))
2392         return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2393
2394     /* when window belongs to other process, don't send a message */
2395     if (nMaxCount <= 0) return 0;
2396     if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2397     get_server_window_text( hwnd, buffer, nMaxCount );
2398     if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2399         lpString[nMaxCount-1] = 0;
2400     HeapFree( GetProcessHeap(), 0, buffer );
2401     return strlen(lpString);
2402 }
2403
2404
2405 /*******************************************************************
2406  *              InternalGetWindowText (USER32.@)
2407  */
2408 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2409 {
2410     WND *win;
2411
2412     if (nMaxCount <= 0) return 0;
2413     if (!(win = WIN_GetPtr( hwnd ))) return 0;
2414     if (win == WND_DESKTOP) lpString[0] = 0;
2415     else if (win != WND_OTHER_PROCESS)
2416     {
2417         if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2418         else lpString[0] = 0;
2419         WIN_ReleasePtr( win );
2420     }
2421     else
2422     {
2423         get_server_window_text( hwnd, lpString, nMaxCount );
2424     }
2425     return strlenW(lpString);
2426 }
2427
2428
2429 /*******************************************************************
2430  *              GetWindowTextW (USER32.@)
2431  */
2432 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2433 {
2434     if (!lpString) return 0;
2435
2436     if (WIN_IsCurrentProcess( hwnd ))
2437         return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2438
2439     /* when window belongs to other process, don't send a message */
2440     if (nMaxCount <= 0) return 0;
2441     get_server_window_text( hwnd, lpString, nMaxCount );
2442     return strlenW(lpString);
2443 }
2444
2445
2446 /*******************************************************************
2447  *              SetWindowTextA (USER32.@)
2448  *              SetWindowText  (USER32.@)
2449  */
2450 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2451 {
2452     if (is_broadcast(hwnd))
2453     {
2454         SetLastError( ERROR_INVALID_PARAMETER );
2455         return FALSE;
2456     }
2457     if (!WIN_IsCurrentProcess( hwnd ))
2458         WARN( "setting text %s of other process window %p should not use SendMessage\n",
2459                debugstr_a(lpString), hwnd );
2460     return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2461 }
2462
2463
2464 /*******************************************************************
2465  *              SetWindowTextW (USER32.@)
2466  */
2467 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2468 {
2469     if (is_broadcast(hwnd))
2470     {
2471         SetLastError( ERROR_INVALID_PARAMETER );
2472         return FALSE;
2473     }
2474     if (!WIN_IsCurrentProcess( hwnd ))
2475         WARN( "setting text %s of other process window %p should not use SendMessage\n",
2476                debugstr_w(lpString), hwnd );
2477     return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2478 }
2479
2480
2481 /*******************************************************************
2482  *              GetWindowTextLengthA (USER32.@)
2483  */
2484 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2485 {
2486     return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2487 }
2488
2489 /*******************************************************************
2490  *              GetWindowTextLengthW (USER32.@)
2491  */
2492 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2493 {
2494     return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2495 }
2496
2497
2498 /*******************************************************************
2499  *              IsWindow (USER32.@)
2500  */
2501 BOOL WINAPI IsWindow( HWND hwnd )
2502 {
2503     WND *ptr;
2504     BOOL ret;
2505
2506     if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2507     if (ptr == WND_DESKTOP) return TRUE;
2508
2509     if (ptr != WND_OTHER_PROCESS)
2510     {
2511         WIN_ReleasePtr( ptr );
2512         return TRUE;
2513     }
2514
2515     /* check other processes */
2516     SERVER_START_REQ( get_window_info )
2517     {
2518         req->handle = hwnd;
2519         ret = !wine_server_call_err( req );
2520     }
2521     SERVER_END_REQ;
2522     return ret;
2523 }
2524
2525
2526 /***********************************************************************
2527  *              GetWindowThreadProcessId (USER32.@)
2528  */
2529 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2530 {
2531     WND *ptr;
2532     DWORD tid = 0;
2533
2534     if (!(ptr = WIN_GetPtr( hwnd )))
2535     {
2536         SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2537         return 0;
2538     }
2539
2540     if (ptr != WND_OTHER_PROCESS && ptr != WND_DESKTOP)
2541     {
2542         /* got a valid window */
2543         tid = ptr->tid;
2544         if (process) *process = GetCurrentProcessId();
2545         WIN_ReleasePtr( ptr );
2546         return tid;
2547     }
2548
2549     /* check other processes */
2550     SERVER_START_REQ( get_window_info )
2551     {
2552         req->handle = hwnd;
2553         if (!wine_server_call_err( req ))
2554         {
2555             tid = (DWORD)reply->tid;
2556             if (process) *process = (DWORD)reply->pid;
2557         }
2558     }
2559     SERVER_END_REQ;
2560     return tid;
2561 }
2562
2563
2564 /*****************************************************************
2565  *              GetParent (USER32.@)
2566  */
2567 HWND WINAPI GetParent( HWND hwnd )
2568 {
2569     WND *wndPtr;
2570     HWND retvalue = 0;
2571
2572     if (!(wndPtr = WIN_GetPtr( hwnd )))
2573     {
2574         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2575         return 0;
2576     }
2577     if (wndPtr == WND_DESKTOP) return 0;
2578     if (wndPtr == WND_OTHER_PROCESS)
2579     {
2580         LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2581         if (style & (WS_POPUP | WS_CHILD))
2582         {
2583             SERVER_START_REQ( get_window_tree )
2584             {
2585                 req->handle = hwnd;
2586                 if (!wine_server_call_err( req ))
2587                 {
2588                     if (style & WS_POPUP) retvalue = reply->owner;
2589                     else if (style & WS_CHILD) retvalue = reply->parent;
2590                 }
2591             }
2592             SERVER_END_REQ;
2593         }
2594     }
2595     else
2596     {
2597         if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2598         else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2599         WIN_ReleasePtr( wndPtr );
2600     }
2601     return retvalue;
2602 }
2603
2604
2605 /*****************************************************************
2606  *              GetAncestor (USER32.@)
2607  */
2608 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2609 {
2610     WND *win;
2611     HWND *list, ret = 0;
2612
2613     switch(type)
2614     {
2615     case GA_PARENT:
2616         if (!(win = WIN_GetPtr( hwnd )))
2617         {
2618             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2619             return 0;
2620         }
2621         if (win == WND_DESKTOP) return 0;
2622         if (win != WND_OTHER_PROCESS)
2623         {
2624             ret = win->parent;
2625             WIN_ReleasePtr( win );
2626         }
2627         else /* need to query the server */
2628         {
2629             SERVER_START_REQ( get_window_tree )
2630             {
2631                 req->handle = hwnd;
2632                 if (!wine_server_call_err( req )) ret = reply->parent;
2633             }
2634             SERVER_END_REQ;
2635         }
2636         break;
2637
2638     case GA_ROOT:
2639         if (!(list = list_window_parents( hwnd ))) return 0;
2640
2641         if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd );  /* top-level window */
2642         else
2643         {
2644             int count = 2;
2645             while (list[count]) count++;
2646             ret = list[count - 2];  /* get the one before the desktop */
2647         }
2648         HeapFree( GetProcessHeap(), 0, list );
2649         break;
2650
2651     case GA_ROOTOWNER:
2652         if (is_desktop_window( hwnd )) return 0;
2653         ret = WIN_GetFullHandle( hwnd );
2654         for (;;)
2655         {
2656             HWND parent = GetParent( ret );
2657             if (!parent) break;
2658             ret = parent;
2659         }
2660         break;
2661     }
2662     return ret;
2663 }
2664
2665
2666 /*****************************************************************
2667  *              SetParent (USER32.@)
2668  */
2669 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2670 {
2671     HWND full_handle;
2672     HWND old_parent = 0;
2673     BOOL was_visible;
2674     WND *wndPtr;
2675     BOOL ret;
2676
2677     if (is_broadcast(hwnd) || is_broadcast(parent))
2678     {
2679         SetLastError(ERROR_INVALID_PARAMETER);
2680         return 0;
2681     }
2682
2683     if (!parent) parent = GetDesktopWindow();
2684     else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
2685     else parent = WIN_GetFullHandle( parent );
2686
2687     if (!IsWindow( parent ))
2688     {
2689         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2690         return 0;
2691     }
2692
2693     /* Some applications try to set a child as a parent */
2694     if (IsChild(hwnd, parent))
2695     {
2696         SetLastError( ERROR_INVALID_PARAMETER );
2697         return 0;
2698     }
2699
2700     if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2701         return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2702
2703     /* Windows hides the window first, then shows it again
2704      * including the WM_SHOWWINDOW messages and all */
2705     was_visible = ShowWindow( hwnd, SW_HIDE );
2706
2707     wndPtr = WIN_GetPtr( hwnd );
2708     if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
2709
2710     SERVER_START_REQ( set_parent )
2711     {
2712         req->handle = hwnd;
2713         req->parent = parent;
2714         if ((ret = !wine_server_call( req )))
2715         {
2716             old_parent = reply->old_parent;
2717             wndPtr->parent = parent = reply->full_parent;
2718         }
2719
2720     }
2721     SERVER_END_REQ;
2722     WIN_ReleasePtr( wndPtr );
2723     if (!ret) return 0;
2724
2725     USER_Driver->pSetParent( full_handle, parent, old_parent );
2726
2727     /* SetParent additionally needs to make hwnd the topmost window
2728        in the x-order and send the expected WM_WINDOWPOSCHANGING and
2729        WM_WINDOWPOSCHANGED notification messages.
2730     */
2731     SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0,
2732                   SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | (was_visible ? SWP_SHOWWINDOW : 0) );
2733     /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
2734      * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
2735
2736     return old_parent;
2737 }
2738
2739
2740 /*******************************************************************
2741  *              IsChild (USER32.@)
2742  */
2743 BOOL WINAPI IsChild( HWND parent, HWND child )
2744 {
2745     HWND *list = list_window_parents( child );
2746     int i;
2747     BOOL ret;
2748
2749     if (!list) return FALSE;
2750     parent = WIN_GetFullHandle( parent );
2751     for (i = 0; list[i]; i++) if (list[i] == parent) break;
2752     ret = list[i] && list[i+1];
2753     HeapFree( GetProcessHeap(), 0, list );
2754     return ret;
2755 }
2756
2757
2758 /***********************************************************************
2759  *              IsWindowVisible (USER32.@)
2760  */
2761 BOOL WINAPI IsWindowVisible( HWND hwnd )
2762 {
2763     HWND *list;
2764     BOOL retval = TRUE;
2765     int i;
2766
2767     if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2768     if (!(list = list_window_parents( hwnd ))) return TRUE;
2769     if (list[0])
2770     {
2771         for (i = 0; list[i+1]; i++)
2772             if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2773         retval = !list[i+1] && (list[i] == GetDesktopWindow());  /* top message window isn't visible */
2774     }
2775     HeapFree( GetProcessHeap(), 0, list );
2776     return retval;
2777 }
2778
2779
2780 /***********************************************************************
2781  *           WIN_IsWindowDrawable
2782  *
2783  * hwnd is drawable when it is visible, all parents are not
2784  * minimized, and it is itself not minimized unless we are
2785  * trying to draw its default class icon.
2786  */
2787 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2788 {
2789     HWND *list;
2790     BOOL retval = TRUE;
2791     int i;
2792     LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2793
2794     if (!(style & WS_VISIBLE)) return FALSE;
2795     if ((style & WS_MINIMIZE) && icon && GetClassLongPtrW( hwnd, GCLP_HICON ))  return FALSE;
2796
2797     if (!(list = list_window_parents( hwnd ))) return TRUE;
2798     if (list[0])
2799     {
2800         for (i = 0; list[i+1]; i++)
2801             if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2802                 break;
2803         retval = !list[i+1] && (list[i] == GetDesktopWindow());  /* top message window isn't visible */
2804     }
2805     HeapFree( GetProcessHeap(), 0, list );
2806     return retval;
2807 }
2808
2809
2810 /*******************************************************************
2811  *              GetTopWindow (USER32.@)
2812  */
2813 HWND WINAPI GetTopWindow( HWND hwnd )
2814 {
2815     if (!hwnd) hwnd = GetDesktopWindow();
2816     return GetWindow( hwnd, GW_CHILD );
2817 }
2818
2819
2820 /*******************************************************************
2821  *              GetWindow (USER32.@)
2822  */
2823 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2824 {
2825     HWND retval = 0;
2826
2827     if (rel == GW_OWNER)  /* this one may be available locally */
2828     {
2829         WND *wndPtr = WIN_GetPtr( hwnd );
2830         if (!wndPtr)
2831         {
2832             SetLastError( ERROR_INVALID_HANDLE );
2833             return 0;
2834         }
2835         if (wndPtr == WND_DESKTOP) return 0;
2836         if (wndPtr != WND_OTHER_PROCESS)
2837         {
2838             retval = wndPtr->owner;
2839             WIN_ReleasePtr( wndPtr );
2840             return retval;
2841         }
2842         /* else fall through to server call */
2843     }
2844
2845     SERVER_START_REQ( get_window_tree )
2846     {
2847         req->handle = hwnd;
2848         if (!wine_server_call_err( req ))
2849         {
2850             switch(rel)
2851             {
2852             case GW_HWNDFIRST:
2853                 retval = reply->first_sibling;
2854                 break;
2855             case GW_HWNDLAST:
2856                 retval = reply->last_sibling;
2857                 break;
2858             case GW_HWNDNEXT:
2859                 retval = reply->next_sibling;
2860                 break;
2861             case GW_HWNDPREV:
2862                 retval = reply->prev_sibling;
2863                 break;
2864             case GW_OWNER:
2865                 retval = reply->owner;
2866                 break;
2867             case GW_CHILD:
2868                 retval = reply->first_child;
2869                 break;
2870             }
2871         }
2872     }
2873     SERVER_END_REQ;
2874     return retval;
2875 }
2876
2877
2878 /*******************************************************************
2879  *              ShowOwnedPopups (USER32.@)
2880  */
2881 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2882 {
2883     int count = 0;
2884     WND *pWnd;
2885     HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2886
2887     if (!win_array) return TRUE;
2888
2889     while (win_array[count]) count++;
2890     while (--count >= 0)
2891     {
2892         if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2893         if (!(pWnd = WIN_GetPtr( win_array[count] ))) continue;
2894         if (pWnd == WND_OTHER_PROCESS) continue;
2895         if (fShow)
2896         {
2897             if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2898             {
2899                 WIN_ReleasePtr( pWnd );
2900                 /* In Windows, ShowOwnedPopups(TRUE) generates
2901                  * WM_SHOWWINDOW messages with SW_PARENTOPENING,
2902                  * regardless of the state of the owner
2903                  */
2904                 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
2905                 continue;
2906             }
2907         }
2908         else
2909         {
2910             if (pWnd->dwStyle & WS_VISIBLE)
2911             {
2912                 WIN_ReleasePtr( pWnd );
2913                 /* In Windows, ShowOwnedPopups(FALSE) generates
2914                  * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
2915                  * regardless of the state of the owner
2916                  */
2917                 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
2918                 continue;
2919             }
2920         }
2921         WIN_ReleasePtr( pWnd );
2922     }
2923     HeapFree( GetProcessHeap(), 0, win_array );
2924     return TRUE;
2925 }
2926
2927
2928 /*******************************************************************
2929  *              GetLastActivePopup (USER32.@)
2930  */
2931 HWND WINAPI GetLastActivePopup( HWND hwnd )
2932 {
2933     HWND retval = hwnd;
2934
2935     SERVER_START_REQ( get_window_info )
2936     {
2937         req->handle = hwnd;
2938         if (!wine_server_call_err( req )) retval = reply->last_active;
2939     }
2940     SERVER_END_REQ;
2941     return retval;
2942 }
2943
2944
2945 /*******************************************************************
2946  *           WIN_ListChildren
2947  *
2948  * Build an array of the children of a given window. The array must be
2949  * freed with HeapFree. Returns NULL when no windows are found.
2950  */
2951 HWND *WIN_ListChildren( HWND hwnd )
2952 {
2953     if (!hwnd)
2954     {
2955         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2956         return NULL;
2957     }
2958     return list_window_children( 0, hwnd, NULL, 0 );
2959 }
2960
2961
2962 /*******************************************************************
2963  *              EnumWindows (USER32.@)
2964  */
2965 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
2966 {
2967     HWND *list;
2968     BOOL ret = TRUE;
2969     int i;
2970
2971     USER_CheckNotLock();
2972
2973     /* We have to build a list of all windows first, to avoid */
2974     /* unpleasant side-effects, for instance if the callback */
2975     /* function changes the Z-order of the windows.          */
2976
2977     if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
2978
2979     /* Now call the callback function for every window */
2980
2981     for (i = 0; list[i]; i++)
2982     {
2983         /* Make sure that the window still exists */
2984         if (!IsWindow( list[i] )) continue;
2985         if (!(ret = lpEnumFunc( list[i], lParam ))) break;
2986     }
2987     HeapFree( GetProcessHeap(), 0, list );
2988     return ret;
2989 }
2990
2991
2992 /**********************************************************************
2993  *              EnumThreadWindows (USER32.@)
2994  */
2995 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
2996 {
2997     HWND *list;
2998     int i;
2999
3000     USER_CheckNotLock();
3001
3002     if (!(list = list_window_children( 0, GetDesktopWindow(), NULL, id ))) return TRUE;
3003
3004     /* Now call the callback function for every window */
3005
3006     for (i = 0; list[i]; i++)
3007         if (!func( list[i], lParam )) break;
3008     HeapFree( GetProcessHeap(), 0, list );
3009     return TRUE;
3010 }
3011
3012
3013 /***********************************************************************
3014  *              EnumDesktopWindows   (USER32.@)
3015  */
3016 BOOL WINAPI EnumDesktopWindows( HDESK desktop, WNDENUMPROC func, LPARAM lparam )
3017 {
3018     HWND *list;
3019     int i;
3020
3021     USER_CheckNotLock();
3022
3023     if (!(list = list_window_children( desktop, 0, NULL, 0 ))) return TRUE;
3024
3025     for (i = 0; list[i]; i++)
3026         if (!func( list[i], lparam )) break;
3027     HeapFree( GetProcessHeap(), 0, list );
3028     return TRUE;
3029 }
3030
3031
3032 /**********************************************************************
3033  *           WIN_EnumChildWindows
3034  *
3035  * Helper function for EnumChildWindows().
3036  */
3037 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
3038 {
3039     HWND *childList;
3040     BOOL ret = FALSE;
3041
3042     for ( ; *list; list++)
3043     {
3044         /* Make sure that the window still exists */
3045         if (!IsWindow( *list )) continue;
3046         /* Build children list first */
3047         childList = WIN_ListChildren( *list );
3048
3049         ret = func( *list, lParam );
3050
3051         if (childList)
3052         {
3053             if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
3054             HeapFree( GetProcessHeap(), 0, childList );
3055         }
3056         if (!ret) return FALSE;
3057     }
3058     return TRUE;
3059 }
3060
3061
3062 /**********************************************************************
3063  *              EnumChildWindows (USER32.@)
3064  */
3065 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
3066 {
3067     HWND *list;
3068     BOOL ret;
3069
3070     USER_CheckNotLock();
3071
3072     if (!(list = WIN_ListChildren( parent ))) return FALSE;
3073     ret = WIN_EnumChildWindows( list, func, lParam );
3074     HeapFree( GetProcessHeap(), 0, list );
3075     return ret;
3076 }
3077
3078
3079 /*******************************************************************
3080  *              AnyPopup (USER.52)
3081  */
3082 BOOL16 WINAPI AnyPopup16(void)
3083 {
3084     return AnyPopup();
3085 }
3086
3087
3088 /*******************************************************************
3089  *              AnyPopup (USER32.@)
3090  */
3091 BOOL WINAPI AnyPopup(void)
3092 {
3093     int i;
3094     BOOL retvalue;
3095     HWND *list = WIN_ListChildren( GetDesktopWindow() );
3096
3097     if (!list) return FALSE;
3098     for (i = 0; list[i]; i++)
3099     {
3100         if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
3101     }
3102     retvalue = (list[i] != 0);
3103     HeapFree( GetProcessHeap(), 0, list );
3104     return retvalue;
3105 }
3106
3107
3108 /*******************************************************************
3109  *              FlashWindow (USER32.@)
3110  */
3111 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3112 {
3113     WND *wndPtr;
3114
3115     TRACE("%p\n", hWnd);
3116
3117     if (IsIconic( hWnd ))
3118     {
3119         RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
3120
3121         wndPtr = WIN_GetPtr(hWnd);
3122         if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3123         if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
3124         {
3125             wndPtr->flags |= WIN_NCACTIVATED;
3126         }
3127         else
3128         {
3129             wndPtr->flags &= ~WIN_NCACTIVATED;
3130         }
3131         WIN_ReleasePtr( wndPtr );
3132         return TRUE;
3133     }
3134     else
3135     {
3136         WPARAM wparam;
3137
3138         wndPtr = WIN_GetPtr(hWnd);
3139         if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3140         hWnd = wndPtr->hwndSelf;  /* make it a full handle */
3141
3142         if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3143         else wparam = (hWnd == GetForegroundWindow());
3144
3145         WIN_ReleasePtr( wndPtr );
3146         SendMessageW( hWnd, WM_NCACTIVATE, wparam, (LPARAM)0 );
3147         return wparam;
3148     }
3149 }
3150
3151 /*******************************************************************
3152  *              FlashWindowEx (USER32.@)
3153  */
3154 BOOL WINAPI FlashWindowEx( PFLASHWINFO pfwi )
3155 {
3156     FIXME("%p\n", pfwi);
3157     return TRUE;
3158 }
3159
3160 /*******************************************************************
3161  *              GetWindowContextHelpId (USER32.@)
3162  */
3163 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3164 {
3165     DWORD retval;
3166     WND *wnd = WIN_GetPtr( hwnd );
3167     if (!wnd || wnd == WND_DESKTOP) return 0;
3168     if (wnd == WND_OTHER_PROCESS)
3169     {
3170         if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3171         return 0;
3172     }
3173     retval = wnd->helpContext;
3174     WIN_ReleasePtr( wnd );
3175     return retval;
3176 }
3177
3178
3179 /*******************************************************************
3180  *              SetWindowContextHelpId (USER32.@)
3181  */
3182 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3183 {
3184     WND *wnd = WIN_GetPtr( hwnd );
3185     if (!wnd || wnd == WND_DESKTOP) return FALSE;
3186     if (wnd == WND_OTHER_PROCESS)
3187     {
3188         if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3189         return 0;
3190     }
3191     wnd->helpContext = id;
3192     WIN_ReleasePtr( wnd );
3193     return TRUE;
3194 }
3195
3196
3197 /*******************************************************************
3198  *              DragDetect (USER32.@)
3199  */
3200 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3201 {
3202     MSG msg;
3203     RECT rect;
3204     WORD wDragWidth = GetSystemMetrics(SM_CXDRAG);
3205     WORD wDragHeight= GetSystemMetrics(SM_CYDRAG);
3206
3207     rect.left = pt.x - wDragWidth;
3208     rect.right = pt.x + wDragWidth;
3209
3210     rect.top = pt.y - wDragHeight;
3211     rect.bottom = pt.y + wDragHeight;
3212
3213     SetCapture(hWnd);
3214
3215     while(1)
3216     {
3217         while (PeekMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ))
3218         {
3219             if( msg.message == WM_LBUTTONUP )
3220             {
3221                 ReleaseCapture();
3222                 return 0;
3223             }
3224             if( msg.message == WM_MOUSEMOVE )
3225             {
3226                 POINT tmp;
3227                 tmp.x = (short)LOWORD(msg.lParam);
3228                 tmp.y = (short)HIWORD(msg.lParam);
3229                 if( !PtInRect( &rect, tmp ))
3230                 {
3231                     ReleaseCapture();
3232                     return 1;
3233                 }
3234             }
3235         }
3236         WaitMessage();
3237     }
3238     return 0;
3239 }
3240
3241 /******************************************************************************
3242  *              GetWindowModuleFileNameA (USER32.@)
3243  */
3244 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR module, UINT size )
3245 {
3246     WND *win;
3247     HINSTANCE hinst;
3248
3249     TRACE( "%p, %p, %u\n", hwnd, module, size );
3250
3251     win = WIN_GetPtr( hwnd );
3252     if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3253     {
3254         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3255         return 0;
3256     }
3257     hinst = win->hInstance;
3258     WIN_ReleasePtr( win );
3259
3260     return GetModuleFileNameA( hinst, module, size );
3261 }
3262
3263 /******************************************************************************
3264  *              GetWindowModuleFileNameW (USER32.@)
3265  */
3266 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR module, UINT size )
3267 {
3268     WND *win;
3269     HINSTANCE hinst;
3270
3271     TRACE( "%p, %p, %u\n", hwnd, module, size );
3272
3273     win = WIN_GetPtr( hwnd );
3274     if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3275     {
3276         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3277         return 0;
3278     }
3279     hinst = win->hInstance;
3280     WIN_ReleasePtr( win );
3281
3282     return GetModuleFileNameW( hinst, module, size );
3283 }
3284
3285 /******************************************************************************
3286  *              GetWindowInfo (USER32.@)
3287  *
3288  * Note: tests show that Windows doesn't check cbSize of the structure.
3289  */
3290 BOOL WINAPI GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3291 {
3292     if (!pwi) return FALSE;
3293     if (!IsWindow(hwnd)) return FALSE;
3294
3295     GetWindowRect(hwnd, &pwi->rcWindow);
3296     GetClientRect(hwnd, &pwi->rcClient);
3297     /* translate to screen coordinates */
3298     MapWindowPoints(hwnd, 0, (LPPOINT)&pwi->rcClient, 2);
3299
3300     pwi->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
3301     pwi->dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3302     pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3303
3304     pwi->cxWindowBorders = pwi->rcClient.left - pwi->rcWindow.left;
3305     pwi->cyWindowBorders = pwi->rcWindow.bottom - pwi->rcClient.bottom;
3306
3307     pwi->atomWindowType = GetClassLongW( hwnd, GCW_ATOM );
3308     pwi->wCreatorVersion = 0x0400;
3309
3310     return TRUE;
3311 }
3312
3313 /******************************************************************************
3314  *              SwitchDesktop (USER32.@)
3315  *
3316  * NOTES: Sets the current input or interactive desktop.
3317  */
3318 BOOL WINAPI SwitchDesktop( HDESK hDesktop)
3319 {
3320     FIXME("SwitchDesktop(hwnd %p) stub!\n", hDesktop);
3321     return TRUE;
3322 }
3323
3324 /*****************************************************************************
3325  *              SetLayeredWindowAttributes (USER32.@)
3326  */
3327 BOOL WINAPI SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, DWORD flags )
3328 {
3329     BOOL ret;
3330
3331     TRACE("(%p,%08x,%d,%x): stub!\n", hwnd, key, alpha, flags);
3332
3333     SERVER_START_REQ( set_window_layered_info )
3334     {
3335         req->handle = hwnd;
3336         req->color_key = key;
3337         req->alpha = alpha;
3338         req->flags = flags;
3339         ret = !wine_server_call_err( req );
3340     }
3341     SERVER_END_REQ;
3342
3343     if (ret) USER_Driver->pSetLayeredWindowAttributes( hwnd, key, alpha, flags );
3344
3345     return ret;
3346 }
3347
3348
3349 /*****************************************************************************
3350  *              GetLayeredWindowAttributes (USER32.@)
3351  */
3352 BOOL WINAPI GetLayeredWindowAttributes( HWND hwnd, COLORREF *key, BYTE *alpha, DWORD *flags )
3353 {
3354     BOOL ret;
3355
3356     SERVER_START_REQ( get_window_layered_info )
3357     {
3358         req->handle = hwnd;
3359         if ((ret = !wine_server_call_err( req )))
3360         {
3361             if (key) *key = reply->color_key;
3362             if (alpha) *alpha = reply->alpha;
3363             if (flags) *flags = reply->flags;
3364         }
3365     }
3366     SERVER_END_REQ;
3367
3368     return ret;
3369 }
3370
3371
3372 /*****************************************************************************
3373  *              UpdateLayeredWindowIndirect  (USER32.@)
3374  */
3375 BOOL WINAPI UpdateLayeredWindowIndirect( HWND hwnd, const UPDATELAYEREDWINDOWINFO *info )
3376 {
3377     BYTE alpha = 0xff;
3378
3379     if (!(info->dwFlags & ULW_EX_NORESIZE) && (info->pptDst || info->psize))
3380     {
3381         int x = 0, y = 0, cx = 0, cy = 0;
3382         DWORD flags = SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOSENDCHANGING;
3383
3384         if (info->pptDst)
3385         {
3386             x = info->pptDst->x;
3387             y = info->pptDst->y;
3388             flags &= ~SWP_NOMOVE;
3389         }
3390         if (info->psize)
3391         {
3392             cx = info->psize->cx;
3393             cy = info->psize->cy;
3394             flags &= ~SWP_NOSIZE;
3395         }
3396         TRACE( "moving window %p pos %d,%d %dx%x\n", hwnd, x, y, cx, cy );
3397         SetWindowPos( hwnd, 0, x, y, cx, cy, flags );
3398     }
3399
3400     if (info->hdcSrc)
3401     {
3402         RECT rect;
3403         HDC hdc = GetDCEx( hwnd, 0, DCX_CACHE );
3404
3405         if (hdc)
3406         {
3407             int x = 0, y = 0;
3408
3409             GetClientRect( hwnd, &rect );
3410             if (info->pptSrc)
3411             {
3412                 x = info->pptSrc->x;
3413                 y = info->pptSrc->y;
3414             }
3415             /* FIXME: intersect rect with info->prcDirty */
3416             TRACE( "copying window %p pos %d,%d\n", hwnd, x, y );
3417             BitBlt( hdc, rect.left, rect.top, rect.right, rect.bottom,
3418                     info->hdcSrc, rect.left + x, rect.top + y, SRCCOPY );
3419             ReleaseDC( hwnd, hdc );
3420         }
3421     }
3422
3423     if (info->pblend && !(info->dwFlags & ULW_OPAQUE)) alpha = info->pblend->SourceConstantAlpha;
3424     TRACE( "setting window %p alpha %u\n", hwnd, alpha );
3425     USER_Driver->pSetLayeredWindowAttributes( hwnd, info->crKey, alpha,
3426                                               info->dwFlags & (LWA_ALPHA | LWA_COLORKEY) );
3427     return TRUE;
3428 }
3429
3430
3431 /*****************************************************************************
3432  *              UpdateLayeredWindow (USER32.@)
3433  */
3434 BOOL WINAPI UpdateLayeredWindow( HWND hwnd, HDC hdcDst, POINT *pptDst, SIZE *psize,
3435                                  HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend,
3436                                  DWORD dwFlags)
3437 {
3438     UPDATELAYEREDWINDOWINFO info;
3439
3440     info.cbSize   = sizeof(info);
3441     info.hdcDst   = hdcDst;
3442     info.pptDst   = pptDst;
3443     info.psize    = psize;
3444     info.hdcSrc   = hdcSrc;
3445     info.pptSrc   = pptSrc;
3446     info.crKey    = crKey;
3447     info.pblend   = pblend;
3448     info.dwFlags  = dwFlags;
3449     info.prcDirty = NULL;
3450     return UpdateLayeredWindowIndirect( hwnd, &info );
3451 }
3452
3453 /* 64bit versions */
3454
3455 #ifdef GetWindowLongPtrW
3456 #undef GetWindowLongPtrW
3457 #endif
3458
3459 #ifdef GetWindowLongPtrA
3460 #undef GetWindowLongPtrA
3461 #endif
3462
3463 #ifdef SetWindowLongPtrW
3464 #undef SetWindowLongPtrW
3465 #endif
3466
3467 #ifdef SetWindowLongPtrA
3468 #undef SetWindowLongPtrA
3469 #endif
3470
3471 /*****************************************************************************
3472  *              GetWindowLongPtrW (USER32.@)
3473  */
3474 LONG_PTR WINAPI GetWindowLongPtrW( HWND hwnd, INT offset )
3475 {
3476     return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), TRUE );
3477 }
3478
3479 /*****************************************************************************
3480  *              GetWindowLongPtrA (USER32.@)
3481  */
3482 LONG_PTR WINAPI GetWindowLongPtrA( HWND hwnd, INT offset )
3483 {
3484     return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), FALSE );
3485 }
3486
3487 /*****************************************************************************
3488  *              SetWindowLongPtrW (USER32.@)
3489  */
3490 LONG_PTR WINAPI SetWindowLongPtrW( HWND hwnd, INT offset, LONG_PTR newval )
3491 {
3492     return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, TRUE );
3493 }
3494
3495 /*****************************************************************************
3496  *              SetWindowLongPtrA (USER32.@)
3497  */
3498 LONG_PTR WINAPI SetWindowLongPtrA( HWND hwnd, INT offset, LONG_PTR newval )
3499 {
3500     return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, FALSE );
3501 }