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