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