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