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