hlink: Site data should only be set if the hlink has an HlinkSite.
[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     if (GetGUIThreadInfo( GetCurrentThreadId(), &info ))
1591     {
1592         if (hwnd == info.hwndCaret) DestroyCaret();
1593         if (hwnd == info.hwndActive) WINPOS_ActivateOtherWindow( hwnd );
1594     }
1595
1596     /*
1597      * Send the WM_DESTROY to the window.
1598      */
1599     SendMessageW( hwnd, WM_DESTROY, 0, 0);
1600
1601     /*
1602      * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1603      * make sure that the window still exists when we come back.
1604      */
1605     if (IsWindow(hwnd))
1606     {
1607         HWND* pWndArray;
1608         int i;
1609
1610         if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1611
1612         for (i = 0; pWndArray[i]; i++)
1613         {
1614             if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1615         }
1616         HeapFree( GetProcessHeap(), 0, pWndArray );
1617     }
1618     else
1619       WARN("\tdestroyed itself while in WM_DESTROY!\n");
1620 }
1621
1622
1623 /***********************************************************************
1624  *              DestroyWindow (USER32.@)
1625  */
1626 BOOL WINAPI DestroyWindow( HWND hwnd )
1627 {
1628     BOOL is_child;
1629
1630     if (!(hwnd = WIN_IsCurrentThread( hwnd )) || is_desktop_window( hwnd ))
1631     {
1632         SetLastError( ERROR_ACCESS_DENIED );
1633         return FALSE;
1634     }
1635
1636     TRACE("(%p)\n", hwnd);
1637
1638       /* Call hooks */
1639
1640     if (HOOK_CallHooks( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0, TRUE )) return FALSE;
1641
1642     if (MENU_IsMenuActive() == hwnd)
1643         EndMenu();
1644
1645     is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;
1646
1647     if (is_child)
1648     {
1649         if (!USER_IsExitingThread( GetCurrentThreadId() ))
1650             send_parent_notify( hwnd, WM_DESTROY );
1651     }
1652     else if (!GetWindow( hwnd, GW_OWNER ))
1653     {
1654         HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
1655         /* FIXME: clean up palette - see "Internals" p.352 */
1656     }
1657
1658     if (!IsWindow(hwnd)) return TRUE;
1659
1660       /* Hide the window */
1661     if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)
1662     {
1663         /* Only child windows receive WM_SHOWWINDOW in DestroyWindow() */
1664         if (is_child)
1665             ShowWindow( hwnd, SW_HIDE );
1666         else
1667             SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE |
1668                           SWP_NOZORDER | SWP_NOACTIVATE | SWP_HIDEWINDOW );
1669     }
1670
1671     if (!IsWindow(hwnd)) return TRUE;
1672
1673       /* Recursively destroy owned windows */
1674
1675     if (!is_child)
1676     {
1677         for (;;)
1678         {
1679             int i, got_one = 0;
1680             HWND *list = WIN_ListChildren( GetDesktopWindow() );
1681             if (list)
1682             {
1683                 for (i = 0; list[i]; i++)
1684                 {
1685                     if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1686                     if (WIN_IsCurrentThread( list[i] ))
1687                     {
1688                         DestroyWindow( list[i] );
1689                         got_one = 1;
1690                         continue;
1691                     }
1692                     WIN_SetOwner( list[i], 0 );
1693                 }
1694                 HeapFree( GetProcessHeap(), 0, list );
1695             }
1696             if (!got_one) break;
1697         }
1698     }
1699
1700       /* Send destroy messages */
1701
1702     WIN_SendDestroyMsg( hwnd );
1703     if (!IsWindow( hwnd )) return TRUE;
1704
1705     if (GetClipboardOwner() == hwnd)
1706         CLIPBOARD_ReleaseOwner();
1707
1708       /* Destroy the window storage */
1709
1710     WIN_DestroyWindow( hwnd );
1711     return TRUE;
1712 }
1713
1714
1715 /***********************************************************************
1716  *              CloseWindow (USER32.@)
1717  */
1718 BOOL WINAPI CloseWindow( HWND hwnd )
1719 {
1720     if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1721     ShowWindow( hwnd, SW_MINIMIZE );
1722     return TRUE;
1723 }
1724
1725
1726 /***********************************************************************
1727  *              OpenIcon (USER32.@)
1728  */
1729 BOOL WINAPI OpenIcon( HWND hwnd )
1730 {
1731     if (!IsIconic( hwnd )) return FALSE;
1732     ShowWindow( hwnd, SW_SHOWNORMAL );
1733     return TRUE;
1734 }
1735
1736
1737 /***********************************************************************
1738  *              FindWindowExW (USER32.@)
1739  */
1740 HWND WINAPI FindWindowExW( HWND parent, HWND child, LPCWSTR className, LPCWSTR title )
1741 {
1742     HWND *list = NULL;
1743     HWND retvalue = 0;
1744     int i = 0, len = 0;
1745     WCHAR *buffer = NULL;
1746
1747     if (!parent && child) parent = GetDesktopWindow();
1748     else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
1749
1750     if (title)
1751     {
1752         len = strlenW(title) + 1;  /* one extra char to check for chars beyond the end */
1753         if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1754     }
1755
1756     if (!(list = list_window_children( 0, parent, className, 0 ))) goto done;
1757
1758     if (child)
1759     {
1760         child = WIN_GetFullHandle( child );
1761         while (list[i] && list[i] != child) i++;
1762         if (!list[i]) goto done;
1763         i++;  /* start from next window */
1764     }
1765
1766     if (title)
1767     {
1768         while (list[i])
1769         {
1770             if (GetWindowTextW( list[i], buffer, len + 1 ))
1771             {
1772                 if (!strcmpiW( buffer, title )) break;
1773             }
1774             else
1775             {
1776                 if (!title[0]) break;
1777             }
1778             i++;
1779         }
1780     }
1781     retvalue = list[i];
1782
1783  done:
1784     HeapFree( GetProcessHeap(), 0, list );
1785     HeapFree( GetProcessHeap(), 0, buffer );
1786     return retvalue;
1787 }
1788
1789
1790
1791 /***********************************************************************
1792  *              FindWindowA (USER32.@)
1793  */
1794 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1795 {
1796     HWND ret = FindWindowExA( 0, 0, className, title );
1797     if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1798     return ret;
1799 }
1800
1801
1802 /***********************************************************************
1803  *              FindWindowExA (USER32.@)
1804  */
1805 HWND WINAPI FindWindowExA( HWND parent, HWND child, LPCSTR className, LPCSTR title )
1806 {
1807     LPWSTR titleW = NULL;
1808     HWND hwnd = 0;
1809
1810     if (title)
1811     {
1812         DWORD len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
1813         if (!(titleW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
1814         MultiByteToWideChar( CP_ACP, 0, title, -1, titleW, len );
1815     }
1816
1817     if (!IS_INTRESOURCE(className))
1818     {
1819         WCHAR classW[256];
1820         if (MultiByteToWideChar( CP_ACP, 0, className, -1, classW, sizeof(classW)/sizeof(WCHAR) ))
1821             hwnd = FindWindowExW( parent, child, classW, titleW );
1822     }
1823     else
1824     {
1825         hwnd = FindWindowExW( parent, child, (LPCWSTR)className, titleW );
1826     }
1827
1828     HeapFree( GetProcessHeap(), 0, titleW );
1829     return hwnd;
1830 }
1831
1832
1833 /***********************************************************************
1834  *              FindWindowW (USER32.@)
1835  */
1836 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
1837 {
1838     return FindWindowExW( 0, 0, className, title );
1839 }
1840
1841
1842 /**********************************************************************
1843  *              GetDesktopWindow (USER32.@)
1844  */
1845 HWND WINAPI GetDesktopWindow(void)
1846 {
1847     struct user_thread_info *thread_info = get_user_thread_info();
1848
1849     if (thread_info->top_window) return thread_info->top_window;
1850
1851     SERVER_START_REQ( get_desktop_window )
1852     {
1853         req->force = 0;
1854         if (!wine_server_call( req ))
1855         {
1856             thread_info->top_window = wine_server_ptr_handle( reply->top_window );
1857             thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
1858         }
1859     }
1860     SERVER_END_REQ;
1861
1862     if (!thread_info->top_window)
1863     {
1864         USEROBJECTFLAGS flags;
1865         if (!GetUserObjectInformationW( GetProcessWindowStation(), UOI_FLAGS, &flags,
1866                                         sizeof(flags), NULL ) || (flags.dwFlags & WSF_VISIBLE))
1867         {
1868             static const WCHAR explorer[] = {'\\','e','x','p','l','o','r','e','r','.','e','x','e',0};
1869             static const WCHAR args[] = {' ','/','d','e','s','k','t','o','p',0};
1870             STARTUPINFOW si;
1871             PROCESS_INFORMATION pi;
1872             WCHAR windir[MAX_PATH];
1873             WCHAR app[MAX_PATH + sizeof(explorer)/sizeof(WCHAR)];
1874             WCHAR cmdline[MAX_PATH + (sizeof(explorer) + sizeof(args))/sizeof(WCHAR)];
1875             void *redir;
1876
1877             memset( &si, 0, sizeof(si) );
1878             si.cb = sizeof(si);
1879             si.dwFlags = STARTF_USESTDHANDLES;
1880             si.hStdInput  = 0;
1881             si.hStdOutput = 0;
1882             si.hStdError  = GetStdHandle( STD_ERROR_HANDLE );
1883
1884             GetSystemDirectoryW( windir, MAX_PATH );
1885             strcpyW( app, windir );
1886             strcatW( app, explorer );
1887             strcpyW( cmdline, app );
1888             strcatW( cmdline, args );
1889
1890             Wow64DisableWow64FsRedirection( &redir );
1891             if (CreateProcessW( app, cmdline, NULL, NULL, FALSE, DETACHED_PROCESS,
1892                                 NULL, windir, &si, &pi ))
1893             {
1894                 TRACE( "started explorer pid %04x tid %04x\n", pi.dwProcessId, pi.dwThreadId );
1895                 WaitForInputIdle( pi.hProcess, 10000 );
1896                 CloseHandle( pi.hThread );
1897                 CloseHandle( pi.hProcess );
1898             }
1899             else WARN( "failed to start explorer, err %d\n", GetLastError() );
1900             Wow64RevertWow64FsRedirection( redir );
1901         }
1902         else TRACE( "not starting explorer since winstation is not visible\n" );
1903
1904         SERVER_START_REQ( get_desktop_window )
1905         {
1906             req->force = 1;
1907             if (!wine_server_call( req ))
1908             {
1909                 thread_info->top_window = wine_server_ptr_handle( reply->top_window );
1910                 thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
1911             }
1912         }
1913         SERVER_END_REQ;
1914     }
1915
1916     if (!thread_info->top_window || !USER_Driver->pCreateDesktopWindow( thread_info->top_window ))
1917         ERR( "failed to create desktop window\n" );
1918
1919     return thread_info->top_window;
1920 }
1921
1922
1923 /*******************************************************************
1924  *              EnableWindow (USER32.@)
1925  */
1926 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
1927 {
1928     BOOL retvalue;
1929     HWND full_handle;
1930
1931     if (is_broadcast(hwnd))
1932     {
1933         SetLastError( ERROR_INVALID_PARAMETER );
1934         return FALSE;
1935     }
1936
1937     if (!(full_handle = WIN_IsCurrentThread( hwnd )))
1938         return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
1939
1940     hwnd = full_handle;
1941
1942     TRACE("( %p, %d )\n", hwnd, enable);
1943
1944     retvalue = !IsWindowEnabled( hwnd );
1945
1946     if (enable && retvalue)
1947     {
1948         WIN_SetStyle( hwnd, 0, WS_DISABLED );
1949         SendMessageW( hwnd, WM_ENABLE, TRUE, 0 );
1950     }
1951     else if (!enable && !retvalue)
1952     {
1953         HWND capture_wnd;
1954
1955         SendMessageW( hwnd, WM_CANCELMODE, 0, 0);
1956
1957         WIN_SetStyle( hwnd, WS_DISABLED, 0 );
1958
1959         if (hwnd == GetFocus())
1960             SetFocus( 0 );  /* A disabled window can't have the focus */
1961
1962         capture_wnd = GetCapture();
1963         if (hwnd == capture_wnd || IsChild(hwnd, capture_wnd))
1964             ReleaseCapture();  /* A disabled window can't capture the mouse */
1965
1966         SendMessageW( hwnd, WM_ENABLE, FALSE, 0 );
1967     }
1968     return retvalue;
1969 }
1970
1971
1972 /***********************************************************************
1973  *              IsWindowEnabled (USER32.@)
1974  */
1975 BOOL WINAPI IsWindowEnabled(HWND hWnd)
1976 {
1977     return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
1978 }
1979
1980
1981 /***********************************************************************
1982  *              IsWindowUnicode (USER32.@)
1983  */
1984 BOOL WINAPI IsWindowUnicode( HWND hwnd )
1985 {
1986     WND * wndPtr;
1987     BOOL retvalue = FALSE;
1988
1989     if (!(wndPtr = WIN_GetPtr(hwnd))) return FALSE;
1990
1991     if (wndPtr == WND_DESKTOP) return TRUE;
1992
1993     if (wndPtr != WND_OTHER_PROCESS)
1994     {
1995         retvalue = (wndPtr->flags & WIN_ISUNICODE) != 0;
1996         WIN_ReleasePtr( wndPtr );
1997     }
1998     else
1999     {
2000         SERVER_START_REQ( get_window_info )
2001         {
2002             req->handle = wine_server_user_handle( hwnd );
2003             if (!wine_server_call_err( req )) retvalue = reply->is_unicode;
2004         }
2005         SERVER_END_REQ;
2006     }
2007     return retvalue;
2008 }
2009
2010
2011 /**********************************************************************
2012  *           WIN_GetWindowLong
2013  *
2014  * Helper function for GetWindowLong().
2015  */
2016 static LONG_PTR WIN_GetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicode )
2017 {
2018     LONG_PTR retvalue = 0;
2019     WND *wndPtr;
2020
2021     if (offset == GWLP_HWNDPARENT)
2022     {
2023         HWND parent = GetAncestor( hwnd, GA_PARENT );
2024         if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
2025         return (ULONG_PTR)parent;
2026     }
2027
2028     if (!(wndPtr = WIN_GetPtr( hwnd )))
2029     {
2030         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2031         return 0;
2032     }
2033
2034     if (wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP)
2035     {
2036         if (offset == GWLP_WNDPROC)
2037         {
2038             SetLastError( ERROR_ACCESS_DENIED );
2039             return 0;
2040         }
2041         SERVER_START_REQ( set_window_info )
2042         {
2043             req->handle = wine_server_user_handle( hwnd );
2044             req->flags  = 0;  /* don't set anything, just retrieve */
2045             req->extra_offset = (offset >= 0) ? offset : -1;
2046             req->extra_size = (offset >= 0) ? size : 0;
2047             if (!wine_server_call_err( req ))
2048             {
2049                 switch(offset)
2050                 {
2051                 case GWL_STYLE:      retvalue = reply->old_style; break;
2052                 case GWL_EXSTYLE:    retvalue = reply->old_ex_style; break;
2053                 case GWLP_ID:        retvalue = reply->old_id; break;
2054                 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wine_server_get_ptr( reply->old_instance ); break;
2055                 case GWLP_USERDATA:  retvalue = reply->old_user_data; break;
2056                 default:
2057                     if (offset >= 0) retvalue = get_win_data( &reply->old_extra_value, size );
2058                     else SetLastError( ERROR_INVALID_INDEX );
2059                     break;
2060                 }
2061             }
2062         }
2063         SERVER_END_REQ;
2064         return retvalue;
2065     }
2066
2067     /* now we have a valid wndPtr */
2068
2069     if (offset >= 0)
2070     {
2071         if (offset > (int)(wndPtr->cbWndExtra - size))
2072         {
2073             WARN("Invalid offset %d\n", offset );
2074             WIN_ReleasePtr( wndPtr );
2075             SetLastError( ERROR_INVALID_INDEX );
2076             return 0;
2077         }
2078         retvalue = get_win_data( (char *)wndPtr->wExtra + offset, size );
2079
2080         /* Special case for dialog window procedure */
2081         if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && wndPtr->dlgInfo)
2082             retvalue = (LONG_PTR)WINPROC_GetProc( (WNDPROC)retvalue, unicode );
2083         WIN_ReleasePtr( wndPtr );
2084         return retvalue;
2085     }
2086
2087     switch(offset)
2088     {
2089     case GWLP_USERDATA:  retvalue = wndPtr->userdata; break;
2090     case GWL_STYLE:      retvalue = wndPtr->dwStyle; break;
2091     case GWL_EXSTYLE:    retvalue = wndPtr->dwExStyle; break;
2092     case GWLP_ID:        retvalue = wndPtr->wIDmenu; break;
2093     case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hInstance; break;
2094     case GWLP_WNDPROC:
2095         /* This looks like a hack only for the edit control (see tests). This makes these controls
2096          * more tolerant to A/W mismatches. The lack of W->A->W conversion for such a mismatch suggests
2097          * that the hack is in GetWindowLongPtr[AW], not in winprocs.
2098          */
2099         if (wndPtr->winproc == BUILTIN_WINPROC(WINPROC_EDIT) && (!unicode != !(wndPtr->flags & WIN_ISUNICODE)))
2100             retvalue = (ULONG_PTR)wndPtr->winproc;
2101         else
2102             retvalue = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, unicode );
2103         break;
2104     default:
2105         WARN("Unknown offset %d\n", offset );
2106         SetLastError( ERROR_INVALID_INDEX );
2107         break;
2108     }
2109     WIN_ReleasePtr(wndPtr);
2110     return retvalue;
2111 }
2112
2113
2114 /**********************************************************************
2115  *           WIN_SetWindowLong
2116  *
2117  * Helper function for SetWindowLong().
2118  *
2119  * 0 is the failure code. However, in the case of failure SetLastError
2120  * must be set to distinguish between a 0 return value and a failure.
2121  */
2122 LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, UINT size, LONG_PTR newval, BOOL unicode )
2123 {
2124     STYLESTRUCT style;
2125     BOOL ok;
2126     LONG_PTR retval = 0;
2127     WND *wndPtr;
2128
2129     TRACE( "%p %d %lx %c\n", hwnd, offset, newval, unicode ? 'W' : 'A' );
2130
2131     if (is_broadcast(hwnd))
2132     {
2133         SetLastError( ERROR_INVALID_PARAMETER );
2134         return FALSE;
2135     }
2136
2137     if (!(wndPtr = WIN_GetPtr( hwnd )))
2138     {
2139         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2140         return 0;
2141     }
2142     if (wndPtr == WND_DESKTOP)
2143     {
2144         /* can't change anything on the desktop window */
2145         SetLastError( ERROR_ACCESS_DENIED );
2146         return 0;
2147     }
2148     if (wndPtr == WND_OTHER_PROCESS)
2149     {
2150         if (offset == GWLP_WNDPROC)
2151         {
2152             SetLastError( ERROR_ACCESS_DENIED );
2153             return 0;
2154         }
2155         if (offset > 32767 || offset < -32767)
2156         {
2157             SetLastError( ERROR_INVALID_INDEX );
2158             return 0;
2159         }
2160         return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, MAKEWPARAM( offset, size ), newval );
2161     }
2162
2163     /* first some special cases */
2164     switch( offset )
2165     {
2166     case GWL_STYLE:
2167         style.styleOld = wndPtr->dwStyle;
2168         style.styleNew = newval;
2169         WIN_ReleasePtr( wndPtr );
2170         SendMessageW( hwnd, WM_STYLECHANGING, GWL_STYLE, (LPARAM)&style );
2171         if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2172         newval = style.styleNew;
2173         /* WS_CLIPSIBLINGS can't be reset on top-level windows */
2174         if (wndPtr->parent == GetDesktopWindow()) newval |= WS_CLIPSIBLINGS;
2175         break;
2176     case GWL_EXSTYLE:
2177         style.styleOld = wndPtr->dwExStyle;
2178         style.styleNew = newval;
2179         WIN_ReleasePtr( wndPtr );
2180         SendMessageW( hwnd, WM_STYLECHANGING, GWL_EXSTYLE, (LPARAM)&style );
2181         if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2182         /* WS_EX_TOPMOST can only be changed through SetWindowPos */
2183         newval = (style.styleNew & ~WS_EX_TOPMOST) | (wndPtr->dwExStyle & WS_EX_TOPMOST);
2184         /* WS_EX_WINDOWEDGE depends on some other styles */
2185         if ((newval & WS_EX_DLGMODALFRAME) || (wndPtr->dwStyle & WS_THICKFRAME))
2186             newval |= WS_EX_WINDOWEDGE;
2187         else if (wndPtr->dwStyle & (WS_CHILD|WS_POPUP))
2188             newval &= ~WS_EX_WINDOWEDGE;
2189         break;
2190     case GWLP_HWNDPARENT:
2191         if (wndPtr->parent == GetDesktopWindow())
2192         {
2193             WIN_ReleasePtr( wndPtr );
2194             return (ULONG_PTR)WIN_SetOwner( hwnd, (HWND)newval );
2195         }
2196         else
2197         {
2198             WIN_ReleasePtr( wndPtr );
2199             return (ULONG_PTR)SetParent( hwnd, (HWND)newval );
2200         }
2201     case GWLP_WNDPROC:
2202     {
2203         WNDPROC proc;
2204         UINT old_flags = wndPtr->flags;
2205         retval = WIN_GetWindowLong( hwnd, offset, size, unicode );
2206         proc = WINPROC_AllocProc( (WNDPROC)newval, unicode );
2207         if (proc) wndPtr->winproc = proc;
2208         if (WINPROC_IsUnicode( proc, unicode )) wndPtr->flags |= WIN_ISUNICODE;
2209         else wndPtr->flags &= ~WIN_ISUNICODE;
2210         if (!((old_flags ^ wndPtr->flags) & WIN_ISUNICODE))
2211         {
2212             WIN_ReleasePtr( wndPtr );
2213             return retval;
2214         }
2215         /* update is_unicode flag on the server side */
2216         break;
2217     }
2218     case GWLP_ID:
2219     case GWLP_HINSTANCE:
2220     case GWLP_USERDATA:
2221         break;
2222     case DWLP_DLGPROC:
2223         if ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
2224             (size == sizeof(LONG_PTR)) && wndPtr->dlgInfo)
2225         {
2226             WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWLP_DLGPROC);
2227             retval = (ULONG_PTR)WINPROC_GetProc( *ptr, unicode );
2228             *ptr = WINPROC_AllocProc( (WNDPROC)newval, unicode );
2229             WIN_ReleasePtr( wndPtr );
2230             return retval;
2231         }
2232         /* fall through */
2233     default:
2234         if (offset < 0 || offset > (int)(wndPtr->cbWndExtra - size))
2235         {
2236             WARN("Invalid offset %d\n", offset );
2237             WIN_ReleasePtr( wndPtr );
2238             SetLastError( ERROR_INVALID_INDEX );
2239             return 0;
2240         }
2241         else if (get_win_data( (char *)wndPtr->wExtra + offset, size ) == newval)
2242         {
2243             /* already set to the same value */
2244             WIN_ReleasePtr( wndPtr );
2245             return newval;
2246         }
2247         break;
2248     }
2249
2250     SERVER_START_REQ( set_window_info )
2251     {
2252         req->handle = wine_server_user_handle( hwnd );
2253         req->extra_offset = -1;
2254         switch(offset)
2255         {
2256         case GWL_STYLE:
2257             req->flags = SET_WIN_STYLE;
2258             req->style = newval;
2259             break;
2260         case GWL_EXSTYLE:
2261             req->flags = SET_WIN_EXSTYLE;
2262             req->ex_style = newval;
2263             break;
2264         case GWLP_ID:
2265             req->flags = SET_WIN_ID;
2266             req->id = newval;
2267             break;
2268         case GWLP_HINSTANCE:
2269             req->flags = SET_WIN_INSTANCE;
2270             req->instance = wine_server_client_ptr( (void *)newval );
2271             break;
2272         case GWLP_WNDPROC:
2273             req->flags = SET_WIN_UNICODE;
2274             req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
2275             break;
2276         case GWLP_USERDATA:
2277             req->flags = SET_WIN_USERDATA;
2278             req->user_data = newval;
2279             break;
2280         default:
2281             req->flags = SET_WIN_EXTRA;
2282             req->extra_offset = offset;
2283             req->extra_size = size;
2284             set_win_data( &req->extra_value, newval, size );
2285         }
2286         if ((ok = !wine_server_call_err( req )))
2287         {
2288             switch(offset)
2289             {
2290             case GWL_STYLE:
2291                 wndPtr->dwStyle = newval;
2292                 retval = reply->old_style;
2293                 break;
2294             case GWL_EXSTYLE:
2295                 wndPtr->dwExStyle = newval;
2296                 retval = reply->old_ex_style;
2297                 break;
2298             case GWLP_ID:
2299                 wndPtr->wIDmenu = newval;
2300                 retval = reply->old_id;
2301                 break;
2302             case GWLP_HINSTANCE:
2303                 wndPtr->hInstance = (HINSTANCE)newval;
2304                 retval = (ULONG_PTR)wine_server_get_ptr( reply->old_instance );
2305                 break;
2306             case GWLP_WNDPROC:
2307                 break;
2308             case GWLP_USERDATA:
2309                 wndPtr->userdata = newval;
2310                 retval = reply->old_user_data;
2311                 break;
2312             default:
2313                 retval = get_win_data( (char *)wndPtr->wExtra + offset, size );
2314                 set_win_data( (char *)wndPtr->wExtra + offset, newval, size );
2315                 break;
2316             }
2317         }
2318     }
2319     SERVER_END_REQ;
2320     WIN_ReleasePtr( wndPtr );
2321
2322     if (!ok) return 0;
2323
2324     if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2325     {
2326         style.styleOld = retval;
2327         style.styleNew = newval;
2328         USER_Driver->pSetWindowStyle( hwnd, offset, &style );
2329         SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2330     }
2331
2332     return retval;
2333 }
2334
2335
2336 /**********************************************************************
2337  *              GetWindowWord (USER32.@)
2338  */
2339 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
2340 {
2341     switch(offset)
2342     {
2343     case GWLP_ID:
2344     case GWLP_HINSTANCE:
2345     case GWLP_HWNDPARENT:
2346         break;
2347     default:
2348         if (offset < 0)
2349         {
2350             WARN("Invalid offset %d\n", offset );
2351             SetLastError( ERROR_INVALID_INDEX );
2352             return 0;
2353         }
2354         break;
2355     }
2356     return WIN_GetWindowLong( hwnd, offset, sizeof(WORD), FALSE );
2357 }
2358
2359
2360 /**********************************************************************
2361  *              GetWindowLongA (USER32.@)
2362  */
2363 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2364 {
2365     return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), FALSE );
2366 }
2367
2368
2369 /**********************************************************************
2370  *              GetWindowLongW (USER32.@)
2371  */
2372 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2373 {
2374     return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), TRUE );
2375 }
2376
2377
2378 /**********************************************************************
2379  *              SetWindowWord (USER32.@)
2380  */
2381 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
2382 {
2383     switch(offset)
2384     {
2385     case GWLP_ID:
2386     case GWLP_HINSTANCE:
2387     case GWLP_HWNDPARENT:
2388         break;
2389     default:
2390         if (offset < 0)
2391         {
2392             WARN("Invalid offset %d\n", offset );
2393             SetLastError( ERROR_INVALID_INDEX );
2394             return 0;
2395         }
2396         break;
2397     }
2398     return WIN_SetWindowLong( hwnd, offset, sizeof(WORD), newval, FALSE );
2399 }
2400
2401
2402 /**********************************************************************
2403  *              SetWindowLongA (USER32.@)
2404  *
2405  * See SetWindowLongW.
2406  */
2407 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2408 {
2409     return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, FALSE );
2410 }
2411
2412
2413 /**********************************************************************
2414  *              SetWindowLongW (USER32.@) Set window attribute
2415  *
2416  * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2417  * value in a window's extra memory.
2418  *
2419  * The _hwnd_ parameter specifies the window.  is the handle to a
2420  * window that has extra memory. The _newval_ parameter contains the
2421  * new attribute or extra memory value.  If positive, the _offset_
2422  * parameter is the byte-addressed location in the window's extra
2423  * memory to set.  If negative, _offset_ specifies the window
2424  * attribute to set, and should be one of the following values:
2425  *
2426  * GWL_EXSTYLE      The window's extended window style
2427  *
2428  * GWL_STYLE        The window's window style.
2429  *
2430  * GWLP_WNDPROC     Pointer to the window's window procedure.
2431  *
2432  * GWLP_HINSTANCE   The window's pplication instance handle.
2433  *
2434  * GWLP_ID          The window's identifier.
2435  *
2436  * GWLP_USERDATA    The window's user-specified data.
2437  *
2438  * If the window is a dialog box, the _offset_ parameter can be one of
2439  * the following values:
2440  *
2441  * DWLP_DLGPROC     The address of the window's dialog box procedure.
2442  *
2443  * DWLP_MSGRESULT   The return value of a message
2444  *                  that the dialog box procedure processed.
2445  *
2446  * DWLP_USER        Application specific information.
2447  *
2448  * RETURNS
2449  *
2450  * If successful, returns the previous value located at _offset_. Otherwise,
2451  * returns 0.
2452  *
2453  * NOTES
2454  *
2455  * Extra memory for a window class is specified by a nonzero cbWndExtra
2456  * parameter of the WNDCLASS structure passed to RegisterClass() at the
2457  * time of class creation.
2458  *
2459  * Using GWL_WNDPROC to set a new window procedure effectively creates
2460  * a window subclass. Use CallWindowProc() in the new windows procedure
2461  * to pass messages to the superclass's window procedure.
2462  *
2463  * The user data is reserved for use by the application which created
2464  * the window.
2465  *
2466  * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2467  * instead, call the EnableWindow() function to change the window's
2468  * disabled state.
2469  *
2470  * Do not use GWL_HWNDPARENT to reset the window's parent, use
2471  * SetParent() instead.
2472  *
2473  * Win95:
2474  * When offset is GWL_STYLE and the calling app's ver is 4.0,
2475  * it sends WM_STYLECHANGING before changing the settings
2476  * and WM_STYLECHANGED afterwards.
2477  * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2478  */
2479 LONG WINAPI SetWindowLongW(
2480     HWND hwnd,  /* [in] window to alter */
2481     INT offset, /* [in] offset, in bytes, of location to alter */
2482     LONG newval /* [in] new value of location */
2483 ) {
2484     return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, TRUE );
2485 }
2486
2487
2488 /*******************************************************************
2489  *              GetWindowTextA (USER32.@)
2490  */
2491 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2492 {
2493     WCHAR *buffer;
2494
2495     if (!lpString) return 0;
2496
2497     if (WIN_IsCurrentProcess( hwnd ))
2498         return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2499
2500     /* when window belongs to other process, don't send a message */
2501     if (nMaxCount <= 0) return 0;
2502     if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2503     get_server_window_text( hwnd, buffer, nMaxCount );
2504     if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2505         lpString[nMaxCount-1] = 0;
2506     HeapFree( GetProcessHeap(), 0, buffer );
2507     return strlen(lpString);
2508 }
2509
2510
2511 /*******************************************************************
2512  *              InternalGetWindowText (USER32.@)
2513  */
2514 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2515 {
2516     WND *win;
2517
2518     if (nMaxCount <= 0) return 0;
2519     if (!(win = WIN_GetPtr( hwnd ))) return 0;
2520     if (win == WND_DESKTOP) lpString[0] = 0;
2521     else if (win != WND_OTHER_PROCESS)
2522     {
2523         if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2524         else lpString[0] = 0;
2525         WIN_ReleasePtr( win );
2526     }
2527     else
2528     {
2529         get_server_window_text( hwnd, lpString, nMaxCount );
2530     }
2531     return strlenW(lpString);
2532 }
2533
2534
2535 /*******************************************************************
2536  *              GetWindowTextW (USER32.@)
2537  */
2538 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2539 {
2540     if (!lpString) return 0;
2541
2542     if (WIN_IsCurrentProcess( hwnd ))
2543         return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2544
2545     /* when window belongs to other process, don't send a message */
2546     if (nMaxCount <= 0) return 0;
2547     get_server_window_text( hwnd, lpString, nMaxCount );
2548     return strlenW(lpString);
2549 }
2550
2551
2552 /*******************************************************************
2553  *              SetWindowTextA (USER32.@)
2554  *              SetWindowText  (USER32.@)
2555  */
2556 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2557 {
2558     if (is_broadcast(hwnd))
2559     {
2560         SetLastError( ERROR_INVALID_PARAMETER );
2561         return FALSE;
2562     }
2563     if (!WIN_IsCurrentProcess( hwnd ))
2564         WARN( "setting text %s of other process window %p should not use SendMessage\n",
2565                debugstr_a(lpString), hwnd );
2566     return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2567 }
2568
2569
2570 /*******************************************************************
2571  *              SetWindowTextW (USER32.@)
2572  */
2573 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2574 {
2575     if (is_broadcast(hwnd))
2576     {
2577         SetLastError( ERROR_INVALID_PARAMETER );
2578         return FALSE;
2579     }
2580     if (!WIN_IsCurrentProcess( hwnd ))
2581         WARN( "setting text %s of other process window %p should not use SendMessage\n",
2582                debugstr_w(lpString), hwnd );
2583     return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2584 }
2585
2586
2587 /*******************************************************************
2588  *              GetWindowTextLengthA (USER32.@)
2589  */
2590 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2591 {
2592     return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2593 }
2594
2595 /*******************************************************************
2596  *              GetWindowTextLengthW (USER32.@)
2597  */
2598 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2599 {
2600     return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2601 }
2602
2603
2604 /*******************************************************************
2605  *              IsWindow (USER32.@)
2606  */
2607 BOOL WINAPI IsWindow( HWND hwnd )
2608 {
2609     WND *ptr;
2610     BOOL ret;
2611
2612     if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2613     if (ptr == WND_DESKTOP) return TRUE;
2614
2615     if (ptr != WND_OTHER_PROCESS)
2616     {
2617         WIN_ReleasePtr( ptr );
2618         return TRUE;
2619     }
2620
2621     /* check other processes */
2622     SERVER_START_REQ( get_window_info )
2623     {
2624         req->handle = wine_server_user_handle( hwnd );
2625         ret = !wine_server_call_err( req );
2626     }
2627     SERVER_END_REQ;
2628     return ret;
2629 }
2630
2631
2632 /***********************************************************************
2633  *              GetWindowThreadProcessId (USER32.@)
2634  */
2635 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2636 {
2637     WND *ptr;
2638     DWORD tid = 0;
2639
2640     if (!(ptr = WIN_GetPtr( hwnd )))
2641     {
2642         SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2643         return 0;
2644     }
2645
2646     if (ptr != WND_OTHER_PROCESS && ptr != WND_DESKTOP)
2647     {
2648         /* got a valid window */
2649         tid = ptr->tid;
2650         if (process) *process = GetCurrentProcessId();
2651         WIN_ReleasePtr( ptr );
2652         return tid;
2653     }
2654
2655     /* check other processes */
2656     SERVER_START_REQ( get_window_info )
2657     {
2658         req->handle = wine_server_user_handle( hwnd );
2659         if (!wine_server_call_err( req ))
2660         {
2661             tid = (DWORD)reply->tid;
2662             if (process) *process = (DWORD)reply->pid;
2663         }
2664     }
2665     SERVER_END_REQ;
2666     return tid;
2667 }
2668
2669
2670 /*****************************************************************
2671  *              GetParent (USER32.@)
2672  */
2673 HWND WINAPI GetParent( HWND hwnd )
2674 {
2675     WND *wndPtr;
2676     HWND retvalue = 0;
2677
2678     if (!(wndPtr = WIN_GetPtr( hwnd )))
2679     {
2680         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2681         return 0;
2682     }
2683     if (wndPtr == WND_DESKTOP) return 0;
2684     if (wndPtr == WND_OTHER_PROCESS)
2685     {
2686         LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2687         if (style & (WS_POPUP | WS_CHILD))
2688         {
2689             SERVER_START_REQ( get_window_tree )
2690             {
2691                 req->handle = wine_server_user_handle( hwnd );
2692                 if (!wine_server_call_err( req ))
2693                 {
2694                     if (style & WS_POPUP) retvalue = wine_server_ptr_handle( reply->owner );
2695                     else if (style & WS_CHILD) retvalue = wine_server_ptr_handle( reply->parent );
2696                 }
2697             }
2698             SERVER_END_REQ;
2699         }
2700     }
2701     else
2702     {
2703         if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2704         else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2705         WIN_ReleasePtr( wndPtr );
2706     }
2707     return retvalue;
2708 }
2709
2710
2711 /*****************************************************************
2712  *              GetAncestor (USER32.@)
2713  */
2714 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2715 {
2716     WND *win;
2717     HWND *list, ret = 0;
2718
2719     switch(type)
2720     {
2721     case GA_PARENT:
2722         if (!(win = WIN_GetPtr( hwnd )))
2723         {
2724             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2725             return 0;
2726         }
2727         if (win == WND_DESKTOP) return 0;
2728         if (win != WND_OTHER_PROCESS)
2729         {
2730             ret = win->parent;
2731             WIN_ReleasePtr( win );
2732         }
2733         else /* need to query the server */
2734         {
2735             SERVER_START_REQ( get_window_tree )
2736             {
2737                 req->handle = wine_server_user_handle( hwnd );
2738                 if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->parent );
2739             }
2740             SERVER_END_REQ;
2741         }
2742         break;
2743
2744     case GA_ROOT:
2745         if (!(list = list_window_parents( hwnd ))) return 0;
2746
2747         if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd );  /* top-level window */
2748         else
2749         {
2750             int count = 2;
2751             while (list[count]) count++;
2752             ret = list[count - 2];  /* get the one before the desktop */
2753         }
2754         HeapFree( GetProcessHeap(), 0, list );
2755         break;
2756
2757     case GA_ROOTOWNER:
2758         if (is_desktop_window( hwnd )) return 0;
2759         ret = WIN_GetFullHandle( hwnd );
2760         for (;;)
2761         {
2762             HWND parent = GetParent( ret );
2763             if (!parent) break;
2764             ret = parent;
2765         }
2766         break;
2767     }
2768     return ret;
2769 }
2770
2771
2772 /*****************************************************************
2773  *              SetParent (USER32.@)
2774  */
2775 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2776 {
2777     HWND full_handle;
2778     HWND old_parent = 0;
2779     BOOL was_visible;
2780     WND *wndPtr;
2781     BOOL ret;
2782
2783     if (is_broadcast(hwnd) || is_broadcast(parent))
2784     {
2785         SetLastError(ERROR_INVALID_PARAMETER);
2786         return 0;
2787     }
2788
2789     if (!parent) parent = GetDesktopWindow();
2790     else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
2791     else parent = WIN_GetFullHandle( parent );
2792
2793     if (!IsWindow( parent ))
2794     {
2795         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2796         return 0;
2797     }
2798
2799     /* Some applications try to set a child as a parent */
2800     if (IsChild(hwnd, parent))
2801     {
2802         SetLastError( ERROR_INVALID_PARAMETER );
2803         return 0;
2804     }
2805
2806     if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2807         return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2808
2809     if (full_handle == parent)
2810     {
2811         SetLastError( ERROR_INVALID_PARAMETER );
2812         return 0;
2813     }
2814
2815     /* Windows hides the window first, then shows it again
2816      * including the WM_SHOWWINDOW messages and all */
2817     was_visible = ShowWindow( hwnd, SW_HIDE );
2818
2819     wndPtr = WIN_GetPtr( hwnd );
2820     if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
2821
2822     SERVER_START_REQ( set_parent )
2823     {
2824         req->handle = wine_server_user_handle( hwnd );
2825         req->parent = wine_server_user_handle( parent );
2826         if ((ret = !wine_server_call( req )))
2827         {
2828             old_parent = wine_server_ptr_handle( reply->old_parent );
2829             wndPtr->parent = parent = wine_server_ptr_handle( reply->full_parent );
2830         }
2831
2832     }
2833     SERVER_END_REQ;
2834     WIN_ReleasePtr( wndPtr );
2835     if (!ret) return 0;
2836
2837     USER_Driver->pSetParent( full_handle, parent, old_parent );
2838
2839     /* SetParent additionally needs to make hwnd the topmost window
2840        in the x-order and send the expected WM_WINDOWPOSCHANGING and
2841        WM_WINDOWPOSCHANGED notification messages.
2842     */
2843     SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0,
2844                   SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | (was_visible ? SWP_SHOWWINDOW : 0) );
2845     /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
2846      * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
2847
2848     return old_parent;
2849 }
2850
2851
2852 /*******************************************************************
2853  *              IsChild (USER32.@)
2854  */
2855 BOOL WINAPI IsChild( HWND parent, HWND child )
2856 {
2857     HWND *list = list_window_parents( child );
2858     int i;
2859     BOOL ret;
2860
2861     if (!list) return FALSE;
2862     parent = WIN_GetFullHandle( parent );
2863     for (i = 0; list[i]; i++) if (list[i] == parent) break;
2864     ret = list[i] && list[i+1];
2865     HeapFree( GetProcessHeap(), 0, list );
2866     return ret;
2867 }
2868
2869
2870 /***********************************************************************
2871  *              IsWindowVisible (USER32.@)
2872  */
2873 BOOL WINAPI IsWindowVisible( HWND hwnd )
2874 {
2875     HWND *list;
2876     BOOL retval = TRUE;
2877     int i;
2878
2879     if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2880     if (!(list = list_window_parents( hwnd ))) return TRUE;
2881     if (list[0])
2882     {
2883         for (i = 0; list[i+1]; i++)
2884             if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2885         retval = !list[i+1] && (list[i] == GetDesktopWindow());  /* top message window isn't visible */
2886     }
2887     HeapFree( GetProcessHeap(), 0, list );
2888     return retval;
2889 }
2890
2891
2892 /***********************************************************************
2893  *           WIN_IsWindowDrawable
2894  *
2895  * hwnd is drawable when it is visible, all parents are not
2896  * minimized, and it is itself not minimized unless we are
2897  * trying to draw its default class icon.
2898  */
2899 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2900 {
2901     HWND *list;
2902     BOOL retval = TRUE;
2903     int i;
2904     LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2905
2906     if (!(style & WS_VISIBLE)) return FALSE;
2907     if ((style & WS_MINIMIZE) && icon && GetClassLongPtrW( hwnd, GCLP_HICON ))  return FALSE;
2908
2909     if (!(list = list_window_parents( hwnd ))) return TRUE;
2910     if (list[0])
2911     {
2912         for (i = 0; list[i+1]; i++)
2913             if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2914                 break;
2915         retval = !list[i+1] && (list[i] == GetDesktopWindow());  /* top message window isn't visible */
2916     }
2917     HeapFree( GetProcessHeap(), 0, list );
2918     return retval;
2919 }
2920
2921
2922 /*******************************************************************
2923  *              GetTopWindow (USER32.@)
2924  */
2925 HWND WINAPI GetTopWindow( HWND hwnd )
2926 {
2927     if (!hwnd) hwnd = GetDesktopWindow();
2928     return GetWindow( hwnd, GW_CHILD );
2929 }
2930
2931
2932 /*******************************************************************
2933  *              GetWindow (USER32.@)
2934  */
2935 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2936 {
2937     HWND retval = 0;
2938
2939     if (rel == GW_OWNER)  /* this one may be available locally */
2940     {
2941         WND *wndPtr = WIN_GetPtr( hwnd );
2942         if (!wndPtr)
2943         {
2944             SetLastError( ERROR_INVALID_HANDLE );
2945             return 0;
2946         }
2947         if (wndPtr == WND_DESKTOP) return 0;
2948         if (wndPtr != WND_OTHER_PROCESS)
2949         {
2950             retval = wndPtr->owner;
2951             WIN_ReleasePtr( wndPtr );
2952             return retval;
2953         }
2954         /* else fall through to server call */
2955     }
2956
2957     SERVER_START_REQ( get_window_tree )
2958     {
2959         req->handle = wine_server_user_handle( hwnd );
2960         if (!wine_server_call_err( req ))
2961         {
2962             switch(rel)
2963             {
2964             case GW_HWNDFIRST:
2965                 retval = wine_server_ptr_handle( reply->first_sibling );
2966                 break;
2967             case GW_HWNDLAST:
2968                 retval = wine_server_ptr_handle( reply->last_sibling );
2969                 break;
2970             case GW_HWNDNEXT:
2971                 retval = wine_server_ptr_handle( reply->next_sibling );
2972                 break;
2973             case GW_HWNDPREV:
2974                 retval = wine_server_ptr_handle( reply->prev_sibling );
2975                 break;
2976             case GW_OWNER:
2977                 retval = wine_server_ptr_handle( reply->owner );
2978                 break;
2979             case GW_CHILD:
2980                 retval = wine_server_ptr_handle( reply->first_child );
2981                 break;
2982             }
2983         }
2984     }
2985     SERVER_END_REQ;
2986     return retval;
2987 }
2988
2989
2990 /*******************************************************************
2991  *              ShowOwnedPopups (USER32.@)
2992  */
2993 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2994 {
2995     int count = 0;
2996     WND *pWnd;
2997     HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2998
2999     if (!win_array) return TRUE;
3000
3001     while (win_array[count]) count++;
3002     while (--count >= 0)
3003     {
3004         if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
3005         if (!(pWnd = WIN_GetPtr( win_array[count] ))) continue;
3006         if (pWnd == WND_OTHER_PROCESS) continue;
3007         if (fShow)
3008         {
3009             if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
3010             {
3011                 WIN_ReleasePtr( pWnd );
3012                 /* In Windows, ShowOwnedPopups(TRUE) generates
3013                  * WM_SHOWWINDOW messages with SW_PARENTOPENING,
3014                  * regardless of the state of the owner
3015                  */
3016                 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
3017                 continue;
3018             }
3019         }
3020         else
3021         {
3022             if (pWnd->dwStyle & WS_VISIBLE)
3023             {
3024                 WIN_ReleasePtr( pWnd );
3025                 /* In Windows, ShowOwnedPopups(FALSE) generates
3026                  * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
3027                  * regardless of the state of the owner
3028                  */
3029                 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
3030                 continue;
3031             }
3032         }
3033         WIN_ReleasePtr( pWnd );
3034     }
3035     HeapFree( GetProcessHeap(), 0, win_array );
3036     return TRUE;
3037 }
3038
3039
3040 /*******************************************************************
3041  *              GetLastActivePopup (USER32.@)
3042  */
3043 HWND WINAPI GetLastActivePopup( HWND hwnd )
3044 {
3045     HWND retval = hwnd;
3046
3047     SERVER_START_REQ( get_window_info )
3048     {
3049         req->handle = wine_server_user_handle( hwnd );
3050         if (!wine_server_call_err( req )) retval = wine_server_ptr_handle( reply->last_active );
3051     }
3052     SERVER_END_REQ;
3053     return retval;
3054 }
3055
3056
3057 /*******************************************************************
3058  *           WIN_ListChildren
3059  *
3060  * Build an array of the children of a given window. The array must be
3061  * freed with HeapFree. Returns NULL when no windows are found.
3062  */
3063 HWND *WIN_ListChildren( HWND hwnd )
3064 {
3065     if (!hwnd)
3066     {
3067         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3068         return NULL;
3069     }
3070     return list_window_children( 0, hwnd, NULL, 0 );
3071 }
3072
3073
3074 /*******************************************************************
3075  *              EnumWindows (USER32.@)
3076  */
3077 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
3078 {
3079     HWND *list;
3080     BOOL ret = TRUE;
3081     int i;
3082
3083     USER_CheckNotLock();
3084
3085     /* We have to build a list of all windows first, to avoid */
3086     /* unpleasant side-effects, for instance if the callback */
3087     /* function changes the Z-order of the windows.          */
3088
3089     if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
3090
3091     /* Now call the callback function for every window */
3092
3093     for (i = 0; list[i]; i++)
3094     {
3095         /* Make sure that the window still exists */
3096         if (!IsWindow( list[i] )) continue;
3097         if (!(ret = lpEnumFunc( list[i], lParam ))) break;
3098     }
3099     HeapFree( GetProcessHeap(), 0, list );
3100     return ret;
3101 }
3102
3103
3104 /**********************************************************************
3105  *              EnumThreadWindows (USER32.@)
3106  */
3107 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
3108 {
3109     HWND *list;
3110     int i;
3111     BOOL ret = TRUE;
3112
3113     USER_CheckNotLock();
3114
3115     if (!(list = list_window_children( 0, GetDesktopWindow(), NULL, id ))) return TRUE;
3116
3117     /* Now call the callback function for every window */
3118
3119     for (i = 0; list[i]; i++)
3120         if (!(ret = func( list[i], lParam ))) break;
3121     HeapFree( GetProcessHeap(), 0, list );
3122     return ret;
3123 }
3124
3125
3126 /***********************************************************************
3127  *              EnumDesktopWindows   (USER32.@)
3128  */
3129 BOOL WINAPI EnumDesktopWindows( HDESK desktop, WNDENUMPROC func, LPARAM lparam )
3130 {
3131     HWND *list;
3132     int i;
3133
3134     USER_CheckNotLock();
3135
3136     if (!(list = list_window_children( desktop, 0, NULL, 0 ))) return TRUE;
3137
3138     for (i = 0; list[i]; i++)
3139         if (!func( list[i], lparam )) break;
3140     HeapFree( GetProcessHeap(), 0, list );
3141     return TRUE;
3142 }
3143
3144
3145 /**********************************************************************
3146  *           WIN_EnumChildWindows
3147  *
3148  * Helper function for EnumChildWindows().
3149  */
3150 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
3151 {
3152     HWND *childList;
3153     BOOL ret = FALSE;
3154
3155     for ( ; *list; list++)
3156     {
3157         /* Make sure that the window still exists */
3158         if (!IsWindow( *list )) continue;
3159         /* Build children list first */
3160         childList = WIN_ListChildren( *list );
3161
3162         ret = func( *list, lParam );
3163
3164         if (childList)
3165         {
3166             if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
3167             HeapFree( GetProcessHeap(), 0, childList );
3168         }
3169         if (!ret) return FALSE;
3170     }
3171     return TRUE;
3172 }
3173
3174
3175 /**********************************************************************
3176  *              EnumChildWindows (USER32.@)
3177  */
3178 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
3179 {
3180     HWND *list;
3181     BOOL ret;
3182
3183     USER_CheckNotLock();
3184
3185     if (!(list = WIN_ListChildren( parent ))) return FALSE;
3186     ret = WIN_EnumChildWindows( list, func, lParam );
3187     HeapFree( GetProcessHeap(), 0, list );
3188     return ret;
3189 }
3190
3191
3192 /*******************************************************************
3193  *              AnyPopup (USER32.@)
3194  */
3195 BOOL WINAPI AnyPopup(void)
3196 {
3197     int i;
3198     BOOL retvalue;
3199     HWND *list = WIN_ListChildren( GetDesktopWindow() );
3200
3201     if (!list) return FALSE;
3202     for (i = 0; list[i]; i++)
3203     {
3204         if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
3205     }
3206     retvalue = (list[i] != 0);
3207     HeapFree( GetProcessHeap(), 0, list );
3208     return retvalue;
3209 }
3210
3211
3212 /*******************************************************************
3213  *              FlashWindow (USER32.@)
3214  */
3215 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3216 {
3217     WND *wndPtr;
3218
3219     TRACE("%p\n", hWnd);
3220
3221     if (IsIconic( hWnd ))
3222     {
3223         RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
3224
3225         wndPtr = WIN_GetPtr(hWnd);
3226         if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3227         if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
3228         {
3229             wndPtr->flags |= WIN_NCACTIVATED;
3230         }
3231         else
3232         {
3233             wndPtr->flags &= ~WIN_NCACTIVATED;
3234         }
3235         WIN_ReleasePtr( wndPtr );
3236         return TRUE;
3237     }
3238     else
3239     {
3240         WPARAM wparam;
3241
3242         wndPtr = WIN_GetPtr(hWnd);
3243         if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3244         hWnd = wndPtr->obj.handle;  /* make it a full handle */
3245
3246         if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3247         else wparam = (hWnd == GetForegroundWindow());
3248
3249         WIN_ReleasePtr( wndPtr );
3250         SendMessageW( hWnd, WM_NCACTIVATE, wparam, 0 );
3251         return wparam;
3252     }
3253 }
3254
3255 /*******************************************************************
3256  *              FlashWindowEx (USER32.@)
3257  */
3258 BOOL WINAPI FlashWindowEx( PFLASHWINFO pfwi )
3259 {
3260     FIXME("%p\n", pfwi);
3261     return TRUE;
3262 }
3263
3264 /*******************************************************************
3265  *              GetWindowContextHelpId (USER32.@)
3266  */
3267 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3268 {
3269     DWORD retval;
3270     WND *wnd = WIN_GetPtr( hwnd );
3271     if (!wnd || wnd == WND_DESKTOP) return 0;
3272     if (wnd == WND_OTHER_PROCESS)
3273     {
3274         if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3275         return 0;
3276     }
3277     retval = wnd->helpContext;
3278     WIN_ReleasePtr( wnd );
3279     return retval;
3280 }
3281
3282
3283 /*******************************************************************
3284  *              SetWindowContextHelpId (USER32.@)
3285  */
3286 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3287 {
3288     WND *wnd = WIN_GetPtr( hwnd );
3289     if (!wnd || wnd == WND_DESKTOP) return FALSE;
3290     if (wnd == WND_OTHER_PROCESS)
3291     {
3292         if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3293         return 0;
3294     }
3295     wnd->helpContext = id;
3296     WIN_ReleasePtr( wnd );
3297     return TRUE;
3298 }
3299
3300
3301 /*******************************************************************
3302  *              DragDetect (USER32.@)
3303  */
3304 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3305 {
3306     MSG msg;
3307     RECT rect;
3308     WORD wDragWidth = GetSystemMetrics(SM_CXDRAG);
3309     WORD wDragHeight= GetSystemMetrics(SM_CYDRAG);
3310
3311     rect.left = pt.x - wDragWidth;
3312     rect.right = pt.x + wDragWidth;
3313
3314     rect.top = pt.y - wDragHeight;
3315     rect.bottom = pt.y + wDragHeight;
3316
3317     SetCapture(hWnd);
3318
3319     while(1)
3320     {
3321         while (PeekMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ))
3322         {
3323             if( msg.message == WM_LBUTTONUP )
3324             {
3325                 ReleaseCapture();
3326                 return 0;
3327             }
3328             if( msg.message == WM_MOUSEMOVE )
3329             {
3330                 POINT tmp;
3331                 tmp.x = (short)LOWORD(msg.lParam);
3332                 tmp.y = (short)HIWORD(msg.lParam);
3333                 if( !PtInRect( &rect, tmp ))
3334                 {
3335                     ReleaseCapture();
3336                     return 1;
3337                 }
3338             }
3339         }
3340         WaitMessage();
3341     }
3342     return 0;
3343 }
3344
3345 /******************************************************************************
3346  *              GetWindowModuleFileNameA (USER32.@)
3347  */
3348 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR module, UINT size )
3349 {
3350     WND *win;
3351     HINSTANCE hinst;
3352
3353     TRACE( "%p, %p, %u\n", hwnd, module, size );
3354
3355     win = WIN_GetPtr( hwnd );
3356     if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3357     {
3358         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3359         return 0;
3360     }
3361     hinst = win->hInstance;
3362     WIN_ReleasePtr( win );
3363
3364     return GetModuleFileNameA( hinst, module, size );
3365 }
3366
3367 /******************************************************************************
3368  *              GetWindowModuleFileNameW (USER32.@)
3369  */
3370 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR module, UINT size )
3371 {
3372     WND *win;
3373     HINSTANCE hinst;
3374
3375     TRACE( "%p, %p, %u\n", hwnd, module, size );
3376
3377     win = WIN_GetPtr( hwnd );
3378     if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3379     {
3380         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3381         return 0;
3382     }
3383     hinst = win->hInstance;
3384     WIN_ReleasePtr( win );
3385
3386     return GetModuleFileNameW( hinst, module, size );
3387 }
3388
3389 /******************************************************************************
3390  *              GetWindowInfo (USER32.@)
3391  *
3392  * Note: tests show that Windows doesn't check cbSize of the structure.
3393  */
3394 BOOL WINAPI GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3395 {
3396     if (!pwi) return FALSE;
3397     if (!WIN_GetRectangles( hwnd, COORDS_SCREEN, &pwi->rcWindow, &pwi->rcClient )) return FALSE;
3398
3399     pwi->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
3400     pwi->dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3401     pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3402
3403     pwi->cxWindowBorders = pwi->rcClient.left - pwi->rcWindow.left;
3404     pwi->cyWindowBorders = pwi->rcWindow.bottom - pwi->rcClient.bottom;
3405
3406     pwi->atomWindowType = GetClassLongW( hwnd, GCW_ATOM );
3407     pwi->wCreatorVersion = 0x0400;
3408
3409     return TRUE;
3410 }
3411
3412 /******************************************************************************
3413  *              SwitchDesktop (USER32.@)
3414  *
3415  * NOTES: Sets the current input or interactive desktop.
3416  */
3417 BOOL WINAPI SwitchDesktop( HDESK hDesktop)
3418 {
3419     FIXME("(hwnd %p) stub!\n", hDesktop);
3420     return TRUE;
3421 }
3422
3423 /*****************************************************************************
3424  *              SetLayeredWindowAttributes (USER32.@)
3425  */
3426 BOOL WINAPI SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, DWORD flags )
3427 {
3428     BOOL ret;
3429
3430     TRACE("(%p,%08x,%d,%x): stub!\n", hwnd, key, alpha, flags);
3431
3432     SERVER_START_REQ( set_window_layered_info )
3433     {
3434         req->handle = wine_server_user_handle( hwnd );
3435         req->color_key = key;
3436         req->alpha = alpha;
3437         req->flags = flags;
3438         ret = !wine_server_call_err( req );
3439     }
3440     SERVER_END_REQ;
3441
3442     if (ret) USER_Driver->pSetLayeredWindowAttributes( hwnd, key, alpha, flags );
3443
3444     return ret;
3445 }
3446
3447
3448 /*****************************************************************************
3449  *              GetLayeredWindowAttributes (USER32.@)
3450  */
3451 BOOL WINAPI GetLayeredWindowAttributes( HWND hwnd, COLORREF *key, BYTE *alpha, DWORD *flags )
3452 {
3453     BOOL ret;
3454
3455     SERVER_START_REQ( get_window_layered_info )
3456     {
3457         req->handle = wine_server_user_handle( hwnd );
3458         if ((ret = !wine_server_call_err( req )))
3459         {
3460             if (key) *key = reply->color_key;
3461             if (alpha) *alpha = reply->alpha;
3462             if (flags) *flags = reply->flags;
3463         }
3464     }
3465     SERVER_END_REQ;
3466
3467     return ret;
3468 }
3469
3470
3471 /*****************************************************************************
3472  *              UpdateLayeredWindowIndirect  (USER32.@)
3473  */
3474 BOOL WINAPI UpdateLayeredWindowIndirect( HWND hwnd, const UPDATELAYEREDWINDOWINFO *info )
3475 {
3476     BYTE alpha = 0xff;
3477
3478     if (!(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_LAYERED) ||
3479         GetLayeredWindowAttributes( hwnd, NULL, NULL, NULL ))
3480     {
3481         SetLastError( ERROR_INVALID_PARAMETER );
3482         return FALSE;
3483     }
3484
3485     if (!(info->dwFlags & ULW_EX_NORESIZE) && (info->pptDst || info->psize))
3486     {
3487         int x = 0, y = 0, cx = 0, cy = 0;
3488         DWORD flags = SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOSENDCHANGING;
3489
3490         if (info->pptDst)
3491         {
3492             x = info->pptDst->x;
3493             y = info->pptDst->y;
3494             flags &= ~SWP_NOMOVE;
3495         }
3496         if (info->psize)
3497         {
3498             cx = info->psize->cx;
3499             cy = info->psize->cy;
3500             flags &= ~SWP_NOSIZE;
3501         }
3502         TRACE( "moving window %p pos %d,%d %dx%d\n", hwnd, x, y, cx, cy );
3503         SetWindowPos( hwnd, 0, x, y, cx, cy, flags );
3504     }
3505
3506     if (info->hdcSrc)
3507     {
3508         HDC hdc = GetWindowDC( hwnd );
3509
3510         if (hdc)
3511         {
3512             int x = 0, y = 0;
3513             RECT rect;
3514
3515             GetWindowRect( hwnd, &rect );
3516             OffsetRect( &rect, -rect.left, -rect.top);
3517             if (info->pptSrc)
3518             {
3519                 x = info->pptSrc->x;
3520                 y = info->pptSrc->y;
3521             }
3522
3523             if (!info->prcDirty || (info->prcDirty && IntersectRect(&rect, &rect, info->prcDirty)))
3524             {
3525                 TRACE( "copying window %p pos %d,%d\n", hwnd, x, y );
3526                 BitBlt( hdc, rect.left, rect.top, rect.right, rect.bottom,
3527                         info->hdcSrc, rect.left + x, rect.top + y, SRCCOPY );
3528             }
3529             ReleaseDC( hwnd, hdc );
3530         }
3531     }
3532
3533     if (info->pblend && !(info->dwFlags & ULW_OPAQUE)) alpha = info->pblend->SourceConstantAlpha;
3534     TRACE( "setting window %p alpha %u\n", hwnd, alpha );
3535     USER_Driver->pSetLayeredWindowAttributes( hwnd, info->crKey, alpha,
3536                                               info->dwFlags & (LWA_ALPHA | LWA_COLORKEY) );
3537     return TRUE;
3538 }
3539
3540
3541 /*****************************************************************************
3542  *              UpdateLayeredWindow (USER32.@)
3543  */
3544 BOOL WINAPI UpdateLayeredWindow( HWND hwnd, HDC hdcDst, POINT *pptDst, SIZE *psize,
3545                                  HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend,
3546                                  DWORD dwFlags)
3547 {
3548     UPDATELAYEREDWINDOWINFO info;
3549
3550     info.cbSize   = sizeof(info);
3551     info.hdcDst   = hdcDst;
3552     info.pptDst   = pptDst;
3553     info.psize    = psize;
3554     info.hdcSrc   = hdcSrc;
3555     info.pptSrc   = pptSrc;
3556     info.crKey    = crKey;
3557     info.pblend   = pblend;
3558     info.dwFlags  = dwFlags;
3559     info.prcDirty = NULL;
3560     return UpdateLayeredWindowIndirect( hwnd, &info );
3561 }
3562
3563
3564 /******************************************************************************
3565  *                    GetProcessDefaultLayout [USER32.@]
3566  *
3567  * Gets the default layout for parentless windows.
3568  */
3569 BOOL WINAPI GetProcessDefaultLayout( DWORD *layout )
3570 {
3571     if (!layout)
3572     {
3573         SetLastError( ERROR_NOACCESS );
3574         return FALSE;
3575     }
3576     if (process_layout == ~0u)
3577     {
3578         static const WCHAR translationW[] = { '\\','V','a','r','F','i','l','e','I','n','f','o',
3579                                               '\\','T','r','a','n','s','l','a','t','i','o','n', 0 };
3580         static const WCHAR filedescW[] = { '\\','S','t','r','i','n','g','F','i','l','e','I','n','f','o',
3581                                            '\\','%','0','4','x','%','0','4','x',
3582                                            '\\','F','i','l','e','D','e','s','c','r','i','p','t','i','o','n',0 };
3583         WCHAR *str, buffer[MAX_PATH];
3584         DWORD i, len, version_layout = 0;
3585         DWORD user_lang = GetUserDefaultLangID();
3586         DWORD *languages;
3587         void *data = NULL;
3588
3589         GetModuleFileNameW( 0, buffer, MAX_PATH );
3590         if (!(len = GetFileVersionInfoSizeW( buffer, NULL ))) goto done;
3591         if (!(data = HeapAlloc( GetProcessHeap(), 0, len ))) goto done;
3592         if (!GetFileVersionInfoW( buffer, 0, len, data )) goto done;
3593         if (!VerQueryValueW( data, translationW, (void **)&languages, &len ) || !len) goto done;
3594
3595         len /= sizeof(DWORD);
3596         for (i = 0; i < len; i++) if (LOWORD(languages[i]) == user_lang) break;
3597         if (i == len)  /* try neutral language */
3598             for (i = 0; i < len; i++)
3599                 if (LOWORD(languages[i]) == MAKELANGID( PRIMARYLANGID(user_lang), SUBLANG_NEUTRAL )) break;
3600         if (i == len) i = 0;  /* default to the first one */
3601
3602         sprintfW( buffer, filedescW, LOWORD(languages[i]), HIWORD(languages[i]) );
3603         if (!VerQueryValueW( data, buffer, (void **)&str, &len )) goto done;
3604         TRACE( "found description %s\n", debugstr_w( str ));
3605         if (str[0] == 0x200e && str[1] == 0x200e) version_layout = LAYOUT_RTL;
3606
3607     done:
3608         HeapFree( GetProcessHeap(), 0, data );
3609         process_layout = version_layout;
3610     }
3611     *layout = process_layout;
3612     return TRUE;
3613 }
3614
3615
3616 /******************************************************************************
3617  *                    SetProcessDefaultLayout [USER32.@]
3618  *
3619  * Sets the default layout for parentless windows.
3620  */
3621 BOOL WINAPI SetProcessDefaultLayout( DWORD layout )
3622 {
3623     process_layout = layout;
3624     return TRUE;
3625 }
3626
3627
3628 /* 64bit versions */
3629
3630 #ifdef GetWindowLongPtrW
3631 #undef GetWindowLongPtrW
3632 #endif
3633
3634 #ifdef GetWindowLongPtrA
3635 #undef GetWindowLongPtrA
3636 #endif
3637
3638 #ifdef SetWindowLongPtrW
3639 #undef SetWindowLongPtrW
3640 #endif
3641
3642 #ifdef SetWindowLongPtrA
3643 #undef SetWindowLongPtrA
3644 #endif
3645
3646 /*****************************************************************************
3647  *              GetWindowLongPtrW (USER32.@)
3648  */
3649 LONG_PTR WINAPI GetWindowLongPtrW( HWND hwnd, INT offset )
3650 {
3651     return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), TRUE );
3652 }
3653
3654 /*****************************************************************************
3655  *              GetWindowLongPtrA (USER32.@)
3656  */
3657 LONG_PTR WINAPI GetWindowLongPtrA( HWND hwnd, INT offset )
3658 {
3659     return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), FALSE );
3660 }
3661
3662 /*****************************************************************************
3663  *              SetWindowLongPtrW (USER32.@)
3664  */
3665 LONG_PTR WINAPI SetWindowLongPtrW( HWND hwnd, INT offset, LONG_PTR newval )
3666 {
3667     return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, TRUE );
3668 }
3669
3670 /*****************************************************************************
3671  *              SetWindowLongPtrA (USER32.@)
3672  */
3673 LONG_PTR WINAPI SetWindowLongPtrA( HWND hwnd, INT offset, LONG_PTR newval )
3674 {
3675     return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, FALSE );
3676 }