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