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