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