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