ole32: Fix memory leaks in the storage test.
[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 WIN_CreateWindowEx( (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 WIN_CreateWindowEx( (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 WIN_CreateWindowEx( &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         if (unicode) proc = WINPROC_AllocProc( NULL, (WNDPROC)newval );
2103         else proc = WINPROC_AllocProc( (WNDPROC)newval, NULL );
2104         if (proc) wndPtr->winproc = proc;
2105         if (WINPROC_IsUnicode( proc, unicode )) wndPtr->flags |= WIN_ISUNICODE;
2106         else wndPtr->flags &= ~WIN_ISUNICODE;
2107         if (!((old_flags ^ wndPtr->flags) & WIN_ISUNICODE))
2108         {
2109             WIN_ReleasePtr( wndPtr );
2110             return retval;
2111         }
2112         /* update is_unicode flag on the server side */
2113         break;
2114     }
2115     case GWLP_ID:
2116     case GWLP_HINSTANCE:
2117     case GWLP_USERDATA:
2118         break;
2119     case DWLP_DLGPROC:
2120         if ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
2121             (size == sizeof(LONG_PTR)) && (wndPtr->flags & WIN_ISDIALOG))
2122         {
2123             WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWLP_DLGPROC);
2124             retval = (ULONG_PTR)WINPROC_GetProc( *ptr, unicode );
2125             if (unicode) *ptr = WINPROC_AllocProc( NULL, (WNDPROC)newval );
2126             else *ptr = WINPROC_AllocProc( (WNDPROC)newval, NULL );
2127             WIN_ReleasePtr( wndPtr );
2128             return retval;
2129         }
2130         /* fall through */
2131     default:
2132         if (offset < 0 || offset > (int)(wndPtr->cbWndExtra - size))
2133         {
2134             WARN("Invalid offset %d\n", offset );
2135             WIN_ReleasePtr( wndPtr );
2136             SetLastError( ERROR_INVALID_INDEX );
2137             return 0;
2138         }
2139         else if (get_win_data( (char *)wndPtr->wExtra + offset, size ) == newval)
2140         {
2141             /* already set to the same value */
2142             WIN_ReleasePtr( wndPtr );
2143             return newval;
2144         }
2145         break;
2146     }
2147
2148     SERVER_START_REQ( set_window_info )
2149     {
2150         req->handle = wine_server_user_handle( hwnd );
2151         req->extra_offset = -1;
2152         switch(offset)
2153         {
2154         case GWL_STYLE:
2155             req->flags = SET_WIN_STYLE;
2156             req->style = newval;
2157             break;
2158         case GWL_EXSTYLE:
2159             req->flags = SET_WIN_EXSTYLE;
2160             /* WS_EX_TOPMOST can only be changed through SetWindowPos */
2161             newval = (newval & ~WS_EX_TOPMOST) | (wndPtr->dwExStyle & WS_EX_TOPMOST);
2162             req->ex_style = newval;
2163             break;
2164         case GWLP_ID:
2165             req->flags = SET_WIN_ID;
2166             req->id = newval;
2167             break;
2168         case GWLP_HINSTANCE:
2169             req->flags = SET_WIN_INSTANCE;
2170             req->instance = wine_server_client_ptr( (void *)newval );
2171             break;
2172         case GWLP_WNDPROC:
2173             req->flags = SET_WIN_UNICODE;
2174             req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
2175             break;
2176         case GWLP_USERDATA:
2177             req->flags = SET_WIN_USERDATA;
2178             req->user_data = newval;
2179             break;
2180         default:
2181             req->flags = SET_WIN_EXTRA;
2182             req->extra_offset = offset;
2183             req->extra_size = size;
2184             set_win_data( &req->extra_value, newval, size );
2185         }
2186         if ((ok = !wine_server_call_err( req )))
2187         {
2188             switch(offset)
2189             {
2190             case GWL_STYLE:
2191                 wndPtr->dwStyle = newval;
2192                 retval = reply->old_style;
2193                 break;
2194             case GWL_EXSTYLE:
2195                 wndPtr->dwExStyle = newval;
2196                 retval = reply->old_ex_style;
2197                 break;
2198             case GWLP_ID:
2199                 wndPtr->wIDmenu = newval;
2200                 retval = reply->old_id;
2201                 break;
2202             case GWLP_HINSTANCE:
2203                 wndPtr->hInstance = (HINSTANCE)newval;
2204                 retval = (ULONG_PTR)wine_server_get_ptr( reply->old_instance );
2205                 break;
2206             case GWLP_WNDPROC:
2207                 break;
2208             case GWLP_USERDATA:
2209                 wndPtr->userdata = newval;
2210                 retval = reply->old_user_data;
2211                 break;
2212             default:
2213                 retval = get_win_data( (char *)wndPtr->wExtra + offset, size );
2214                 set_win_data( (char *)wndPtr->wExtra + offset, newval, size );
2215                 break;
2216             }
2217         }
2218     }
2219     SERVER_END_REQ;
2220     WIN_ReleasePtr( wndPtr );
2221
2222     if (!ok) return 0;
2223
2224     if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2225     {
2226         USER_Driver->pSetWindowStyle( hwnd, offset, &style );
2227         SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2228     }
2229
2230     return retval;
2231 }
2232
2233
2234 /**********************************************************************
2235  *              GetWindowWord (USER32.@)
2236  */
2237 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
2238 {
2239     switch(offset)
2240     {
2241     case GWLP_ID:
2242     case GWLP_HINSTANCE:
2243     case GWLP_HWNDPARENT:
2244         break;
2245     default:
2246         if (offset < 0)
2247         {
2248             WARN("Invalid offset %d\n", offset );
2249             SetLastError( ERROR_INVALID_INDEX );
2250             return 0;
2251         }
2252         break;
2253     }
2254     return WIN_GetWindowLong( hwnd, offset, sizeof(WORD), FALSE );
2255 }
2256
2257
2258 /**********************************************************************
2259  *              GetWindowLongA (USER32.@)
2260  */
2261 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2262 {
2263     return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), FALSE );
2264 }
2265
2266
2267 /**********************************************************************
2268  *              GetWindowLongW (USER32.@)
2269  */
2270 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2271 {
2272     return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), TRUE );
2273 }
2274
2275
2276 /**********************************************************************
2277  *              SetWindowWord (USER32.@)
2278  */
2279 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
2280 {
2281     switch(offset)
2282     {
2283     case GWLP_ID:
2284     case GWLP_HINSTANCE:
2285     case GWLP_HWNDPARENT:
2286         break;
2287     default:
2288         if (offset < 0)
2289         {
2290             WARN("Invalid offset %d\n", offset );
2291             SetLastError( ERROR_INVALID_INDEX );
2292             return 0;
2293         }
2294         break;
2295     }
2296     return WIN_SetWindowLong( hwnd, offset, sizeof(WORD), newval, FALSE );
2297 }
2298
2299
2300 /**********************************************************************
2301  *              SetWindowLongA (USER32.@)
2302  *
2303  * See SetWindowLongW.
2304  */
2305 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2306 {
2307     return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, FALSE );
2308 }
2309
2310
2311 /**********************************************************************
2312  *              SetWindowLongW (USER32.@) Set window attribute
2313  *
2314  * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2315  * value in a window's extra memory.
2316  *
2317  * The _hwnd_ parameter specifies the window.  is the handle to a
2318  * window that has extra memory. The _newval_ parameter contains the
2319  * new attribute or extra memory value.  If positive, the _offset_
2320  * parameter is the byte-addressed location in the window's extra
2321  * memory to set.  If negative, _offset_ specifies the window
2322  * attribute to set, and should be one of the following values:
2323  *
2324  * GWL_EXSTYLE      The window's extended window style
2325  *
2326  * GWL_STYLE        The window's window style.
2327  *
2328  * GWLP_WNDPROC     Pointer to the window's window procedure.
2329  *
2330  * GWLP_HINSTANCE   The window's pplication instance handle.
2331  *
2332  * GWLP_ID          The window's identifier.
2333  *
2334  * GWLP_USERDATA    The window's user-specified data.
2335  *
2336  * If the window is a dialog box, the _offset_ parameter can be one of
2337  * the following values:
2338  *
2339  * DWLP_DLGPROC     The address of the window's dialog box procedure.
2340  *
2341  * DWLP_MSGRESULT   The return value of a message
2342  *                  that the dialog box procedure processed.
2343  *
2344  * DWLP_USER        Application specific information.
2345  *
2346  * RETURNS
2347  *
2348  * If successful, returns the previous value located at _offset_. Otherwise,
2349  * returns 0.
2350  *
2351  * NOTES
2352  *
2353  * Extra memory for a window class is specified by a nonzero cbWndExtra
2354  * parameter of the WNDCLASS structure passed to RegisterClass() at the
2355  * time of class creation.
2356  *
2357  * Using GWL_WNDPROC to set a new window procedure effectively creates
2358  * a window subclass. Use CallWindowProc() in the new windows procedure
2359  * to pass messages to the superclass's window procedure.
2360  *
2361  * The user data is reserved for use by the application which created
2362  * the window.
2363  *
2364  * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2365  * instead, call the EnableWindow() function to change the window's
2366  * disabled state.
2367  *
2368  * Do not use GWL_HWNDPARENT to reset the window's parent, use
2369  * SetParent() instead.
2370  *
2371  * Win95:
2372  * When offset is GWL_STYLE and the calling app's ver is 4.0,
2373  * it sends WM_STYLECHANGING before changing the settings
2374  * and WM_STYLECHANGED afterwards.
2375  * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2376  */
2377 LONG WINAPI SetWindowLongW(
2378     HWND hwnd,  /* [in] window to alter */
2379     INT offset, /* [in] offset, in bytes, of location to alter */
2380     LONG newval /* [in] new value of location */
2381 ) {
2382     return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, TRUE );
2383 }
2384
2385
2386 /*******************************************************************
2387  *              GetWindowTextA (USER32.@)
2388  */
2389 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2390 {
2391     WCHAR *buffer;
2392
2393     if (!lpString) return 0;
2394
2395     if (WIN_IsCurrentProcess( hwnd ))
2396         return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2397
2398     /* when window belongs to other process, don't send a message */
2399     if (nMaxCount <= 0) return 0;
2400     if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2401     get_server_window_text( hwnd, buffer, nMaxCount );
2402     if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2403         lpString[nMaxCount-1] = 0;
2404     HeapFree( GetProcessHeap(), 0, buffer );
2405     return strlen(lpString);
2406 }
2407
2408
2409 /*******************************************************************
2410  *              InternalGetWindowText (USER32.@)
2411  */
2412 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2413 {
2414     WND *win;
2415
2416     if (nMaxCount <= 0) return 0;
2417     if (!(win = WIN_GetPtr( hwnd ))) return 0;
2418     if (win == WND_DESKTOP) lpString[0] = 0;
2419     else if (win != WND_OTHER_PROCESS)
2420     {
2421         if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2422         else lpString[0] = 0;
2423         WIN_ReleasePtr( win );
2424     }
2425     else
2426     {
2427         get_server_window_text( hwnd, lpString, nMaxCount );
2428     }
2429     return strlenW(lpString);
2430 }
2431
2432
2433 /*******************************************************************
2434  *              GetWindowTextW (USER32.@)
2435  */
2436 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2437 {
2438     if (!lpString) return 0;
2439
2440     if (WIN_IsCurrentProcess( hwnd ))
2441         return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2442
2443     /* when window belongs to other process, don't send a message */
2444     if (nMaxCount <= 0) return 0;
2445     get_server_window_text( hwnd, lpString, nMaxCount );
2446     return strlenW(lpString);
2447 }
2448
2449
2450 /*******************************************************************
2451  *              SetWindowTextA (USER32.@)
2452  *              SetWindowText  (USER32.@)
2453  */
2454 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2455 {
2456     if (is_broadcast(hwnd))
2457     {
2458         SetLastError( ERROR_INVALID_PARAMETER );
2459         return FALSE;
2460     }
2461     if (!WIN_IsCurrentProcess( hwnd ))
2462         WARN( "setting text %s of other process window %p should not use SendMessage\n",
2463                debugstr_a(lpString), hwnd );
2464     return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2465 }
2466
2467
2468 /*******************************************************************
2469  *              SetWindowTextW (USER32.@)
2470  */
2471 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2472 {
2473     if (is_broadcast(hwnd))
2474     {
2475         SetLastError( ERROR_INVALID_PARAMETER );
2476         return FALSE;
2477     }
2478     if (!WIN_IsCurrentProcess( hwnd ))
2479         WARN( "setting text %s of other process window %p should not use SendMessage\n",
2480                debugstr_w(lpString), hwnd );
2481     return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2482 }
2483
2484
2485 /*******************************************************************
2486  *              GetWindowTextLengthA (USER32.@)
2487  */
2488 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2489 {
2490     return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2491 }
2492
2493 /*******************************************************************
2494  *              GetWindowTextLengthW (USER32.@)
2495  */
2496 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2497 {
2498     return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2499 }
2500
2501
2502 /*******************************************************************
2503  *              IsWindow (USER32.@)
2504  */
2505 BOOL WINAPI IsWindow( HWND hwnd )
2506 {
2507     WND *ptr;
2508     BOOL ret;
2509
2510     if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2511     if (ptr == WND_DESKTOP) return TRUE;
2512
2513     if (ptr != WND_OTHER_PROCESS)
2514     {
2515         WIN_ReleasePtr( ptr );
2516         return TRUE;
2517     }
2518
2519     /* check other processes */
2520     SERVER_START_REQ( get_window_info )
2521     {
2522         req->handle = wine_server_user_handle( hwnd );
2523         ret = !wine_server_call_err( req );
2524     }
2525     SERVER_END_REQ;
2526     return ret;
2527 }
2528
2529
2530 /***********************************************************************
2531  *              GetWindowThreadProcessId (USER32.@)
2532  */
2533 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2534 {
2535     WND *ptr;
2536     DWORD tid = 0;
2537
2538     if (!(ptr = WIN_GetPtr( hwnd )))
2539     {
2540         SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2541         return 0;
2542     }
2543
2544     if (ptr != WND_OTHER_PROCESS && ptr != WND_DESKTOP)
2545     {
2546         /* got a valid window */
2547         tid = ptr->tid;
2548         if (process) *process = GetCurrentProcessId();
2549         WIN_ReleasePtr( ptr );
2550         return tid;
2551     }
2552
2553     /* check other processes */
2554     SERVER_START_REQ( get_window_info )
2555     {
2556         req->handle = wine_server_user_handle( hwnd );
2557         if (!wine_server_call_err( req ))
2558         {
2559             tid = (DWORD)reply->tid;
2560             if (process) *process = (DWORD)reply->pid;
2561         }
2562     }
2563     SERVER_END_REQ;
2564     return tid;
2565 }
2566
2567
2568 /*****************************************************************
2569  *              GetParent (USER32.@)
2570  */
2571 HWND WINAPI GetParent( HWND hwnd )
2572 {
2573     WND *wndPtr;
2574     HWND retvalue = 0;
2575
2576     if (!(wndPtr = WIN_GetPtr( hwnd )))
2577     {
2578         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2579         return 0;
2580     }
2581     if (wndPtr == WND_DESKTOP) return 0;
2582     if (wndPtr == WND_OTHER_PROCESS)
2583     {
2584         LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2585         if (style & (WS_POPUP | WS_CHILD))
2586         {
2587             SERVER_START_REQ( get_window_tree )
2588             {
2589                 req->handle = wine_server_user_handle( hwnd );
2590                 if (!wine_server_call_err( req ))
2591                 {
2592                     if (style & WS_POPUP) retvalue = wine_server_ptr_handle( reply->owner );
2593                     else if (style & WS_CHILD) retvalue = wine_server_ptr_handle( reply->parent );
2594                 }
2595             }
2596             SERVER_END_REQ;
2597         }
2598     }
2599     else
2600     {
2601         if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2602         else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2603         WIN_ReleasePtr( wndPtr );
2604     }
2605     return retvalue;
2606 }
2607
2608
2609 /*****************************************************************
2610  *              GetAncestor (USER32.@)
2611  */
2612 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2613 {
2614     WND *win;
2615     HWND *list, ret = 0;
2616
2617     switch(type)
2618     {
2619     case GA_PARENT:
2620         if (!(win = WIN_GetPtr( hwnd )))
2621         {
2622             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2623             return 0;
2624         }
2625         if (win == WND_DESKTOP) return 0;
2626         if (win != WND_OTHER_PROCESS)
2627         {
2628             ret = win->parent;
2629             WIN_ReleasePtr( win );
2630         }
2631         else /* need to query the server */
2632         {
2633             SERVER_START_REQ( get_window_tree )
2634             {
2635                 req->handle = wine_server_user_handle( hwnd );
2636                 if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->parent );
2637             }
2638             SERVER_END_REQ;
2639         }
2640         break;
2641
2642     case GA_ROOT:
2643         if (!(list = list_window_parents( hwnd ))) return 0;
2644
2645         if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd );  /* top-level window */
2646         else
2647         {
2648             int count = 2;
2649             while (list[count]) count++;
2650             ret = list[count - 2];  /* get the one before the desktop */
2651         }
2652         HeapFree( GetProcessHeap(), 0, list );
2653         break;
2654
2655     case GA_ROOTOWNER:
2656         if (is_desktop_window( hwnd )) return 0;
2657         ret = WIN_GetFullHandle( hwnd );
2658         for (;;)
2659         {
2660             HWND parent = GetParent( ret );
2661             if (!parent) break;
2662             ret = parent;
2663         }
2664         break;
2665     }
2666     return ret;
2667 }
2668
2669
2670 /*****************************************************************
2671  *              SetParent (USER32.@)
2672  */
2673 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2674 {
2675     HWND full_handle;
2676     HWND old_parent = 0;
2677     BOOL was_visible;
2678     WND *wndPtr;
2679     BOOL ret;
2680
2681     if (is_broadcast(hwnd) || is_broadcast(parent))
2682     {
2683         SetLastError(ERROR_INVALID_PARAMETER);
2684         return 0;
2685     }
2686
2687     if (!parent) parent = GetDesktopWindow();
2688     else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
2689     else parent = WIN_GetFullHandle( parent );
2690
2691     if (!IsWindow( parent ))
2692     {
2693         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2694         return 0;
2695     }
2696
2697     /* Some applications try to set a child as a parent */
2698     if (IsChild(hwnd, parent))
2699     {
2700         SetLastError( ERROR_INVALID_PARAMETER );
2701         return 0;
2702     }
2703
2704     if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2705         return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2706
2707     /* Windows hides the window first, then shows it again
2708      * including the WM_SHOWWINDOW messages and all */
2709     was_visible = ShowWindow( hwnd, SW_HIDE );
2710
2711     wndPtr = WIN_GetPtr( hwnd );
2712     if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
2713
2714     SERVER_START_REQ( set_parent )
2715     {
2716         req->handle = wine_server_user_handle( hwnd );
2717         req->parent = wine_server_user_handle( parent );
2718         if ((ret = !wine_server_call( req )))
2719         {
2720             old_parent = wine_server_ptr_handle( reply->old_parent );
2721             wndPtr->parent = parent = wine_server_ptr_handle( reply->full_parent );
2722         }
2723
2724     }
2725     SERVER_END_REQ;
2726     WIN_ReleasePtr( wndPtr );
2727     if (!ret) return 0;
2728
2729     USER_Driver->pSetParent( full_handle, parent, old_parent );
2730
2731     /* SetParent additionally needs to make hwnd the topmost window
2732        in the x-order and send the expected WM_WINDOWPOSCHANGING and
2733        WM_WINDOWPOSCHANGED notification messages.
2734     */
2735     SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0,
2736                   SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | (was_visible ? SWP_SHOWWINDOW : 0) );
2737     /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
2738      * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
2739
2740     return old_parent;
2741 }
2742
2743
2744 /*******************************************************************
2745  *              IsChild (USER32.@)
2746  */
2747 BOOL WINAPI IsChild( HWND parent, HWND child )
2748 {
2749     HWND *list = list_window_parents( child );
2750     int i;
2751     BOOL ret;
2752
2753     if (!list) return FALSE;
2754     parent = WIN_GetFullHandle( parent );
2755     for (i = 0; list[i]; i++) if (list[i] == parent) break;
2756     ret = list[i] && list[i+1];
2757     HeapFree( GetProcessHeap(), 0, list );
2758     return ret;
2759 }
2760
2761
2762 /***********************************************************************
2763  *              IsWindowVisible (USER32.@)
2764  */
2765 BOOL WINAPI IsWindowVisible( HWND hwnd )
2766 {
2767     HWND *list;
2768     BOOL retval = TRUE;
2769     int i;
2770
2771     if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2772     if (!(list = list_window_parents( hwnd ))) return TRUE;
2773     if (list[0])
2774     {
2775         for (i = 0; list[i+1]; i++)
2776             if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2777         retval = !list[i+1] && (list[i] == GetDesktopWindow());  /* top message window isn't visible */
2778     }
2779     HeapFree( GetProcessHeap(), 0, list );
2780     return retval;
2781 }
2782
2783
2784 /***********************************************************************
2785  *           WIN_IsWindowDrawable
2786  *
2787  * hwnd is drawable when it is visible, all parents are not
2788  * minimized, and it is itself not minimized unless we are
2789  * trying to draw its default class icon.
2790  */
2791 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2792 {
2793     HWND *list;
2794     BOOL retval = TRUE;
2795     int i;
2796     LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2797
2798     if (!(style & WS_VISIBLE)) return FALSE;
2799     if ((style & WS_MINIMIZE) && icon && GetClassLongPtrW( hwnd, GCLP_HICON ))  return FALSE;
2800
2801     if (!(list = list_window_parents( hwnd ))) return TRUE;
2802     if (list[0])
2803     {
2804         for (i = 0; list[i+1]; i++)
2805             if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2806                 break;
2807         retval = !list[i+1] && (list[i] == GetDesktopWindow());  /* top message window isn't visible */
2808     }
2809     HeapFree( GetProcessHeap(), 0, list );
2810     return retval;
2811 }
2812
2813
2814 /*******************************************************************
2815  *              GetTopWindow (USER32.@)
2816  */
2817 HWND WINAPI GetTopWindow( HWND hwnd )
2818 {
2819     if (!hwnd) hwnd = GetDesktopWindow();
2820     return GetWindow( hwnd, GW_CHILD );
2821 }
2822
2823
2824 /*******************************************************************
2825  *              GetWindow (USER32.@)
2826  */
2827 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2828 {
2829     HWND retval = 0;
2830
2831     if (rel == GW_OWNER)  /* this one may be available locally */
2832     {
2833         WND *wndPtr = WIN_GetPtr( hwnd );
2834         if (!wndPtr)
2835         {
2836             SetLastError( ERROR_INVALID_HANDLE );
2837             return 0;
2838         }
2839         if (wndPtr == WND_DESKTOP) return 0;
2840         if (wndPtr != WND_OTHER_PROCESS)
2841         {
2842             retval = wndPtr->owner;
2843             WIN_ReleasePtr( wndPtr );
2844             return retval;
2845         }
2846         /* else fall through to server call */
2847     }
2848
2849     SERVER_START_REQ( get_window_tree )
2850     {
2851         req->handle = wine_server_user_handle( hwnd );
2852         if (!wine_server_call_err( req ))
2853         {
2854             switch(rel)
2855             {
2856             case GW_HWNDFIRST:
2857                 retval = wine_server_ptr_handle( reply->first_sibling );
2858                 break;
2859             case GW_HWNDLAST:
2860                 retval = wine_server_ptr_handle( reply->last_sibling );
2861                 break;
2862             case GW_HWNDNEXT:
2863                 retval = wine_server_ptr_handle( reply->next_sibling );
2864                 break;
2865             case GW_HWNDPREV:
2866                 retval = wine_server_ptr_handle( reply->prev_sibling );
2867                 break;
2868             case GW_OWNER:
2869                 retval = wine_server_ptr_handle( reply->owner );
2870                 break;
2871             case GW_CHILD:
2872                 retval = wine_server_ptr_handle( reply->first_child );
2873                 break;
2874             }
2875         }
2876     }
2877     SERVER_END_REQ;
2878     return retval;
2879 }
2880
2881
2882 /*******************************************************************
2883  *              ShowOwnedPopups (USER32.@)
2884  */
2885 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2886 {
2887     int count = 0;
2888     WND *pWnd;
2889     HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2890
2891     if (!win_array) return TRUE;
2892
2893     while (win_array[count]) count++;
2894     while (--count >= 0)
2895     {
2896         if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2897         if (!(pWnd = WIN_GetPtr( win_array[count] ))) continue;
2898         if (pWnd == WND_OTHER_PROCESS) continue;
2899         if (fShow)
2900         {
2901             if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2902             {
2903                 WIN_ReleasePtr( pWnd );
2904                 /* In Windows, ShowOwnedPopups(TRUE) generates
2905                  * WM_SHOWWINDOW messages with SW_PARENTOPENING,
2906                  * regardless of the state of the owner
2907                  */
2908                 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
2909                 continue;
2910             }
2911         }
2912         else
2913         {
2914             if (pWnd->dwStyle & WS_VISIBLE)
2915             {
2916                 WIN_ReleasePtr( pWnd );
2917                 /* In Windows, ShowOwnedPopups(FALSE) generates
2918                  * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
2919                  * regardless of the state of the owner
2920                  */
2921                 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
2922                 continue;
2923             }
2924         }
2925         WIN_ReleasePtr( pWnd );
2926     }
2927     HeapFree( GetProcessHeap(), 0, win_array );
2928     return TRUE;
2929 }
2930
2931
2932 /*******************************************************************
2933  *              GetLastActivePopup (USER32.@)
2934  */
2935 HWND WINAPI GetLastActivePopup( HWND hwnd )
2936 {
2937     HWND retval = hwnd;
2938
2939     SERVER_START_REQ( get_window_info )
2940     {
2941         req->handle = wine_server_user_handle( hwnd );
2942         if (!wine_server_call_err( req )) retval = wine_server_ptr_handle( reply->last_active );
2943     }
2944     SERVER_END_REQ;
2945     return retval;
2946 }
2947
2948
2949 /*******************************************************************
2950  *           WIN_ListChildren
2951  *
2952  * Build an array of the children of a given window. The array must be
2953  * freed with HeapFree. Returns NULL when no windows are found.
2954  */
2955 HWND *WIN_ListChildren( HWND hwnd )
2956 {
2957     if (!hwnd)
2958     {
2959         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2960         return NULL;
2961     }
2962     return list_window_children( 0, hwnd, NULL, 0 );
2963 }
2964
2965
2966 /*******************************************************************
2967  *              EnumWindows (USER32.@)
2968  */
2969 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
2970 {
2971     HWND *list;
2972     BOOL ret = TRUE;
2973     int i;
2974
2975     USER_CheckNotLock();
2976
2977     /* We have to build a list of all windows first, to avoid */
2978     /* unpleasant side-effects, for instance if the callback */
2979     /* function changes the Z-order of the windows.          */
2980
2981     if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
2982
2983     /* Now call the callback function for every window */
2984
2985     for (i = 0; list[i]; i++)
2986     {
2987         /* Make sure that the window still exists */
2988         if (!IsWindow( list[i] )) continue;
2989         if (!(ret = lpEnumFunc( list[i], lParam ))) break;
2990     }
2991     HeapFree( GetProcessHeap(), 0, list );
2992     return ret;
2993 }
2994
2995
2996 /**********************************************************************
2997  *              EnumThreadWindows (USER32.@)
2998  */
2999 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
3000 {
3001     HWND *list;
3002     int i;
3003     BOOL ret = TRUE;
3004
3005     USER_CheckNotLock();
3006
3007     if (!(list = list_window_children( 0, GetDesktopWindow(), NULL, id ))) return TRUE;
3008
3009     /* Now call the callback function for every window */
3010
3011     for (i = 0; list[i]; i++)
3012         if (!(ret = func( list[i], lParam ))) break;
3013     HeapFree( GetProcessHeap(), 0, list );
3014     return ret;
3015 }
3016
3017
3018 /***********************************************************************
3019  *              EnumDesktopWindows   (USER32.@)
3020  */
3021 BOOL WINAPI EnumDesktopWindows( HDESK desktop, WNDENUMPROC func, LPARAM lparam )
3022 {
3023     HWND *list;
3024     int i;
3025
3026     USER_CheckNotLock();
3027
3028     if (!(list = list_window_children( desktop, 0, NULL, 0 ))) return TRUE;
3029
3030     for (i = 0; list[i]; i++)
3031         if (!func( list[i], lparam )) break;
3032     HeapFree( GetProcessHeap(), 0, list );
3033     return TRUE;
3034 }
3035
3036
3037 /**********************************************************************
3038  *           WIN_EnumChildWindows
3039  *
3040  * Helper function for EnumChildWindows().
3041  */
3042 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
3043 {
3044     HWND *childList;
3045     BOOL ret = FALSE;
3046
3047     for ( ; *list; list++)
3048     {
3049         /* Make sure that the window still exists */
3050         if (!IsWindow( *list )) continue;
3051         /* Build children list first */
3052         childList = WIN_ListChildren( *list );
3053
3054         ret = func( *list, lParam );
3055
3056         if (childList)
3057         {
3058             if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
3059             HeapFree( GetProcessHeap(), 0, childList );
3060         }
3061         if (!ret) return FALSE;
3062     }
3063     return TRUE;
3064 }
3065
3066
3067 /**********************************************************************
3068  *              EnumChildWindows (USER32.@)
3069  */
3070 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
3071 {
3072     HWND *list;
3073     BOOL ret;
3074
3075     USER_CheckNotLock();
3076
3077     if (!(list = WIN_ListChildren( parent ))) return FALSE;
3078     ret = WIN_EnumChildWindows( list, func, lParam );
3079     HeapFree( GetProcessHeap(), 0, list );
3080     return ret;
3081 }
3082
3083
3084 /*******************************************************************
3085  *              AnyPopup (USER32.@)
3086  */
3087 BOOL WINAPI AnyPopup(void)
3088 {
3089     int i;
3090     BOOL retvalue;
3091     HWND *list = WIN_ListChildren( GetDesktopWindow() );
3092
3093     if (!list) return FALSE;
3094     for (i = 0; list[i]; i++)
3095     {
3096         if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
3097     }
3098     retvalue = (list[i] != 0);
3099     HeapFree( GetProcessHeap(), 0, list );
3100     return retvalue;
3101 }
3102
3103
3104 /*******************************************************************
3105  *              FlashWindow (USER32.@)
3106  */
3107 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3108 {
3109     WND *wndPtr;
3110
3111     TRACE("%p\n", hWnd);
3112
3113     if (IsIconic( hWnd ))
3114     {
3115         RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
3116
3117         wndPtr = WIN_GetPtr(hWnd);
3118         if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3119         if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
3120         {
3121             wndPtr->flags |= WIN_NCACTIVATED;
3122         }
3123         else
3124         {
3125             wndPtr->flags &= ~WIN_NCACTIVATED;
3126         }
3127         WIN_ReleasePtr( wndPtr );
3128         return TRUE;
3129     }
3130     else
3131     {
3132         WPARAM wparam;
3133
3134         wndPtr = WIN_GetPtr(hWnd);
3135         if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3136         hWnd = wndPtr->obj.handle;  /* make it a full handle */
3137
3138         if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3139         else wparam = (hWnd == GetForegroundWindow());
3140
3141         WIN_ReleasePtr( wndPtr );
3142         SendMessageW( hWnd, WM_NCACTIVATE, wparam, 0 );
3143         return wparam;
3144     }
3145 }
3146
3147 /*******************************************************************
3148  *              FlashWindowEx (USER32.@)
3149  */
3150 BOOL WINAPI FlashWindowEx( PFLASHWINFO pfwi )
3151 {
3152     FIXME("%p\n", pfwi);
3153     return TRUE;
3154 }
3155
3156 /*******************************************************************
3157  *              GetWindowContextHelpId (USER32.@)
3158  */
3159 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3160 {
3161     DWORD retval;
3162     WND *wnd = WIN_GetPtr( hwnd );
3163     if (!wnd || wnd == WND_DESKTOP) return 0;
3164     if (wnd == WND_OTHER_PROCESS)
3165     {
3166         if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3167         return 0;
3168     }
3169     retval = wnd->helpContext;
3170     WIN_ReleasePtr( wnd );
3171     return retval;
3172 }
3173
3174
3175 /*******************************************************************
3176  *              SetWindowContextHelpId (USER32.@)
3177  */
3178 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3179 {
3180     WND *wnd = WIN_GetPtr( hwnd );
3181     if (!wnd || wnd == WND_DESKTOP) return FALSE;
3182     if (wnd == WND_OTHER_PROCESS)
3183     {
3184         if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3185         return 0;
3186     }
3187     wnd->helpContext = id;
3188     WIN_ReleasePtr( wnd );
3189     return TRUE;
3190 }
3191
3192
3193 /*******************************************************************
3194  *              DragDetect (USER32.@)
3195  */
3196 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3197 {
3198     MSG msg;
3199     RECT rect;
3200     WORD wDragWidth = GetSystemMetrics(SM_CXDRAG);
3201     WORD wDragHeight= GetSystemMetrics(SM_CYDRAG);
3202
3203     rect.left = pt.x - wDragWidth;
3204     rect.right = pt.x + wDragWidth;
3205
3206     rect.top = pt.y - wDragHeight;
3207     rect.bottom = pt.y + wDragHeight;
3208
3209     SetCapture(hWnd);
3210
3211     while(1)
3212     {
3213         while (PeekMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ))
3214         {
3215             if( msg.message == WM_LBUTTONUP )
3216             {
3217                 ReleaseCapture();
3218                 return 0;
3219             }
3220             if( msg.message == WM_MOUSEMOVE )
3221             {
3222                 POINT tmp;
3223                 tmp.x = (short)LOWORD(msg.lParam);
3224                 tmp.y = (short)HIWORD(msg.lParam);
3225                 if( !PtInRect( &rect, tmp ))
3226                 {
3227                     ReleaseCapture();
3228                     return 1;
3229                 }
3230             }
3231         }
3232         WaitMessage();
3233     }
3234     return 0;
3235 }
3236
3237 /******************************************************************************
3238  *              GetWindowModuleFileNameA (USER32.@)
3239  */
3240 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR module, UINT size )
3241 {
3242     WND *win;
3243     HINSTANCE hinst;
3244
3245     TRACE( "%p, %p, %u\n", hwnd, module, size );
3246
3247     win = WIN_GetPtr( hwnd );
3248     if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3249     {
3250         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3251         return 0;
3252     }
3253     hinst = win->hInstance;
3254     WIN_ReleasePtr( win );
3255
3256     return GetModuleFileNameA( hinst, module, size );
3257 }
3258
3259 /******************************************************************************
3260  *              GetWindowModuleFileNameW (USER32.@)
3261  */
3262 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR module, UINT size )
3263 {
3264     WND *win;
3265     HINSTANCE hinst;
3266
3267     TRACE( "%p, %p, %u\n", hwnd, module, size );
3268
3269     win = WIN_GetPtr( hwnd );
3270     if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3271     {
3272         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3273         return 0;
3274     }
3275     hinst = win->hInstance;
3276     WIN_ReleasePtr( win );
3277
3278     return GetModuleFileNameW( hinst, module, size );
3279 }
3280
3281 /******************************************************************************
3282  *              GetWindowInfo (USER32.@)
3283  *
3284  * Note: tests show that Windows doesn't check cbSize of the structure.
3285  */
3286 BOOL WINAPI GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3287 {
3288     if (!pwi) return FALSE;
3289     if (!IsWindow(hwnd)) return FALSE;
3290
3291     GetWindowRect(hwnd, &pwi->rcWindow);
3292     GetClientRect(hwnd, &pwi->rcClient);
3293     /* translate to screen coordinates */
3294     MapWindowPoints(hwnd, 0, (LPPOINT)&pwi->rcClient, 2);
3295
3296     pwi->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
3297     pwi->dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3298     pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3299
3300     pwi->cxWindowBorders = pwi->rcClient.left - pwi->rcWindow.left;
3301     pwi->cyWindowBorders = pwi->rcWindow.bottom - pwi->rcClient.bottom;
3302
3303     pwi->atomWindowType = GetClassLongW( hwnd, GCW_ATOM );
3304     pwi->wCreatorVersion = 0x0400;
3305
3306     return TRUE;
3307 }
3308
3309 /******************************************************************************
3310  *              SwitchDesktop (USER32.@)
3311  *
3312  * NOTES: Sets the current input or interactive desktop.
3313  */
3314 BOOL WINAPI SwitchDesktop( HDESK hDesktop)
3315 {
3316     FIXME("SwitchDesktop(hwnd %p) stub!\n", hDesktop);
3317     return TRUE;
3318 }
3319
3320 /*****************************************************************************
3321  *              SetLayeredWindowAttributes (USER32.@)
3322  */
3323 BOOL WINAPI SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, DWORD flags )
3324 {
3325     BOOL ret;
3326
3327     TRACE("(%p,%08x,%d,%x): stub!\n", hwnd, key, alpha, flags);
3328
3329     SERVER_START_REQ( set_window_layered_info )
3330     {
3331         req->handle = wine_server_user_handle( hwnd );
3332         req->color_key = key;
3333         req->alpha = alpha;
3334         req->flags = flags;
3335         ret = !wine_server_call_err( req );
3336     }
3337     SERVER_END_REQ;
3338
3339     if (ret) USER_Driver->pSetLayeredWindowAttributes( hwnd, key, alpha, flags );
3340
3341     return ret;
3342 }
3343
3344
3345 /*****************************************************************************
3346  *              GetLayeredWindowAttributes (USER32.@)
3347  */
3348 BOOL WINAPI GetLayeredWindowAttributes( HWND hwnd, COLORREF *key, BYTE *alpha, DWORD *flags )
3349 {
3350     BOOL ret;
3351
3352     SERVER_START_REQ( get_window_layered_info )
3353     {
3354         req->handle = wine_server_user_handle( hwnd );
3355         if ((ret = !wine_server_call_err( req )))
3356         {
3357             if (key) *key = reply->color_key;
3358             if (alpha) *alpha = reply->alpha;
3359             if (flags) *flags = reply->flags;
3360         }
3361     }
3362     SERVER_END_REQ;
3363
3364     return ret;
3365 }
3366
3367
3368 /*****************************************************************************
3369  *              UpdateLayeredWindowIndirect  (USER32.@)
3370  */
3371 BOOL WINAPI UpdateLayeredWindowIndirect( HWND hwnd, const UPDATELAYEREDWINDOWINFO *info )
3372 {
3373     BYTE alpha = 0xff;
3374
3375     if (!(info->dwFlags & ULW_EX_NORESIZE) && (info->pptDst || info->psize))
3376     {
3377         int x = 0, y = 0, cx = 0, cy = 0;
3378         DWORD flags = SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOSENDCHANGING;
3379
3380         if (info->pptDst)
3381         {
3382             x = info->pptDst->x;
3383             y = info->pptDst->y;
3384             flags &= ~SWP_NOMOVE;
3385         }
3386         if (info->psize)
3387         {
3388             cx = info->psize->cx;
3389             cy = info->psize->cy;
3390             flags &= ~SWP_NOSIZE;
3391         }
3392         TRACE( "moving window %p pos %d,%d %dx%x\n", hwnd, x, y, cx, cy );
3393         SetWindowPos( hwnd, 0, x, y, cx, cy, flags );
3394     }
3395
3396     if (info->hdcSrc)
3397     {
3398         RECT rect;
3399         HDC hdc = GetDCEx( hwnd, 0, DCX_CACHE );
3400
3401         if (hdc)
3402         {
3403             int x = 0, y = 0;
3404
3405             GetClientRect( hwnd, &rect );
3406             if (info->pptSrc)
3407             {
3408                 x = info->pptSrc->x;
3409                 y = info->pptSrc->y;
3410             }
3411             /* FIXME: intersect rect with info->prcDirty */
3412             TRACE( "copying window %p pos %d,%d\n", hwnd, x, y );
3413             BitBlt( hdc, rect.left, rect.top, rect.right, rect.bottom,
3414                     info->hdcSrc, rect.left + x, rect.top + y, SRCCOPY );
3415             ReleaseDC( hwnd, hdc );
3416         }
3417     }
3418
3419     if (info->pblend && !(info->dwFlags & ULW_OPAQUE)) alpha = info->pblend->SourceConstantAlpha;
3420     TRACE( "setting window %p alpha %u\n", hwnd, alpha );
3421     USER_Driver->pSetLayeredWindowAttributes( hwnd, info->crKey, alpha,
3422                                               info->dwFlags & (LWA_ALPHA | LWA_COLORKEY) );
3423     return TRUE;
3424 }
3425
3426
3427 /*****************************************************************************
3428  *              UpdateLayeredWindow (USER32.@)
3429  */
3430 BOOL WINAPI UpdateLayeredWindow( HWND hwnd, HDC hdcDst, POINT *pptDst, SIZE *psize,
3431                                  HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend,
3432                                  DWORD dwFlags)
3433 {
3434     UPDATELAYEREDWINDOWINFO info;
3435
3436     info.cbSize   = sizeof(info);
3437     info.hdcDst   = hdcDst;
3438     info.pptDst   = pptDst;
3439     info.psize    = psize;
3440     info.hdcSrc   = hdcSrc;
3441     info.pptSrc   = pptSrc;
3442     info.crKey    = crKey;
3443     info.pblend   = pblend;
3444     info.dwFlags  = dwFlags;
3445     info.prcDirty = NULL;
3446     return UpdateLayeredWindowIndirect( hwnd, &info );
3447 }
3448
3449 /* 64bit versions */
3450
3451 #ifdef GetWindowLongPtrW
3452 #undef GetWindowLongPtrW
3453 #endif
3454
3455 #ifdef GetWindowLongPtrA
3456 #undef GetWindowLongPtrA
3457 #endif
3458
3459 #ifdef SetWindowLongPtrW
3460 #undef SetWindowLongPtrW
3461 #endif
3462
3463 #ifdef SetWindowLongPtrA
3464 #undef SetWindowLongPtrA
3465 #endif
3466
3467 /*****************************************************************************
3468  *              GetWindowLongPtrW (USER32.@)
3469  */
3470 LONG_PTR WINAPI GetWindowLongPtrW( HWND hwnd, INT offset )
3471 {
3472     return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), TRUE );
3473 }
3474
3475 /*****************************************************************************
3476  *              GetWindowLongPtrA (USER32.@)
3477  */
3478 LONG_PTR WINAPI GetWindowLongPtrA( HWND hwnd, INT offset )
3479 {
3480     return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), FALSE );
3481 }
3482
3483 /*****************************************************************************
3484  *              SetWindowLongPtrW (USER32.@)
3485  */
3486 LONG_PTR WINAPI SetWindowLongPtrW( HWND hwnd, INT offset, LONG_PTR newval )
3487 {
3488     return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, TRUE );
3489 }
3490
3491 /*****************************************************************************
3492  *              SetWindowLongPtrA (USER32.@)
3493  */
3494 LONG_PTR WINAPI SetWindowLongPtrA( HWND hwnd, INT offset, LONG_PTR newval )
3495 {
3496     return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, FALSE );
3497 }