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