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