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