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