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