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