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