setupapi: Improve parameter validation for SetupCreateDiskSpaceListA/W.
[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 (WIN_GetRectangles( hwnd, COORDS_PARENT, &rect, NULL ))
1390     {
1391         /* yes, even if the CBT hook was called with HWND_TOP */
1392         HWND insert_after = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) ? HWND_BOTTOM : HWND_TOP;
1393         RECT client_rect = rect;
1394
1395         /* the rectangle is in screen coords for WM_NCCALCSIZE when wparam is FALSE */
1396         MapWindowPoints( parent, 0, (POINT *)&client_rect, 2 );
1397         SendMessageW( hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&client_rect );
1398         MapWindowPoints( 0, parent, (POINT *)&client_rect, 2 );
1399         set_window_pos( hwnd, insert_after, SWP_NOACTIVATE, &rect, &client_rect, NULL );
1400     }
1401     else return 0;
1402
1403     /* send WM_CREATE */
1404
1405     if (unicode)
1406         result = SendMessageW( hwnd, WM_CREATE, 0, (LPARAM)cs );
1407     else
1408         result = SendMessageA( hwnd, WM_CREATE, 0, (LPARAM)cs );
1409     if (result == -1) goto failed;
1410
1411     /* call the driver */
1412
1413     if (!USER_Driver->pCreateWindow( hwnd )) goto failed;
1414
1415     NotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_WINDOW, 0);
1416
1417     /* send the size messages */
1418
1419     if (!(wndPtr = WIN_GetPtr( hwnd )) ||
1420           wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
1421     if (!(wndPtr->flags & WIN_NEED_SIZE))
1422     {
1423         WIN_ReleasePtr( wndPtr );
1424         WIN_GetRectangles( hwnd, COORDS_PARENT, NULL, &rect );
1425         SendMessageW( hwnd, WM_SIZE, SIZE_RESTORED,
1426                       MAKELONG(rect.right-rect.left, rect.bottom-rect.top));
1427         SendMessageW( hwnd, WM_MOVE, 0, MAKELONG( rect.left, rect.top ) );
1428     }
1429     else WIN_ReleasePtr( wndPtr );
1430
1431     /* Show the window, maximizing or minimizing if needed */
1432
1433     style = WIN_SetStyle( hwnd, 0, WS_MAXIMIZE | WS_MINIMIZE );
1434     if (style & (WS_MINIMIZE | WS_MAXIMIZE))
1435     {
1436         RECT newPos;
1437         UINT swFlag = (style & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;
1438
1439         swFlag = WINPOS_MinMaximize( hwnd, swFlag, &newPos );
1440         swFlag |= SWP_FRAMECHANGED; /* Frame always gets changed */
1441         if (!(style & WS_VISIBLE) || (style & WS_CHILD) || GetActiveWindow()) swFlag |= SWP_NOACTIVATE;
1442         SetWindowPos( hwnd, 0, newPos.left, newPos.top, newPos.right - newPos.left,
1443                       newPos.bottom - newPos.top, swFlag );
1444     }
1445
1446     /* Notify the parent window only */
1447
1448     send_parent_notify( hwnd, WM_CREATE );
1449     if (!IsWindow( hwnd )) return 0;
1450
1451     if (cs->style & WS_VISIBLE)
1452     {
1453         if (cs->style & WS_MAXIMIZE)
1454             sw = SW_SHOW;
1455         else if (cs->style & WS_MINIMIZE)
1456             sw = SW_SHOWMINIMIZED;
1457
1458         ShowWindow( hwnd, sw );
1459         if (cs->dwExStyle & WS_EX_MDICHILD)
1460         {
1461             SendMessageW(cs->hwndParent, WM_MDIREFRESHMENU, 0, 0);
1462             /* ShowWindow won't activate child windows */
1463             SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE );
1464         }
1465     }
1466
1467     /* Call WH_SHELL hook */
1468
1469     if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1470         HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0, TRUE );
1471
1472     TRACE("created window %p\n", hwnd);
1473     return hwnd;
1474
1475 failed:
1476     WIN_DestroyWindow( hwnd );
1477     return 0;
1478 }
1479
1480
1481 /***********************************************************************
1482  *              CreateWindowExA (USER32.@)
1483  */
1484 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1485                                  LPCSTR windowName, DWORD style, INT x,
1486                                  INT y, INT width, INT height,
1487                                  HWND parent, HMENU menu,
1488                                  HINSTANCE instance, LPVOID data )
1489 {
1490     CREATESTRUCTA cs;
1491
1492     cs.lpCreateParams = data;
1493     cs.hInstance      = instance;
1494     cs.hMenu          = menu;
1495     cs.hwndParent     = parent;
1496     cs.x              = x;
1497     cs.y              = y;
1498     cs.cx             = width;
1499     cs.cy             = height;
1500     cs.style          = style;
1501     cs.lpszName       = windowName;
1502     cs.lpszClass      = className;
1503     cs.dwExStyle      = exStyle;
1504
1505     if (!IS_INTRESOURCE(className))
1506     {
1507         WCHAR bufferW[256];
1508         if (!MultiByteToWideChar( CP_ACP, 0, className, -1, bufferW, sizeof(bufferW)/sizeof(WCHAR) ))
1509             return 0;
1510         return wow_handlers.create_window( (CREATESTRUCTW *)&cs, bufferW, instance, FALSE );
1511     }
1512     /* Note: we rely on the fact that CREATESTRUCTA and */
1513     /* CREATESTRUCTW have the same layout. */
1514     return wow_handlers.create_window( (CREATESTRUCTW *)&cs, (LPCWSTR)className, instance, FALSE );
1515 }
1516
1517
1518 /***********************************************************************
1519  *              CreateWindowExW (USER32.@)
1520  */
1521 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1522                                  LPCWSTR windowName, DWORD style, INT x,
1523                                  INT y, INT width, INT height,
1524                                  HWND parent, HMENU menu,
1525                                  HINSTANCE instance, LPVOID data )
1526 {
1527     CREATESTRUCTW cs;
1528
1529     cs.lpCreateParams = data;
1530     cs.hInstance      = instance;
1531     cs.hMenu          = menu;
1532     cs.hwndParent     = parent;
1533     cs.x              = x;
1534     cs.y              = y;
1535     cs.cx             = width;
1536     cs.cy             = height;
1537     cs.style          = style;
1538     cs.lpszName       = windowName;
1539     cs.lpszClass      = className;
1540     cs.dwExStyle      = exStyle;
1541
1542     return wow_handlers.create_window( &cs, className, instance, TRUE );
1543 }
1544
1545
1546 /***********************************************************************
1547  *           WIN_SendDestroyMsg
1548  */
1549 static void WIN_SendDestroyMsg( HWND hwnd )
1550 {
1551     GUITHREADINFO info;
1552
1553     if (GetGUIThreadInfo( GetCurrentThreadId(), &info ))
1554     {
1555         if (hwnd == info.hwndCaret) DestroyCaret();
1556         if (hwnd == info.hwndActive) WINPOS_ActivateOtherWindow( hwnd );
1557     }
1558
1559     /*
1560      * Send the WM_DESTROY to the window.
1561      */
1562     SendMessageW( hwnd, WM_DESTROY, 0, 0);
1563
1564     /*
1565      * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1566      * make sure that the window still exists when we come back.
1567      */
1568     if (IsWindow(hwnd))
1569     {
1570         HWND* pWndArray;
1571         int i;
1572
1573         if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1574
1575         for (i = 0; pWndArray[i]; i++)
1576         {
1577             if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1578         }
1579         HeapFree( GetProcessHeap(), 0, pWndArray );
1580     }
1581     else
1582       WARN("\tdestroyed itself while in WM_DESTROY!\n");
1583 }
1584
1585
1586 /***********************************************************************
1587  *              DestroyWindow (USER32.@)
1588  */
1589 BOOL WINAPI DestroyWindow( HWND hwnd )
1590 {
1591     BOOL is_child;
1592
1593     if (!(hwnd = WIN_IsCurrentThread( hwnd )) || is_desktop_window( hwnd ))
1594     {
1595         SetLastError( ERROR_ACCESS_DENIED );
1596         return FALSE;
1597     }
1598
1599     TRACE("(%p)\n", hwnd);
1600
1601       /* Call hooks */
1602
1603     if (HOOK_CallHooks( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0, TRUE )) return FALSE;
1604
1605     if (MENU_IsMenuActive() == hwnd)
1606         EndMenu();
1607
1608     is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;
1609
1610     if (is_child)
1611     {
1612         if (!USER_IsExitingThread( GetCurrentThreadId() ))
1613             send_parent_notify( hwnd, WM_DESTROY );
1614     }
1615     else if (!GetWindow( hwnd, GW_OWNER ))
1616     {
1617         HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
1618         /* FIXME: clean up palette - see "Internals" p.352 */
1619     }
1620
1621     if (!IsWindow(hwnd)) return TRUE;
1622
1623       /* Hide the window */
1624     if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)
1625     {
1626         /* Only child windows receive WM_SHOWWINDOW in DestroyWindow() */
1627         if (is_child)
1628             ShowWindow( hwnd, SW_HIDE );
1629         else
1630             SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE |
1631                           SWP_NOZORDER | SWP_NOACTIVATE | SWP_HIDEWINDOW );
1632     }
1633
1634     if (!IsWindow(hwnd)) return TRUE;
1635
1636       /* Recursively destroy owned windows */
1637
1638     if (!is_child)
1639     {
1640         for (;;)
1641         {
1642             int i, got_one = 0;
1643             HWND *list = WIN_ListChildren( GetDesktopWindow() );
1644             if (list)
1645             {
1646                 for (i = 0; list[i]; i++)
1647                 {
1648                     if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1649                     if (WIN_IsCurrentThread( list[i] ))
1650                     {
1651                         DestroyWindow( list[i] );
1652                         got_one = 1;
1653                         continue;
1654                     }
1655                     WIN_SetOwner( list[i], 0 );
1656                 }
1657                 HeapFree( GetProcessHeap(), 0, list );
1658             }
1659             if (!got_one) break;
1660         }
1661     }
1662
1663       /* Send destroy messages */
1664
1665     WIN_SendDestroyMsg( hwnd );
1666     if (!IsWindow( hwnd )) return TRUE;
1667
1668     if (GetClipboardOwner() == hwnd)
1669         CLIPBOARD_ReleaseOwner();
1670
1671       /* Destroy the window storage */
1672
1673     WIN_DestroyWindow( hwnd );
1674     return TRUE;
1675 }
1676
1677
1678 /***********************************************************************
1679  *              CloseWindow (USER32.@)
1680  */
1681 BOOL WINAPI CloseWindow( HWND hwnd )
1682 {
1683     if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1684     ShowWindow( hwnd, SW_MINIMIZE );
1685     return TRUE;
1686 }
1687
1688
1689 /***********************************************************************
1690  *              OpenIcon (USER32.@)
1691  */
1692 BOOL WINAPI OpenIcon( HWND hwnd )
1693 {
1694     if (!IsIconic( hwnd )) return FALSE;
1695     ShowWindow( hwnd, SW_SHOWNORMAL );
1696     return TRUE;
1697 }
1698
1699
1700 /***********************************************************************
1701  *              FindWindowExW (USER32.@)
1702  */
1703 HWND WINAPI FindWindowExW( HWND parent, HWND child, LPCWSTR className, LPCWSTR title )
1704 {
1705     HWND *list = NULL;
1706     HWND retvalue = 0;
1707     int i = 0, len = 0;
1708     WCHAR *buffer = NULL;
1709
1710     if (!parent && child) parent = GetDesktopWindow();
1711     else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
1712
1713     if (title)
1714     {
1715         len = strlenW(title) + 1;  /* one extra char to check for chars beyond the end */
1716         if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1717     }
1718
1719     if (!(list = list_window_children( 0, parent, className, 0 ))) goto done;
1720
1721     if (child)
1722     {
1723         child = WIN_GetFullHandle( child );
1724         while (list[i] && list[i] != child) i++;
1725         if (!list[i]) goto done;
1726         i++;  /* start from next window */
1727     }
1728
1729     if (title)
1730     {
1731         while (list[i])
1732         {
1733             if (GetWindowTextW( list[i], buffer, len + 1 ) && !strcmpiW( buffer, title )) break;
1734             i++;
1735         }
1736     }
1737     retvalue = list[i];
1738
1739  done:
1740     HeapFree( GetProcessHeap(), 0, list );
1741     HeapFree( GetProcessHeap(), 0, buffer );
1742     return retvalue;
1743 }
1744
1745
1746
1747 /***********************************************************************
1748  *              FindWindowA (USER32.@)
1749  */
1750 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1751 {
1752     HWND ret = FindWindowExA( 0, 0, className, title );
1753     if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1754     return ret;
1755 }
1756
1757
1758 /***********************************************************************
1759  *              FindWindowExA (USER32.@)
1760  */
1761 HWND WINAPI FindWindowExA( HWND parent, HWND child, LPCSTR className, LPCSTR title )
1762 {
1763     LPWSTR titleW = NULL;
1764     HWND hwnd = 0;
1765
1766     if (title)
1767     {
1768         DWORD len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
1769         if (!(titleW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
1770         MultiByteToWideChar( CP_ACP, 0, title, -1, titleW, len );
1771     }
1772
1773     if (!IS_INTRESOURCE(className))
1774     {
1775         WCHAR classW[256];
1776         if (MultiByteToWideChar( CP_ACP, 0, className, -1, classW, sizeof(classW)/sizeof(WCHAR) ))
1777             hwnd = FindWindowExW( parent, child, classW, titleW );
1778     }
1779     else
1780     {
1781         hwnd = FindWindowExW( parent, child, (LPCWSTR)className, titleW );
1782     }
1783
1784     HeapFree( GetProcessHeap(), 0, titleW );
1785     return hwnd;
1786 }
1787
1788
1789 /***********************************************************************
1790  *              FindWindowW (USER32.@)
1791  */
1792 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
1793 {
1794     return FindWindowExW( 0, 0, className, title );
1795 }
1796
1797
1798 /**********************************************************************
1799  *              GetDesktopWindow (USER32.@)
1800  */
1801 HWND WINAPI GetDesktopWindow(void)
1802 {
1803     struct user_thread_info *thread_info = get_user_thread_info();
1804
1805     if (thread_info->top_window) return thread_info->top_window;
1806
1807     SERVER_START_REQ( get_desktop_window )
1808     {
1809         req->force = 0;
1810         if (!wine_server_call( req ))
1811         {
1812             thread_info->top_window = wine_server_ptr_handle( reply->top_window );
1813             thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
1814         }
1815     }
1816     SERVER_END_REQ;
1817
1818     if (!thread_info->top_window)
1819     {
1820         USEROBJECTFLAGS flags;
1821         if (!GetUserObjectInformationW( GetProcessWindowStation(), UOI_FLAGS, &flags,
1822                                         sizeof(flags), NULL ) || (flags.dwFlags & WSF_VISIBLE))
1823         {
1824             static const WCHAR explorer[] = {'\\','e','x','p','l','o','r','e','r','.','e','x','e',0};
1825             static const WCHAR args[] = {' ','/','d','e','s','k','t','o','p',0};
1826             STARTUPINFOW si;
1827             PROCESS_INFORMATION pi;
1828             WCHAR windir[MAX_PATH];
1829             WCHAR app[MAX_PATH + sizeof(explorer)/sizeof(WCHAR)];
1830             WCHAR cmdline[MAX_PATH + (sizeof(explorer) + sizeof(args))/sizeof(WCHAR)];
1831             void *redir;
1832
1833             memset( &si, 0, sizeof(si) );
1834             si.cb = sizeof(si);
1835             si.dwFlags = STARTF_USESTDHANDLES;
1836             si.hStdInput  = 0;
1837             si.hStdOutput = 0;
1838             si.hStdError  = GetStdHandle( STD_ERROR_HANDLE );
1839
1840             GetSystemDirectoryW( windir, MAX_PATH );
1841             strcpyW( app, windir );
1842             strcatW( app, explorer );
1843             strcpyW( cmdline, app );
1844             strcatW( cmdline, args );
1845
1846             Wow64DisableWow64FsRedirection( &redir );
1847             if (CreateProcessW( app, cmdline, NULL, NULL, FALSE, DETACHED_PROCESS,
1848                                 NULL, windir, &si, &pi ))
1849             {
1850                 TRACE( "started explorer pid %04x tid %04x\n", pi.dwProcessId, pi.dwThreadId );
1851                 WaitForInputIdle( pi.hProcess, 10000 );
1852                 CloseHandle( pi.hThread );
1853                 CloseHandle( pi.hProcess );
1854             }
1855             else WARN( "failed to start explorer, err %d\n", GetLastError() );
1856             Wow64RevertWow64FsRedirection( redir );
1857         }
1858         else TRACE( "not starting explorer since winstation is not visible\n" );
1859
1860         SERVER_START_REQ( get_desktop_window )
1861         {
1862             req->force = 1;
1863             if (!wine_server_call( req ))
1864             {
1865                 thread_info->top_window = wine_server_ptr_handle( reply->top_window );
1866                 thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
1867             }
1868         }
1869         SERVER_END_REQ;
1870     }
1871
1872     if (!thread_info->top_window || !USER_Driver->pCreateDesktopWindow( thread_info->top_window ))
1873         ERR( "failed to create desktop window\n" );
1874
1875     return thread_info->top_window;
1876 }
1877
1878
1879 /*******************************************************************
1880  *              EnableWindow (USER32.@)
1881  */
1882 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
1883 {
1884     BOOL retvalue;
1885     HWND full_handle;
1886
1887     if (is_broadcast(hwnd))
1888     {
1889         SetLastError( ERROR_INVALID_PARAMETER );
1890         return FALSE;
1891     }
1892
1893     if (!(full_handle = WIN_IsCurrentThread( hwnd )))
1894         return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
1895
1896     hwnd = full_handle;
1897
1898     TRACE("( %p, %d )\n", hwnd, enable);
1899
1900     retvalue = !IsWindowEnabled( hwnd );
1901
1902     if (enable && retvalue)
1903     {
1904         WIN_SetStyle( hwnd, 0, WS_DISABLED );
1905         SendMessageW( hwnd, WM_ENABLE, TRUE, 0 );
1906     }
1907     else if (!enable && !retvalue)
1908     {
1909         HWND capture_wnd;
1910
1911         SendMessageW( hwnd, WM_CANCELMODE, 0, 0);
1912
1913         WIN_SetStyle( hwnd, WS_DISABLED, 0 );
1914
1915         if (hwnd == GetFocus())
1916             SetFocus( 0 );  /* A disabled window can't have the focus */
1917
1918         capture_wnd = GetCapture();
1919         if (hwnd == capture_wnd || IsChild(hwnd, capture_wnd))
1920             ReleaseCapture();  /* A disabled window can't capture the mouse */
1921
1922         SendMessageW( hwnd, WM_ENABLE, FALSE, 0 );
1923     }
1924     return retvalue;
1925 }
1926
1927
1928 /***********************************************************************
1929  *              IsWindowEnabled (USER32.@)
1930  */
1931 BOOL WINAPI IsWindowEnabled(HWND hWnd)
1932 {
1933     return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
1934 }
1935
1936
1937 /***********************************************************************
1938  *              IsWindowUnicode (USER32.@)
1939  */
1940 BOOL WINAPI IsWindowUnicode( HWND hwnd )
1941 {
1942     WND * wndPtr;
1943     BOOL retvalue = FALSE;
1944
1945     if (!(wndPtr = WIN_GetPtr(hwnd))) return FALSE;
1946
1947     if (wndPtr == WND_DESKTOP) return TRUE;
1948
1949     if (wndPtr != WND_OTHER_PROCESS)
1950     {
1951         retvalue = (wndPtr->flags & WIN_ISUNICODE) != 0;
1952         WIN_ReleasePtr( wndPtr );
1953     }
1954     else
1955     {
1956         SERVER_START_REQ( get_window_info )
1957         {
1958             req->handle = wine_server_user_handle( hwnd );
1959             if (!wine_server_call_err( req )) retvalue = reply->is_unicode;
1960         }
1961         SERVER_END_REQ;
1962     }
1963     return retvalue;
1964 }
1965
1966
1967 /**********************************************************************
1968  *           WIN_GetWindowLong
1969  *
1970  * Helper function for GetWindowLong().
1971  */
1972 static LONG_PTR WIN_GetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicode )
1973 {
1974     LONG_PTR retvalue = 0;
1975     WND *wndPtr;
1976
1977     if (offset == GWLP_HWNDPARENT)
1978     {
1979         HWND parent = GetAncestor( hwnd, GA_PARENT );
1980         if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
1981         return (ULONG_PTR)parent;
1982     }
1983
1984     if (!(wndPtr = WIN_GetPtr( hwnd )))
1985     {
1986         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1987         return 0;
1988     }
1989
1990     if (wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP)
1991     {
1992         if (offset == GWLP_WNDPROC)
1993         {
1994             SetLastError( ERROR_ACCESS_DENIED );
1995             return 0;
1996         }
1997         SERVER_START_REQ( set_window_info )
1998         {
1999             req->handle = wine_server_user_handle( hwnd );
2000             req->flags  = 0;  /* don't set anything, just retrieve */
2001             req->extra_offset = (offset >= 0) ? offset : -1;
2002             req->extra_size = (offset >= 0) ? size : 0;
2003             if (!wine_server_call_err( req ))
2004             {
2005                 switch(offset)
2006                 {
2007                 case GWL_STYLE:      retvalue = reply->old_style; break;
2008                 case GWL_EXSTYLE:    retvalue = reply->old_ex_style; break;
2009                 case GWLP_ID:        retvalue = reply->old_id; break;
2010                 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wine_server_get_ptr( reply->old_instance ); break;
2011                 case GWLP_USERDATA:  retvalue = reply->old_user_data; break;
2012                 default:
2013                     if (offset >= 0) retvalue = get_win_data( &reply->old_extra_value, size );
2014                     else SetLastError( ERROR_INVALID_INDEX );
2015                     break;
2016                 }
2017             }
2018         }
2019         SERVER_END_REQ;
2020         return retvalue;
2021     }
2022
2023     /* now we have a valid wndPtr */
2024
2025     if (offset >= 0)
2026     {
2027         if (offset > (int)(wndPtr->cbWndExtra - size))
2028         {
2029             WARN("Invalid offset %d\n", offset );
2030             WIN_ReleasePtr( wndPtr );
2031             SetLastError( ERROR_INVALID_INDEX );
2032             return 0;
2033         }
2034         retvalue = get_win_data( (char *)wndPtr->wExtra + offset, size );
2035
2036         /* Special case for dialog window procedure */
2037         if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && wndPtr->dlgInfo)
2038             retvalue = (LONG_PTR)WINPROC_GetProc( (WNDPROC)retvalue, unicode );
2039         WIN_ReleasePtr( wndPtr );
2040         return retvalue;
2041     }
2042
2043     switch(offset)
2044     {
2045     case GWLP_USERDATA:  retvalue = wndPtr->userdata; break;
2046     case GWL_STYLE:      retvalue = wndPtr->dwStyle; break;
2047     case GWL_EXSTYLE:    retvalue = wndPtr->dwExStyle; break;
2048     case GWLP_ID:        retvalue = wndPtr->wIDmenu; break;
2049     case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hInstance; break;
2050     case GWLP_WNDPROC:
2051         /* This looks like a hack only for the edit control (see tests). This makes these controls
2052          * more tolerant to A/W mismatches. The lack of W->A->W conversion for such a mismatch suggests
2053          * that the hack is in GetWindowLongPtr[AW], not in winprocs.
2054          */
2055         if (wndPtr->winproc == BUILTIN_WINPROC(WINPROC_EDIT) && (!unicode != !(wndPtr->flags & WIN_ISUNICODE)))
2056             retvalue = (ULONG_PTR)wndPtr->winproc;
2057         else
2058             retvalue = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, unicode );
2059         break;
2060     default:
2061         WARN("Unknown offset %d\n", offset );
2062         SetLastError( ERROR_INVALID_INDEX );
2063         break;
2064     }
2065     WIN_ReleasePtr(wndPtr);
2066     return retvalue;
2067 }
2068
2069
2070 /**********************************************************************
2071  *           WIN_SetWindowLong
2072  *
2073  * Helper function for SetWindowLong().
2074  *
2075  * 0 is the failure code. However, in the case of failure SetLastError
2076  * must be set to distinguish between a 0 return value and a failure.
2077  */
2078 LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, UINT size, LONG_PTR newval, BOOL unicode )
2079 {
2080     STYLESTRUCT style;
2081     BOOL ok;
2082     LONG_PTR retval = 0;
2083     WND *wndPtr;
2084
2085     TRACE( "%p %d %lx %c\n", hwnd, offset, newval, unicode ? 'W' : 'A' );
2086
2087     if (is_broadcast(hwnd))
2088     {
2089         SetLastError( ERROR_INVALID_PARAMETER );
2090         return FALSE;
2091     }
2092
2093     if (!(wndPtr = WIN_GetPtr( hwnd )))
2094     {
2095         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2096         return 0;
2097     }
2098     if (wndPtr == WND_DESKTOP)
2099     {
2100         /* can't change anything on the desktop window */
2101         SetLastError( ERROR_ACCESS_DENIED );
2102         return 0;
2103     }
2104     if (wndPtr == WND_OTHER_PROCESS)
2105     {
2106         if (offset == GWLP_WNDPROC)
2107         {
2108             SetLastError( ERROR_ACCESS_DENIED );
2109             return 0;
2110         }
2111         if (offset > 32767 || offset < -32767)
2112         {
2113             SetLastError( ERROR_INVALID_INDEX );
2114             return 0;
2115         }
2116         return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, MAKEWPARAM( offset, size ), newval );
2117     }
2118
2119     /* first some special cases */
2120     switch( offset )
2121     {
2122     case GWL_STYLE:
2123         style.styleOld = wndPtr->dwStyle;
2124         style.styleNew = newval;
2125         WIN_ReleasePtr( wndPtr );
2126         SendMessageW( hwnd, WM_STYLECHANGING, GWL_STYLE, (LPARAM)&style );
2127         if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2128         newval = style.styleNew;
2129         /* WS_CLIPSIBLINGS can't be reset on top-level windows */
2130         if (wndPtr->parent == GetDesktopWindow()) newval |= WS_CLIPSIBLINGS;
2131         break;
2132     case GWL_EXSTYLE:
2133         style.styleOld = wndPtr->dwExStyle;
2134         style.styleNew = newval;
2135         WIN_ReleasePtr( wndPtr );
2136         SendMessageW( hwnd, WM_STYLECHANGING, GWL_EXSTYLE, (LPARAM)&style );
2137         if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2138         /* WS_EX_TOPMOST can only be changed through SetWindowPos */
2139         newval = (style.styleNew & ~WS_EX_TOPMOST) | (wndPtr->dwExStyle & WS_EX_TOPMOST);
2140         /* WS_EX_WINDOWEDGE depends on some other styles */
2141         if ((newval & WS_EX_DLGMODALFRAME) || (wndPtr->dwStyle & WS_THICKFRAME))
2142             newval |= WS_EX_WINDOWEDGE;
2143         else if (wndPtr->dwStyle & (WS_CHILD|WS_POPUP))
2144             newval &= ~WS_EX_WINDOWEDGE;
2145         break;
2146     case GWLP_HWNDPARENT:
2147         if (wndPtr->parent == GetDesktopWindow())
2148         {
2149             WIN_ReleasePtr( wndPtr );
2150             return (ULONG_PTR)WIN_SetOwner( hwnd, (HWND)newval );
2151         }
2152         else
2153         {
2154             WIN_ReleasePtr( wndPtr );
2155             return (ULONG_PTR)SetParent( hwnd, (HWND)newval );
2156         }
2157     case GWLP_WNDPROC:
2158     {
2159         WNDPROC proc;
2160         UINT old_flags = wndPtr->flags;
2161         retval = WIN_GetWindowLong( hwnd, offset, size, unicode );
2162         proc = WINPROC_AllocProc( (WNDPROC)newval, unicode );
2163         if (proc) wndPtr->winproc = proc;
2164         if (WINPROC_IsUnicode( proc, unicode )) wndPtr->flags |= WIN_ISUNICODE;
2165         else wndPtr->flags &= ~WIN_ISUNICODE;
2166         if (!((old_flags ^ wndPtr->flags) & WIN_ISUNICODE))
2167         {
2168             WIN_ReleasePtr( wndPtr );
2169             return retval;
2170         }
2171         /* update is_unicode flag on the server side */
2172         break;
2173     }
2174     case GWLP_ID:
2175     case GWLP_HINSTANCE:
2176     case GWLP_USERDATA:
2177         break;
2178     case DWLP_DLGPROC:
2179         if ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
2180             (size == sizeof(LONG_PTR)) && wndPtr->dlgInfo)
2181         {
2182             WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWLP_DLGPROC);
2183             retval = (ULONG_PTR)WINPROC_GetProc( *ptr, unicode );
2184             *ptr = WINPROC_AllocProc( (WNDPROC)newval, unicode );
2185             WIN_ReleasePtr( wndPtr );
2186             return retval;
2187         }
2188         /* fall through */
2189     default:
2190         if (offset < 0 || offset > (int)(wndPtr->cbWndExtra - size))
2191         {
2192             WARN("Invalid offset %d\n", offset );
2193             WIN_ReleasePtr( wndPtr );
2194             SetLastError( ERROR_INVALID_INDEX );
2195             return 0;
2196         }
2197         else if (get_win_data( (char *)wndPtr->wExtra + offset, size ) == newval)
2198         {
2199             /* already set to the same value */
2200             WIN_ReleasePtr( wndPtr );
2201             return newval;
2202         }
2203         break;
2204     }
2205
2206     SERVER_START_REQ( set_window_info )
2207     {
2208         req->handle = wine_server_user_handle( hwnd );
2209         req->extra_offset = -1;
2210         switch(offset)
2211         {
2212         case GWL_STYLE:
2213             req->flags = SET_WIN_STYLE;
2214             req->style = newval;
2215             break;
2216         case GWL_EXSTYLE:
2217             req->flags = SET_WIN_EXSTYLE;
2218             req->ex_style = newval;
2219             break;
2220         case GWLP_ID:
2221             req->flags = SET_WIN_ID;
2222             req->id = newval;
2223             break;
2224         case GWLP_HINSTANCE:
2225             req->flags = SET_WIN_INSTANCE;
2226             req->instance = wine_server_client_ptr( (void *)newval );
2227             break;
2228         case GWLP_WNDPROC:
2229             req->flags = SET_WIN_UNICODE;
2230             req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
2231             break;
2232         case GWLP_USERDATA:
2233             req->flags = SET_WIN_USERDATA;
2234             req->user_data = newval;
2235             break;
2236         default:
2237             req->flags = SET_WIN_EXTRA;
2238             req->extra_offset = offset;
2239             req->extra_size = size;
2240             set_win_data( &req->extra_value, newval, size );
2241         }
2242         if ((ok = !wine_server_call_err( req )))
2243         {
2244             switch(offset)
2245             {
2246             case GWL_STYLE:
2247                 wndPtr->dwStyle = newval;
2248                 retval = reply->old_style;
2249                 break;
2250             case GWL_EXSTYLE:
2251                 wndPtr->dwExStyle = newval;
2252                 retval = reply->old_ex_style;
2253                 break;
2254             case GWLP_ID:
2255                 wndPtr->wIDmenu = newval;
2256                 retval = reply->old_id;
2257                 break;
2258             case GWLP_HINSTANCE:
2259                 wndPtr->hInstance = (HINSTANCE)newval;
2260                 retval = (ULONG_PTR)wine_server_get_ptr( reply->old_instance );
2261                 break;
2262             case GWLP_WNDPROC:
2263                 break;
2264             case GWLP_USERDATA:
2265                 wndPtr->userdata = newval;
2266                 retval = reply->old_user_data;
2267                 break;
2268             default:
2269                 retval = get_win_data( (char *)wndPtr->wExtra + offset, size );
2270                 set_win_data( (char *)wndPtr->wExtra + offset, newval, size );
2271                 break;
2272             }
2273         }
2274     }
2275     SERVER_END_REQ;
2276     WIN_ReleasePtr( wndPtr );
2277
2278     if (!ok) return 0;
2279
2280     if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2281     {
2282         style.styleOld = retval;
2283         style.styleNew = newval;
2284         USER_Driver->pSetWindowStyle( hwnd, offset, &style );
2285         SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2286     }
2287
2288     return retval;
2289 }
2290
2291
2292 /**********************************************************************
2293  *              GetWindowWord (USER32.@)
2294  */
2295 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
2296 {
2297     switch(offset)
2298     {
2299     case GWLP_ID:
2300     case GWLP_HINSTANCE:
2301     case GWLP_HWNDPARENT:
2302         break;
2303     default:
2304         if (offset < 0)
2305         {
2306             WARN("Invalid offset %d\n", offset );
2307             SetLastError( ERROR_INVALID_INDEX );
2308             return 0;
2309         }
2310         break;
2311     }
2312     return WIN_GetWindowLong( hwnd, offset, sizeof(WORD), FALSE );
2313 }
2314
2315
2316 /**********************************************************************
2317  *              GetWindowLongA (USER32.@)
2318  */
2319 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2320 {
2321     return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), FALSE );
2322 }
2323
2324
2325 /**********************************************************************
2326  *              GetWindowLongW (USER32.@)
2327  */
2328 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2329 {
2330     return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), TRUE );
2331 }
2332
2333
2334 /**********************************************************************
2335  *              SetWindowWord (USER32.@)
2336  */
2337 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
2338 {
2339     switch(offset)
2340     {
2341     case GWLP_ID:
2342     case GWLP_HINSTANCE:
2343     case GWLP_HWNDPARENT:
2344         break;
2345     default:
2346         if (offset < 0)
2347         {
2348             WARN("Invalid offset %d\n", offset );
2349             SetLastError( ERROR_INVALID_INDEX );
2350             return 0;
2351         }
2352         break;
2353     }
2354     return WIN_SetWindowLong( hwnd, offset, sizeof(WORD), newval, FALSE );
2355 }
2356
2357
2358 /**********************************************************************
2359  *              SetWindowLongA (USER32.@)
2360  *
2361  * See SetWindowLongW.
2362  */
2363 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2364 {
2365     return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, FALSE );
2366 }
2367
2368
2369 /**********************************************************************
2370  *              SetWindowLongW (USER32.@) Set window attribute
2371  *
2372  * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2373  * value in a window's extra memory.
2374  *
2375  * The _hwnd_ parameter specifies the window.  is the handle to a
2376  * window that has extra memory. The _newval_ parameter contains the
2377  * new attribute or extra memory value.  If positive, the _offset_
2378  * parameter is the byte-addressed location in the window's extra
2379  * memory to set.  If negative, _offset_ specifies the window
2380  * attribute to set, and should be one of the following values:
2381  *
2382  * GWL_EXSTYLE      The window's extended window style
2383  *
2384  * GWL_STYLE        The window's window style.
2385  *
2386  * GWLP_WNDPROC     Pointer to the window's window procedure.
2387  *
2388  * GWLP_HINSTANCE   The window's pplication instance handle.
2389  *
2390  * GWLP_ID          The window's identifier.
2391  *
2392  * GWLP_USERDATA    The window's user-specified data.
2393  *
2394  * If the window is a dialog box, the _offset_ parameter can be one of
2395  * the following values:
2396  *
2397  * DWLP_DLGPROC     The address of the window's dialog box procedure.
2398  *
2399  * DWLP_MSGRESULT   The return value of a message
2400  *                  that the dialog box procedure processed.
2401  *
2402  * DWLP_USER        Application specific information.
2403  *
2404  * RETURNS
2405  *
2406  * If successful, returns the previous value located at _offset_. Otherwise,
2407  * returns 0.
2408  *
2409  * NOTES
2410  *
2411  * Extra memory for a window class is specified by a nonzero cbWndExtra
2412  * parameter of the WNDCLASS structure passed to RegisterClass() at the
2413  * time of class creation.
2414  *
2415  * Using GWL_WNDPROC to set a new window procedure effectively creates
2416  * a window subclass. Use CallWindowProc() in the new windows procedure
2417  * to pass messages to the superclass's window procedure.
2418  *
2419  * The user data is reserved for use by the application which created
2420  * the window.
2421  *
2422  * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2423  * instead, call the EnableWindow() function to change the window's
2424  * disabled state.
2425  *
2426  * Do not use GWL_HWNDPARENT to reset the window's parent, use
2427  * SetParent() instead.
2428  *
2429  * Win95:
2430  * When offset is GWL_STYLE and the calling app's ver is 4.0,
2431  * it sends WM_STYLECHANGING before changing the settings
2432  * and WM_STYLECHANGED afterwards.
2433  * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2434  */
2435 LONG WINAPI SetWindowLongW(
2436     HWND hwnd,  /* [in] window to alter */
2437     INT offset, /* [in] offset, in bytes, of location to alter */
2438     LONG newval /* [in] new value of location */
2439 ) {
2440     return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, TRUE );
2441 }
2442
2443
2444 /*******************************************************************
2445  *              GetWindowTextA (USER32.@)
2446  */
2447 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2448 {
2449     WCHAR *buffer;
2450
2451     if (!lpString) return 0;
2452
2453     if (WIN_IsCurrentProcess( hwnd ))
2454         return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2455
2456     /* when window belongs to other process, don't send a message */
2457     if (nMaxCount <= 0) return 0;
2458     if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2459     get_server_window_text( hwnd, buffer, nMaxCount );
2460     if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2461         lpString[nMaxCount-1] = 0;
2462     HeapFree( GetProcessHeap(), 0, buffer );
2463     return strlen(lpString);
2464 }
2465
2466
2467 /*******************************************************************
2468  *              InternalGetWindowText (USER32.@)
2469  */
2470 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2471 {
2472     WND *win;
2473
2474     if (nMaxCount <= 0) return 0;
2475     if (!(win = WIN_GetPtr( hwnd ))) return 0;
2476     if (win == WND_DESKTOP) lpString[0] = 0;
2477     else if (win != WND_OTHER_PROCESS)
2478     {
2479         if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2480         else lpString[0] = 0;
2481         WIN_ReleasePtr( win );
2482     }
2483     else
2484     {
2485         get_server_window_text( hwnd, lpString, nMaxCount );
2486     }
2487     return strlenW(lpString);
2488 }
2489
2490
2491 /*******************************************************************
2492  *              GetWindowTextW (USER32.@)
2493  */
2494 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2495 {
2496     if (!lpString) return 0;
2497
2498     if (WIN_IsCurrentProcess( hwnd ))
2499         return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2500
2501     /* when window belongs to other process, don't send a message */
2502     if (nMaxCount <= 0) return 0;
2503     get_server_window_text( hwnd, lpString, nMaxCount );
2504     return strlenW(lpString);
2505 }
2506
2507
2508 /*******************************************************************
2509  *              SetWindowTextA (USER32.@)
2510  *              SetWindowText  (USER32.@)
2511  */
2512 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2513 {
2514     if (is_broadcast(hwnd))
2515     {
2516         SetLastError( ERROR_INVALID_PARAMETER );
2517         return FALSE;
2518     }
2519     if (!WIN_IsCurrentProcess( hwnd ))
2520         WARN( "setting text %s of other process window %p should not use SendMessage\n",
2521                debugstr_a(lpString), hwnd );
2522     return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2523 }
2524
2525
2526 /*******************************************************************
2527  *              SetWindowTextW (USER32.@)
2528  */
2529 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2530 {
2531     if (is_broadcast(hwnd))
2532     {
2533         SetLastError( ERROR_INVALID_PARAMETER );
2534         return FALSE;
2535     }
2536     if (!WIN_IsCurrentProcess( hwnd ))
2537         WARN( "setting text %s of other process window %p should not use SendMessage\n",
2538                debugstr_w(lpString), hwnd );
2539     return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2540 }
2541
2542
2543 /*******************************************************************
2544  *              GetWindowTextLengthA (USER32.@)
2545  */
2546 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2547 {
2548     return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2549 }
2550
2551 /*******************************************************************
2552  *              GetWindowTextLengthW (USER32.@)
2553  */
2554 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2555 {
2556     return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2557 }
2558
2559
2560 /*******************************************************************
2561  *              IsWindow (USER32.@)
2562  */
2563 BOOL WINAPI IsWindow( HWND hwnd )
2564 {
2565     WND *ptr;
2566     BOOL ret;
2567
2568     if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2569     if (ptr == WND_DESKTOP) return TRUE;
2570
2571     if (ptr != WND_OTHER_PROCESS)
2572     {
2573         WIN_ReleasePtr( ptr );
2574         return TRUE;
2575     }
2576
2577     /* check other processes */
2578     SERVER_START_REQ( get_window_info )
2579     {
2580         req->handle = wine_server_user_handle( hwnd );
2581         ret = !wine_server_call_err( req );
2582     }
2583     SERVER_END_REQ;
2584     return ret;
2585 }
2586
2587
2588 /***********************************************************************
2589  *              GetWindowThreadProcessId (USER32.@)
2590  */
2591 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2592 {
2593     WND *ptr;
2594     DWORD tid = 0;
2595
2596     if (!(ptr = WIN_GetPtr( hwnd )))
2597     {
2598         SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2599         return 0;
2600     }
2601
2602     if (ptr != WND_OTHER_PROCESS && ptr != WND_DESKTOP)
2603     {
2604         /* got a valid window */
2605         tid = ptr->tid;
2606         if (process) *process = GetCurrentProcessId();
2607         WIN_ReleasePtr( ptr );
2608         return tid;
2609     }
2610
2611     /* check other processes */
2612     SERVER_START_REQ( get_window_info )
2613     {
2614         req->handle = wine_server_user_handle( hwnd );
2615         if (!wine_server_call_err( req ))
2616         {
2617             tid = (DWORD)reply->tid;
2618             if (process) *process = (DWORD)reply->pid;
2619         }
2620     }
2621     SERVER_END_REQ;
2622     return tid;
2623 }
2624
2625
2626 /*****************************************************************
2627  *              GetParent (USER32.@)
2628  */
2629 HWND WINAPI GetParent( HWND hwnd )
2630 {
2631     WND *wndPtr;
2632     HWND retvalue = 0;
2633
2634     if (!(wndPtr = WIN_GetPtr( hwnd )))
2635     {
2636         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2637         return 0;
2638     }
2639     if (wndPtr == WND_DESKTOP) return 0;
2640     if (wndPtr == WND_OTHER_PROCESS)
2641     {
2642         LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2643         if (style & (WS_POPUP | WS_CHILD))
2644         {
2645             SERVER_START_REQ( get_window_tree )
2646             {
2647                 req->handle = wine_server_user_handle( hwnd );
2648                 if (!wine_server_call_err( req ))
2649                 {
2650                     if (style & WS_POPUP) retvalue = wine_server_ptr_handle( reply->owner );
2651                     else if (style & WS_CHILD) retvalue = wine_server_ptr_handle( reply->parent );
2652                 }
2653             }
2654             SERVER_END_REQ;
2655         }
2656     }
2657     else
2658     {
2659         if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2660         else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2661         WIN_ReleasePtr( wndPtr );
2662     }
2663     return retvalue;
2664 }
2665
2666
2667 /*****************************************************************
2668  *              GetAncestor (USER32.@)
2669  */
2670 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2671 {
2672     WND *win;
2673     HWND *list, ret = 0;
2674
2675     switch(type)
2676     {
2677     case GA_PARENT:
2678         if (!(win = WIN_GetPtr( hwnd )))
2679         {
2680             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2681             return 0;
2682         }
2683         if (win == WND_DESKTOP) return 0;
2684         if (win != WND_OTHER_PROCESS)
2685         {
2686             ret = win->parent;
2687             WIN_ReleasePtr( win );
2688         }
2689         else /* need to query the server */
2690         {
2691             SERVER_START_REQ( get_window_tree )
2692             {
2693                 req->handle = wine_server_user_handle( hwnd );
2694                 if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->parent );
2695             }
2696             SERVER_END_REQ;
2697         }
2698         break;
2699
2700     case GA_ROOT:
2701         if (!(list = list_window_parents( hwnd ))) return 0;
2702
2703         if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd );  /* top-level window */
2704         else
2705         {
2706             int count = 2;
2707             while (list[count]) count++;
2708             ret = list[count - 2];  /* get the one before the desktop */
2709         }
2710         HeapFree( GetProcessHeap(), 0, list );
2711         break;
2712
2713     case GA_ROOTOWNER:
2714         if (is_desktop_window( hwnd )) return 0;
2715         ret = WIN_GetFullHandle( hwnd );
2716         for (;;)
2717         {
2718             HWND parent = GetParent( ret );
2719             if (!parent) break;
2720             ret = parent;
2721         }
2722         break;
2723     }
2724     return ret;
2725 }
2726
2727
2728 /*****************************************************************
2729  *              SetParent (USER32.@)
2730  */
2731 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2732 {
2733     HWND full_handle;
2734     HWND old_parent = 0;
2735     BOOL was_visible;
2736     WND *wndPtr;
2737     BOOL ret;
2738
2739     if (is_broadcast(hwnd) || is_broadcast(parent))
2740     {
2741         SetLastError(ERROR_INVALID_PARAMETER);
2742         return 0;
2743     }
2744
2745     if (!parent) parent = GetDesktopWindow();
2746     else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
2747     else parent = WIN_GetFullHandle( parent );
2748
2749     if (!IsWindow( parent ))
2750     {
2751         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2752         return 0;
2753     }
2754
2755     /* Some applications try to set a child as a parent */
2756     if (IsChild(hwnd, parent))
2757     {
2758         SetLastError( ERROR_INVALID_PARAMETER );
2759         return 0;
2760     }
2761
2762     if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2763         return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2764
2765     if (full_handle == parent)
2766     {
2767         SetLastError( ERROR_INVALID_PARAMETER );
2768         return 0;
2769     }
2770
2771     /* Windows hides the window first, then shows it again
2772      * including the WM_SHOWWINDOW messages and all */
2773     was_visible = ShowWindow( hwnd, SW_HIDE );
2774
2775     wndPtr = WIN_GetPtr( hwnd );
2776     if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
2777
2778     SERVER_START_REQ( set_parent )
2779     {
2780         req->handle = wine_server_user_handle( hwnd );
2781         req->parent = wine_server_user_handle( parent );
2782         if ((ret = !wine_server_call( req )))
2783         {
2784             old_parent = wine_server_ptr_handle( reply->old_parent );
2785             wndPtr->parent = parent = wine_server_ptr_handle( reply->full_parent );
2786         }
2787
2788     }
2789     SERVER_END_REQ;
2790     WIN_ReleasePtr( wndPtr );
2791     if (!ret) return 0;
2792
2793     USER_Driver->pSetParent( full_handle, parent, old_parent );
2794
2795     /* SetParent additionally needs to make hwnd the topmost window
2796        in the x-order and send the expected WM_WINDOWPOSCHANGING and
2797        WM_WINDOWPOSCHANGED notification messages.
2798     */
2799     SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0,
2800                   SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | (was_visible ? SWP_SHOWWINDOW : 0) );
2801     /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
2802      * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
2803
2804     return old_parent;
2805 }
2806
2807
2808 /*******************************************************************
2809  *              IsChild (USER32.@)
2810  */
2811 BOOL WINAPI IsChild( HWND parent, HWND child )
2812 {
2813     HWND *list = list_window_parents( child );
2814     int i;
2815     BOOL ret;
2816
2817     if (!list) return FALSE;
2818     parent = WIN_GetFullHandle( parent );
2819     for (i = 0; list[i]; i++) if (list[i] == parent) break;
2820     ret = list[i] && list[i+1];
2821     HeapFree( GetProcessHeap(), 0, list );
2822     return ret;
2823 }
2824
2825
2826 /***********************************************************************
2827  *              IsWindowVisible (USER32.@)
2828  */
2829 BOOL WINAPI IsWindowVisible( HWND hwnd )
2830 {
2831     HWND *list;
2832     BOOL retval = TRUE;
2833     int i;
2834
2835     if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2836     if (!(list = list_window_parents( hwnd ))) return TRUE;
2837     if (list[0])
2838     {
2839         for (i = 0; list[i+1]; i++)
2840             if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2841         retval = !list[i+1] && (list[i] == GetDesktopWindow());  /* top message window isn't visible */
2842     }
2843     HeapFree( GetProcessHeap(), 0, list );
2844     return retval;
2845 }
2846
2847
2848 /***********************************************************************
2849  *           WIN_IsWindowDrawable
2850  *
2851  * hwnd is drawable when it is visible, all parents are not
2852  * minimized, and it is itself not minimized unless we are
2853  * trying to draw its default class icon.
2854  */
2855 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2856 {
2857     HWND *list;
2858     BOOL retval = TRUE;
2859     int i;
2860     LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2861
2862     if (!(style & WS_VISIBLE)) return FALSE;
2863     if ((style & WS_MINIMIZE) && icon && GetClassLongPtrW( hwnd, GCLP_HICON ))  return FALSE;
2864
2865     if (!(list = list_window_parents( hwnd ))) return TRUE;
2866     if (list[0])
2867     {
2868         for (i = 0; list[i+1]; i++)
2869             if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2870                 break;
2871         retval = !list[i+1] && (list[i] == GetDesktopWindow());  /* top message window isn't visible */
2872     }
2873     HeapFree( GetProcessHeap(), 0, list );
2874     return retval;
2875 }
2876
2877
2878 /*******************************************************************
2879  *              GetTopWindow (USER32.@)
2880  */
2881 HWND WINAPI GetTopWindow( HWND hwnd )
2882 {
2883     if (!hwnd) hwnd = GetDesktopWindow();
2884     return GetWindow( hwnd, GW_CHILD );
2885 }
2886
2887
2888 /*******************************************************************
2889  *              GetWindow (USER32.@)
2890  */
2891 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2892 {
2893     HWND retval = 0;
2894
2895     if (rel == GW_OWNER)  /* this one may be available locally */
2896     {
2897         WND *wndPtr = WIN_GetPtr( hwnd );
2898         if (!wndPtr)
2899         {
2900             SetLastError( ERROR_INVALID_HANDLE );
2901             return 0;
2902         }
2903         if (wndPtr == WND_DESKTOP) return 0;
2904         if (wndPtr != WND_OTHER_PROCESS)
2905         {
2906             retval = wndPtr->owner;
2907             WIN_ReleasePtr( wndPtr );
2908             return retval;
2909         }
2910         /* else fall through to server call */
2911     }
2912
2913     SERVER_START_REQ( get_window_tree )
2914     {
2915         req->handle = wine_server_user_handle( hwnd );
2916         if (!wine_server_call_err( req ))
2917         {
2918             switch(rel)
2919             {
2920             case GW_HWNDFIRST:
2921                 retval = wine_server_ptr_handle( reply->first_sibling );
2922                 break;
2923             case GW_HWNDLAST:
2924                 retval = wine_server_ptr_handle( reply->last_sibling );
2925                 break;
2926             case GW_HWNDNEXT:
2927                 retval = wine_server_ptr_handle( reply->next_sibling );
2928                 break;
2929             case GW_HWNDPREV:
2930                 retval = wine_server_ptr_handle( reply->prev_sibling );
2931                 break;
2932             case GW_OWNER:
2933                 retval = wine_server_ptr_handle( reply->owner );
2934                 break;
2935             case GW_CHILD:
2936                 retval = wine_server_ptr_handle( reply->first_child );
2937                 break;
2938             }
2939         }
2940     }
2941     SERVER_END_REQ;
2942     return retval;
2943 }
2944
2945
2946 /*******************************************************************
2947  *              ShowOwnedPopups (USER32.@)
2948  */
2949 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2950 {
2951     int count = 0;
2952     WND *pWnd;
2953     HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2954
2955     if (!win_array) return TRUE;
2956
2957     while (win_array[count]) count++;
2958     while (--count >= 0)
2959     {
2960         if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2961         if (!(pWnd = WIN_GetPtr( win_array[count] ))) continue;
2962         if (pWnd == WND_OTHER_PROCESS) continue;
2963         if (fShow)
2964         {
2965             if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2966             {
2967                 WIN_ReleasePtr( pWnd );
2968                 /* In Windows, ShowOwnedPopups(TRUE) generates
2969                  * WM_SHOWWINDOW messages with SW_PARENTOPENING,
2970                  * regardless of the state of the owner
2971                  */
2972                 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
2973                 continue;
2974             }
2975         }
2976         else
2977         {
2978             if (pWnd->dwStyle & WS_VISIBLE)
2979             {
2980                 WIN_ReleasePtr( pWnd );
2981                 /* In Windows, ShowOwnedPopups(FALSE) generates
2982                  * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
2983                  * regardless of the state of the owner
2984                  */
2985                 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
2986                 continue;
2987             }
2988         }
2989         WIN_ReleasePtr( pWnd );
2990     }
2991     HeapFree( GetProcessHeap(), 0, win_array );
2992     return TRUE;
2993 }
2994
2995
2996 /*******************************************************************
2997  *              GetLastActivePopup (USER32.@)
2998  */
2999 HWND WINAPI GetLastActivePopup( HWND hwnd )
3000 {
3001     HWND retval = hwnd;
3002
3003     SERVER_START_REQ( get_window_info )
3004     {
3005         req->handle = wine_server_user_handle( hwnd );
3006         if (!wine_server_call_err( req )) retval = wine_server_ptr_handle( reply->last_active );
3007     }
3008     SERVER_END_REQ;
3009     return retval;
3010 }
3011
3012
3013 /*******************************************************************
3014  *           WIN_ListChildren
3015  *
3016  * Build an array of the children of a given window. The array must be
3017  * freed with HeapFree. Returns NULL when no windows are found.
3018  */
3019 HWND *WIN_ListChildren( HWND hwnd )
3020 {
3021     if (!hwnd)
3022     {
3023         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3024         return NULL;
3025     }
3026     return list_window_children( 0, hwnd, NULL, 0 );
3027 }
3028
3029
3030 /*******************************************************************
3031  *              EnumWindows (USER32.@)
3032  */
3033 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
3034 {
3035     HWND *list;
3036     BOOL ret = TRUE;
3037     int i;
3038
3039     USER_CheckNotLock();
3040
3041     /* We have to build a list of all windows first, to avoid */
3042     /* unpleasant side-effects, for instance if the callback */
3043     /* function changes the Z-order of the windows.          */
3044
3045     if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
3046
3047     /* Now call the callback function for every window */
3048
3049     for (i = 0; list[i]; i++)
3050     {
3051         /* Make sure that the window still exists */
3052         if (!IsWindow( list[i] )) continue;
3053         if (!(ret = lpEnumFunc( list[i], lParam ))) break;
3054     }
3055     HeapFree( GetProcessHeap(), 0, list );
3056     return ret;
3057 }
3058
3059
3060 /**********************************************************************
3061  *              EnumThreadWindows (USER32.@)
3062  */
3063 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
3064 {
3065     HWND *list;
3066     int i;
3067     BOOL ret = TRUE;
3068
3069     USER_CheckNotLock();
3070
3071     if (!(list = list_window_children( 0, GetDesktopWindow(), NULL, id ))) return TRUE;
3072
3073     /* Now call the callback function for every window */
3074
3075     for (i = 0; list[i]; i++)
3076         if (!(ret = func( list[i], lParam ))) break;
3077     HeapFree( GetProcessHeap(), 0, list );
3078     return ret;
3079 }
3080
3081
3082 /***********************************************************************
3083  *              EnumDesktopWindows   (USER32.@)
3084  */
3085 BOOL WINAPI EnumDesktopWindows( HDESK desktop, WNDENUMPROC func, LPARAM lparam )
3086 {
3087     HWND *list;
3088     int i;
3089
3090     USER_CheckNotLock();
3091
3092     if (!(list = list_window_children( desktop, 0, NULL, 0 ))) return TRUE;
3093
3094     for (i = 0; list[i]; i++)
3095         if (!func( list[i], lparam )) break;
3096     HeapFree( GetProcessHeap(), 0, list );
3097     return TRUE;
3098 }
3099
3100
3101 /**********************************************************************
3102  *           WIN_EnumChildWindows
3103  *
3104  * Helper function for EnumChildWindows().
3105  */
3106 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
3107 {
3108     HWND *childList;
3109     BOOL ret = FALSE;
3110
3111     for ( ; *list; list++)
3112     {
3113         /* Make sure that the window still exists */
3114         if (!IsWindow( *list )) continue;
3115         /* Build children list first */
3116         childList = WIN_ListChildren( *list );
3117
3118         ret = func( *list, lParam );
3119
3120         if (childList)
3121         {
3122             if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
3123             HeapFree( GetProcessHeap(), 0, childList );
3124         }
3125         if (!ret) return FALSE;
3126     }
3127     return TRUE;
3128 }
3129
3130
3131 /**********************************************************************
3132  *              EnumChildWindows (USER32.@)
3133  */
3134 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
3135 {
3136     HWND *list;
3137     BOOL ret;
3138
3139     USER_CheckNotLock();
3140
3141     if (!(list = WIN_ListChildren( parent ))) return FALSE;
3142     ret = WIN_EnumChildWindows( list, func, lParam );
3143     HeapFree( GetProcessHeap(), 0, list );
3144     return ret;
3145 }
3146
3147
3148 /*******************************************************************
3149  *              AnyPopup (USER32.@)
3150  */
3151 BOOL WINAPI AnyPopup(void)
3152 {
3153     int i;
3154     BOOL retvalue;
3155     HWND *list = WIN_ListChildren( GetDesktopWindow() );
3156
3157     if (!list) return FALSE;
3158     for (i = 0; list[i]; i++)
3159     {
3160         if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
3161     }
3162     retvalue = (list[i] != 0);
3163     HeapFree( GetProcessHeap(), 0, list );
3164     return retvalue;
3165 }
3166
3167
3168 /*******************************************************************
3169  *              FlashWindow (USER32.@)
3170  */
3171 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3172 {
3173     WND *wndPtr;
3174
3175     TRACE("%p\n", hWnd);
3176
3177     if (IsIconic( hWnd ))
3178     {
3179         RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
3180
3181         wndPtr = WIN_GetPtr(hWnd);
3182         if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3183         if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
3184         {
3185             wndPtr->flags |= WIN_NCACTIVATED;
3186         }
3187         else
3188         {
3189             wndPtr->flags &= ~WIN_NCACTIVATED;
3190         }
3191         WIN_ReleasePtr( wndPtr );
3192         return TRUE;
3193     }
3194     else
3195     {
3196         WPARAM wparam;
3197
3198         wndPtr = WIN_GetPtr(hWnd);
3199         if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3200         hWnd = wndPtr->obj.handle;  /* make it a full handle */
3201
3202         if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3203         else wparam = (hWnd == GetForegroundWindow());
3204
3205         WIN_ReleasePtr( wndPtr );
3206         SendMessageW( hWnd, WM_NCACTIVATE, wparam, 0 );
3207         return wparam;
3208     }
3209 }
3210
3211 /*******************************************************************
3212  *              FlashWindowEx (USER32.@)
3213  */
3214 BOOL WINAPI FlashWindowEx( PFLASHWINFO pfwi )
3215 {
3216     FIXME("%p\n", pfwi);
3217     return TRUE;
3218 }
3219
3220 /*******************************************************************
3221  *              GetWindowContextHelpId (USER32.@)
3222  */
3223 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3224 {
3225     DWORD retval;
3226     WND *wnd = WIN_GetPtr( hwnd );
3227     if (!wnd || wnd == WND_DESKTOP) return 0;
3228     if (wnd == WND_OTHER_PROCESS)
3229     {
3230         if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3231         return 0;
3232     }
3233     retval = wnd->helpContext;
3234     WIN_ReleasePtr( wnd );
3235     return retval;
3236 }
3237
3238
3239 /*******************************************************************
3240  *              SetWindowContextHelpId (USER32.@)
3241  */
3242 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3243 {
3244     WND *wnd = WIN_GetPtr( hwnd );
3245     if (!wnd || wnd == WND_DESKTOP) return FALSE;
3246     if (wnd == WND_OTHER_PROCESS)
3247     {
3248         if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3249         return 0;
3250     }
3251     wnd->helpContext = id;
3252     WIN_ReleasePtr( wnd );
3253     return TRUE;
3254 }
3255
3256
3257 /*******************************************************************
3258  *              DragDetect (USER32.@)
3259  */
3260 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3261 {
3262     MSG msg;
3263     RECT rect;
3264     WORD wDragWidth = GetSystemMetrics(SM_CXDRAG);
3265     WORD wDragHeight= GetSystemMetrics(SM_CYDRAG);
3266
3267     rect.left = pt.x - wDragWidth;
3268     rect.right = pt.x + wDragWidth;
3269
3270     rect.top = pt.y - wDragHeight;
3271     rect.bottom = pt.y + wDragHeight;
3272
3273     SetCapture(hWnd);
3274
3275     while(1)
3276     {
3277         while (PeekMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ))
3278         {
3279             if( msg.message == WM_LBUTTONUP )
3280             {
3281                 ReleaseCapture();
3282                 return 0;
3283             }
3284             if( msg.message == WM_MOUSEMOVE )
3285             {
3286                 POINT tmp;
3287                 tmp.x = (short)LOWORD(msg.lParam);
3288                 tmp.y = (short)HIWORD(msg.lParam);
3289                 if( !PtInRect( &rect, tmp ))
3290                 {
3291                     ReleaseCapture();
3292                     return 1;
3293                 }
3294             }
3295         }
3296         WaitMessage();
3297     }
3298     return 0;
3299 }
3300
3301 /******************************************************************************
3302  *              GetWindowModuleFileNameA (USER32.@)
3303  */
3304 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR module, UINT size )
3305 {
3306     WND *win;
3307     HINSTANCE hinst;
3308
3309     TRACE( "%p, %p, %u\n", hwnd, module, size );
3310
3311     win = WIN_GetPtr( hwnd );
3312     if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3313     {
3314         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3315         return 0;
3316     }
3317     hinst = win->hInstance;
3318     WIN_ReleasePtr( win );
3319
3320     return GetModuleFileNameA( hinst, module, size );
3321 }
3322
3323 /******************************************************************************
3324  *              GetWindowModuleFileNameW (USER32.@)
3325  */
3326 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR module, UINT size )
3327 {
3328     WND *win;
3329     HINSTANCE hinst;
3330
3331     TRACE( "%p, %p, %u\n", hwnd, module, size );
3332
3333     win = WIN_GetPtr( hwnd );
3334     if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3335     {
3336         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3337         return 0;
3338     }
3339     hinst = win->hInstance;
3340     WIN_ReleasePtr( win );
3341
3342     return GetModuleFileNameW( hinst, module, size );
3343 }
3344
3345 /******************************************************************************
3346  *              GetWindowInfo (USER32.@)
3347  *
3348  * Note: tests show that Windows doesn't check cbSize of the structure.
3349  */
3350 BOOL WINAPI GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3351 {
3352     if (!pwi) return FALSE;
3353     if (!WIN_GetRectangles( hwnd, COORDS_SCREEN, &pwi->rcWindow, &pwi->rcClient )) return FALSE;
3354
3355     pwi->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
3356     pwi->dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3357     pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3358
3359     pwi->cxWindowBorders = pwi->rcClient.left - pwi->rcWindow.left;
3360     pwi->cyWindowBorders = pwi->rcWindow.bottom - pwi->rcClient.bottom;
3361
3362     pwi->atomWindowType = GetClassLongW( hwnd, GCW_ATOM );
3363     pwi->wCreatorVersion = 0x0400;
3364
3365     return TRUE;
3366 }
3367
3368 /******************************************************************************
3369  *              SwitchDesktop (USER32.@)
3370  *
3371  * NOTES: Sets the current input or interactive desktop.
3372  */
3373 BOOL WINAPI SwitchDesktop( HDESK hDesktop)
3374 {
3375     FIXME("(hwnd %p) stub!\n", hDesktop);
3376     return TRUE;
3377 }
3378
3379 /*****************************************************************************
3380  *              SetLayeredWindowAttributes (USER32.@)
3381  */
3382 BOOL WINAPI SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, DWORD flags )
3383 {
3384     BOOL ret;
3385
3386     TRACE("(%p,%08x,%d,%x): stub!\n", hwnd, key, alpha, flags);
3387
3388     SERVER_START_REQ( set_window_layered_info )
3389     {
3390         req->handle = wine_server_user_handle( hwnd );
3391         req->color_key = key;
3392         req->alpha = alpha;
3393         req->flags = flags;
3394         ret = !wine_server_call_err( req );
3395     }
3396     SERVER_END_REQ;
3397
3398     if (ret) USER_Driver->pSetLayeredWindowAttributes( hwnd, key, alpha, flags );
3399
3400     return ret;
3401 }
3402
3403
3404 /*****************************************************************************
3405  *              GetLayeredWindowAttributes (USER32.@)
3406  */
3407 BOOL WINAPI GetLayeredWindowAttributes( HWND hwnd, COLORREF *key, BYTE *alpha, DWORD *flags )
3408 {
3409     BOOL ret;
3410
3411     SERVER_START_REQ( get_window_layered_info )
3412     {
3413         req->handle = wine_server_user_handle( hwnd );
3414         if ((ret = !wine_server_call_err( req )))
3415         {
3416             if (key) *key = reply->color_key;
3417             if (alpha) *alpha = reply->alpha;
3418             if (flags) *flags = reply->flags;
3419         }
3420     }
3421     SERVER_END_REQ;
3422
3423     return ret;
3424 }
3425
3426
3427 /*****************************************************************************
3428  *              UpdateLayeredWindowIndirect  (USER32.@)
3429  */
3430 BOOL WINAPI UpdateLayeredWindowIndirect( HWND hwnd, const UPDATELAYEREDWINDOWINFO *info )
3431 {
3432     BYTE alpha = 0xff;
3433
3434     if (!(info->dwFlags & ULW_EX_NORESIZE) && (info->pptDst || info->psize))
3435     {
3436         int x = 0, y = 0, cx = 0, cy = 0;
3437         DWORD flags = SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOSENDCHANGING;
3438
3439         if (info->pptDst)
3440         {
3441             x = info->pptDst->x;
3442             y = info->pptDst->y;
3443             flags &= ~SWP_NOMOVE;
3444         }
3445         if (info->psize)
3446         {
3447             cx = info->psize->cx;
3448             cy = info->psize->cy;
3449             flags &= ~SWP_NOSIZE;
3450         }
3451         TRACE( "moving window %p pos %d,%d %dx%d\n", hwnd, x, y, cx, cy );
3452         SetWindowPos( hwnd, 0, x, y, cx, cy, flags );
3453     }
3454
3455     if (info->hdcSrc)
3456     {
3457         HDC hdc = GetWindowDC( hwnd );
3458
3459         if (hdc)
3460         {
3461             int x = 0, y = 0;
3462             RECT rect;
3463
3464             GetWindowRect( hwnd, &rect );
3465             OffsetRect( &rect, -rect.left, -rect.top);
3466             if (info->pptSrc)
3467             {
3468                 x = info->pptSrc->x;
3469                 y = info->pptSrc->y;
3470             }
3471
3472             if (!info->prcDirty || (info->prcDirty && IntersectRect(&rect, &rect, info->prcDirty)))
3473             {
3474                 TRACE( "copying window %p pos %d,%d\n", hwnd, x, y );
3475                 BitBlt( hdc, rect.left, rect.top, rect.right, rect.bottom,
3476                         info->hdcSrc, rect.left + x, rect.top + y, SRCCOPY );
3477             }
3478             ReleaseDC( hwnd, hdc );
3479         }
3480     }
3481
3482     if (info->pblend && !(info->dwFlags & ULW_OPAQUE)) alpha = info->pblend->SourceConstantAlpha;
3483     TRACE( "setting window %p alpha %u\n", hwnd, alpha );
3484     USER_Driver->pSetLayeredWindowAttributes( hwnd, info->crKey, alpha,
3485                                               info->dwFlags & (LWA_ALPHA | LWA_COLORKEY) );
3486     return TRUE;
3487 }
3488
3489
3490 /*****************************************************************************
3491  *              UpdateLayeredWindow (USER32.@)
3492  */
3493 BOOL WINAPI UpdateLayeredWindow( HWND hwnd, HDC hdcDst, POINT *pptDst, SIZE *psize,
3494                                  HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend,
3495                                  DWORD dwFlags)
3496 {
3497     UPDATELAYEREDWINDOWINFO info;
3498
3499     info.cbSize   = sizeof(info);
3500     info.hdcDst   = hdcDst;
3501     info.pptDst   = pptDst;
3502     info.psize    = psize;
3503     info.hdcSrc   = hdcSrc;
3504     info.pptSrc   = pptSrc;
3505     info.crKey    = crKey;
3506     info.pblend   = pblend;
3507     info.dwFlags  = dwFlags;
3508     info.prcDirty = NULL;
3509     return UpdateLayeredWindowIndirect( hwnd, &info );
3510 }
3511
3512
3513 /******************************************************************************
3514  *                    GetProcessDefaultLayout [USER32.@]
3515  *
3516  * Gets the default layout for parentless windows.
3517  */
3518 BOOL WINAPI GetProcessDefaultLayout( DWORD *layout )
3519 {
3520     if (!layout)
3521     {
3522         SetLastError( ERROR_NOACCESS );
3523         return FALSE;
3524     }
3525     *layout = process_layout;
3526     return TRUE;
3527 }
3528
3529
3530 /******************************************************************************
3531  *                    SetProcessDefaultLayout [USER32.@]
3532  *
3533  * Sets the default layout for parentless windows.
3534  */
3535 BOOL WINAPI SetProcessDefaultLayout( DWORD layout )
3536 {
3537     process_layout = layout;
3538     return TRUE;
3539 }
3540
3541
3542 /* 64bit versions */
3543
3544 #ifdef GetWindowLongPtrW
3545 #undef GetWindowLongPtrW
3546 #endif
3547
3548 #ifdef GetWindowLongPtrA
3549 #undef GetWindowLongPtrA
3550 #endif
3551
3552 #ifdef SetWindowLongPtrW
3553 #undef SetWindowLongPtrW
3554 #endif
3555
3556 #ifdef SetWindowLongPtrA
3557 #undef SetWindowLongPtrA
3558 #endif
3559
3560 /*****************************************************************************
3561  *              GetWindowLongPtrW (USER32.@)
3562  */
3563 LONG_PTR WINAPI GetWindowLongPtrW( HWND hwnd, INT offset )
3564 {
3565     return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), TRUE );
3566 }
3567
3568 /*****************************************************************************
3569  *              GetWindowLongPtrA (USER32.@)
3570  */
3571 LONG_PTR WINAPI GetWindowLongPtrA( HWND hwnd, INT offset )
3572 {
3573     return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), FALSE );
3574 }
3575
3576 /*****************************************************************************
3577  *              SetWindowLongPtrW (USER32.@)
3578  */
3579 LONG_PTR WINAPI SetWindowLongPtrW( HWND hwnd, INT offset, LONG_PTR newval )
3580 {
3581     return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, TRUE );
3582 }
3583
3584 /*****************************************************************************
3585  *              SetWindowLongPtrA (USER32.@)
3586  */
3587 LONG_PTR WINAPI SetWindowLongPtrA( HWND hwnd, INT offset, LONG_PTR newval )
3588 {
3589     return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, FALSE );
3590 }