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