wined3d: Don't crash during initialization if the adapter doesn't have full GL info.
[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             void *redir;
1789
1790             memset( &si, 0, sizeof(si) );
1791             si.cb = sizeof(si);
1792             si.dwFlags = STARTF_USESTDHANDLES;
1793             si.hStdInput  = 0;
1794             si.hStdOutput = 0;
1795             si.hStdError  = GetStdHandle( STD_ERROR_HANDLE );
1796
1797             GetSystemDirectoryW( windir, MAX_PATH );
1798             strcpyW( app, windir );
1799             strcatW( app, explorer );
1800             strcpyW( cmdline, app );
1801             strcatW( cmdline, args );
1802
1803             Wow64DisableWow64FsRedirection( &redir );
1804             if (CreateProcessW( app, cmdline, NULL, NULL, FALSE, DETACHED_PROCESS,
1805                                 NULL, windir, &si, &pi ))
1806             {
1807                 TRACE( "started explorer pid %04x tid %04x\n", pi.dwProcessId, pi.dwThreadId );
1808                 WaitForInputIdle( pi.hProcess, 10000 );
1809                 CloseHandle( pi.hThread );
1810                 CloseHandle( pi.hProcess );
1811             }
1812             else WARN( "failed to start explorer, err %d\n", GetLastError() );
1813             Wow64RevertWow64FsRedirection( redir );
1814         }
1815         else TRACE( "not starting explorer since winstation is not visible\n" );
1816
1817         SERVER_START_REQ( get_desktop_window )
1818         {
1819             req->force = 1;
1820             if (!wine_server_call( req ))
1821             {
1822                 thread_info->top_window = wine_server_ptr_handle( reply->top_window );
1823                 thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
1824             }
1825         }
1826         SERVER_END_REQ;
1827     }
1828
1829     if (!thread_info->top_window || !USER_Driver->pCreateDesktopWindow( thread_info->top_window ))
1830         ERR( "failed to create desktop window\n" );
1831
1832     return thread_info->top_window;
1833 }
1834
1835
1836 /*******************************************************************
1837  *              EnableWindow (USER32.@)
1838  */
1839 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
1840 {
1841     BOOL retvalue;
1842     HWND full_handle;
1843
1844     if (is_broadcast(hwnd))
1845     {
1846         SetLastError( ERROR_INVALID_PARAMETER );
1847         return FALSE;
1848     }
1849
1850     if (!(full_handle = WIN_IsCurrentThread( hwnd )))
1851         return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
1852
1853     hwnd = full_handle;
1854
1855     TRACE("( %p, %d )\n", hwnd, enable);
1856
1857     retvalue = !IsWindowEnabled( hwnd );
1858
1859     if (enable && retvalue)
1860     {
1861         WIN_SetStyle( hwnd, 0, WS_DISABLED );
1862         SendMessageW( hwnd, WM_ENABLE, TRUE, 0 );
1863     }
1864     else if (!enable && !retvalue)
1865     {
1866         HWND capture_wnd;
1867
1868         SendMessageW( hwnd, WM_CANCELMODE, 0, 0);
1869
1870         WIN_SetStyle( hwnd, WS_DISABLED, 0 );
1871
1872         if (hwnd == GetFocus())
1873             SetFocus( 0 );  /* A disabled window can't have the focus */
1874
1875         capture_wnd = GetCapture();
1876         if (hwnd == capture_wnd || IsChild(hwnd, capture_wnd))
1877             ReleaseCapture();  /* A disabled window can't capture the mouse */
1878
1879         SendMessageW( hwnd, WM_ENABLE, FALSE, 0 );
1880     }
1881     return retvalue;
1882 }
1883
1884
1885 /***********************************************************************
1886  *              IsWindowEnabled (USER32.@)
1887  */
1888 BOOL WINAPI IsWindowEnabled(HWND hWnd)
1889 {
1890     return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
1891 }
1892
1893
1894 /***********************************************************************
1895  *              IsWindowUnicode (USER32.@)
1896  */
1897 BOOL WINAPI IsWindowUnicode( HWND hwnd )
1898 {
1899     WND * wndPtr;
1900     BOOL retvalue = FALSE;
1901
1902     if (!(wndPtr = WIN_GetPtr(hwnd))) return FALSE;
1903
1904     if (wndPtr == WND_DESKTOP) return TRUE;
1905
1906     if (wndPtr != WND_OTHER_PROCESS)
1907     {
1908         retvalue = (wndPtr->flags & WIN_ISUNICODE) != 0;
1909         WIN_ReleasePtr( wndPtr );
1910     }
1911     else
1912     {
1913         SERVER_START_REQ( get_window_info )
1914         {
1915             req->handle = wine_server_user_handle( hwnd );
1916             if (!wine_server_call_err( req )) retvalue = reply->is_unicode;
1917         }
1918         SERVER_END_REQ;
1919     }
1920     return retvalue;
1921 }
1922
1923
1924 /**********************************************************************
1925  *           WIN_GetWindowLong
1926  *
1927  * Helper function for GetWindowLong().
1928  */
1929 static LONG_PTR WIN_GetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicode )
1930 {
1931     LONG_PTR retvalue = 0;
1932     WND *wndPtr;
1933
1934     if (offset == GWLP_HWNDPARENT)
1935     {
1936         HWND parent = GetAncestor( hwnd, GA_PARENT );
1937         if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
1938         return (ULONG_PTR)parent;
1939     }
1940
1941     if (!(wndPtr = WIN_GetPtr( hwnd )))
1942     {
1943         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1944         return 0;
1945     }
1946
1947     if (wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP)
1948     {
1949         if (offset == GWLP_WNDPROC)
1950         {
1951             SetLastError( ERROR_ACCESS_DENIED );
1952             return 0;
1953         }
1954         SERVER_START_REQ( set_window_info )
1955         {
1956             req->handle = wine_server_user_handle( hwnd );
1957             req->flags  = 0;  /* don't set anything, just retrieve */
1958             req->extra_offset = (offset >= 0) ? offset : -1;
1959             req->extra_size = (offset >= 0) ? size : 0;
1960             if (!wine_server_call_err( req ))
1961             {
1962                 switch(offset)
1963                 {
1964                 case GWL_STYLE:      retvalue = reply->old_style; break;
1965                 case GWL_EXSTYLE:    retvalue = reply->old_ex_style; break;
1966                 case GWLP_ID:        retvalue = reply->old_id; break;
1967                 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wine_server_get_ptr( reply->old_instance ); break;
1968                 case GWLP_USERDATA:  retvalue = reply->old_user_data; break;
1969                 default:
1970                     if (offset >= 0) retvalue = get_win_data( &reply->old_extra_value, size );
1971                     else SetLastError( ERROR_INVALID_INDEX );
1972                     break;
1973                 }
1974             }
1975         }
1976         SERVER_END_REQ;
1977         return retvalue;
1978     }
1979
1980     /* now we have a valid wndPtr */
1981
1982     if (offset >= 0)
1983     {
1984         if (offset > (int)(wndPtr->cbWndExtra - size))
1985         {
1986             WARN("Invalid offset %d\n", offset );
1987             WIN_ReleasePtr( wndPtr );
1988             SetLastError( ERROR_INVALID_INDEX );
1989             return 0;
1990         }
1991         retvalue = get_win_data( (char *)wndPtr->wExtra + offset, size );
1992
1993         /* Special case for dialog window procedure */
1994         if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && wndPtr->dlgInfo)
1995             retvalue = (LONG_PTR)WINPROC_GetProc( (WNDPROC)retvalue, unicode );
1996         WIN_ReleasePtr( wndPtr );
1997         return retvalue;
1998     }
1999
2000     switch(offset)
2001     {
2002     case GWLP_USERDATA:  retvalue = wndPtr->userdata; break;
2003     case GWL_STYLE:      retvalue = wndPtr->dwStyle; break;
2004     case GWL_EXSTYLE:    retvalue = wndPtr->dwExStyle; break;
2005     case GWLP_ID:        retvalue = wndPtr->wIDmenu; break;
2006     case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hInstance; break;
2007     case GWLP_WNDPROC:
2008         /* This looks like a hack only for the edit control (see tests). This makes these controls
2009          * more tolerant to A/W mismatches. The lack of W->A->W conversion for such a mismatch suggests
2010          * that the hack is in GetWindowLongPtr[AW], not in winprocs.
2011          */
2012         if (wndPtr->winproc == BUILTIN_WINPROC(WINPROC_EDIT) && (!unicode != !(wndPtr->flags & WIN_ISUNICODE)))
2013             retvalue = (ULONG_PTR)wndPtr->winproc;
2014         else
2015             retvalue = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, unicode );
2016         break;
2017     default:
2018         WARN("Unknown offset %d\n", offset );
2019         SetLastError( ERROR_INVALID_INDEX );
2020         break;
2021     }
2022     WIN_ReleasePtr(wndPtr);
2023     return retvalue;
2024 }
2025
2026
2027 /**********************************************************************
2028  *           WIN_SetWindowLong
2029  *
2030  * Helper function for SetWindowLong().
2031  *
2032  * 0 is the failure code. However, in the case of failure SetLastError
2033  * must be set to distinguish between a 0 return value and a failure.
2034  */
2035 LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, UINT size, LONG_PTR newval, BOOL unicode )
2036 {
2037     STYLESTRUCT style;
2038     BOOL ok;
2039     LONG_PTR retval = 0;
2040     WND *wndPtr;
2041
2042     TRACE( "%p %d %lx %c\n", hwnd, offset, newval, unicode ? 'W' : 'A' );
2043
2044     if (is_broadcast(hwnd))
2045     {
2046         SetLastError( ERROR_INVALID_PARAMETER );
2047         return FALSE;
2048     }
2049
2050     if (!(wndPtr = WIN_GetPtr( hwnd )))
2051     {
2052         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2053         return 0;
2054     }
2055     if (wndPtr == WND_DESKTOP)
2056     {
2057         /* can't change anything on the desktop window */
2058         SetLastError( ERROR_ACCESS_DENIED );
2059         return 0;
2060     }
2061     if (wndPtr == WND_OTHER_PROCESS)
2062     {
2063         if (offset == GWLP_WNDPROC)
2064         {
2065             SetLastError( ERROR_ACCESS_DENIED );
2066             return 0;
2067         }
2068         if (offset > 32767 || offset < -32767)
2069         {
2070             SetLastError( ERROR_INVALID_INDEX );
2071             return 0;
2072         }
2073         return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, MAKEWPARAM( offset, size ), newval );
2074     }
2075
2076     /* first some special cases */
2077     switch( offset )
2078     {
2079     case GWL_STYLE:
2080     case GWL_EXSTYLE:
2081         style.styleOld =
2082             offset == GWL_STYLE ? wndPtr->dwStyle : wndPtr->dwExStyle;
2083         style.styleNew = newval;
2084         WIN_ReleasePtr( wndPtr );
2085         SendMessageW( hwnd, WM_STYLECHANGING, offset, (LPARAM)&style );
2086         if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2087         newval = style.styleNew;
2088         break;
2089     case GWLP_HWNDPARENT:
2090         if (wndPtr->parent == GetDesktopWindow())
2091         {
2092             WIN_ReleasePtr( wndPtr );
2093             return (ULONG_PTR)WIN_SetOwner( hwnd, (HWND)newval );
2094         }
2095         else
2096         {
2097             WIN_ReleasePtr( wndPtr );
2098             return (ULONG_PTR)SetParent( hwnd, (HWND)newval );
2099         }
2100     case GWLP_WNDPROC:
2101     {
2102         WNDPROC proc;
2103         UINT old_flags = wndPtr->flags;
2104         retval = WIN_GetWindowLong( hwnd, offset, size, unicode );
2105         proc = WINPROC_AllocProc( (WNDPROC)newval, unicode );
2106         if (proc) wndPtr->winproc = proc;
2107         if (WINPROC_IsUnicode( proc, unicode )) wndPtr->flags |= WIN_ISUNICODE;
2108         else wndPtr->flags &= ~WIN_ISUNICODE;
2109         if (!((old_flags ^ wndPtr->flags) & WIN_ISUNICODE))
2110         {
2111             WIN_ReleasePtr( wndPtr );
2112             return retval;
2113         }
2114         /* update is_unicode flag on the server side */
2115         break;
2116     }
2117     case GWLP_ID:
2118     case GWLP_HINSTANCE:
2119     case GWLP_USERDATA:
2120         break;
2121     case DWLP_DLGPROC:
2122         if ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
2123             (size == sizeof(LONG_PTR)) && wndPtr->dlgInfo)
2124         {
2125             WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWLP_DLGPROC);
2126             retval = (ULONG_PTR)WINPROC_GetProc( *ptr, unicode );
2127             *ptr = WINPROC_AllocProc( (WNDPROC)newval, unicode );
2128             WIN_ReleasePtr( wndPtr );
2129             return retval;
2130         }
2131         /* fall through */
2132     default:
2133         if (offset < 0 || offset > (int)(wndPtr->cbWndExtra - size))
2134         {
2135             WARN("Invalid offset %d\n", offset );
2136             WIN_ReleasePtr( wndPtr );
2137             SetLastError( ERROR_INVALID_INDEX );
2138             return 0;
2139         }
2140         else if (get_win_data( (char *)wndPtr->wExtra + offset, size ) == newval)
2141         {
2142             /* already set to the same value */
2143             WIN_ReleasePtr( wndPtr );
2144             return newval;
2145         }
2146         break;
2147     }
2148
2149     SERVER_START_REQ( set_window_info )
2150     {
2151         req->handle = wine_server_user_handle( hwnd );
2152         req->extra_offset = -1;
2153         switch(offset)
2154         {
2155         case GWL_STYLE:
2156             req->flags = SET_WIN_STYLE;
2157             req->style = newval;
2158             break;
2159         case GWL_EXSTYLE:
2160             req->flags = SET_WIN_EXSTYLE;
2161             /* WS_EX_TOPMOST can only be changed through SetWindowPos */
2162             newval = (newval & ~WS_EX_TOPMOST) | (wndPtr->dwExStyle & WS_EX_TOPMOST);
2163             req->ex_style = newval;
2164             break;
2165         case GWLP_ID:
2166             req->flags = SET_WIN_ID;
2167             req->id = newval;
2168             break;
2169         case GWLP_HINSTANCE:
2170             req->flags = SET_WIN_INSTANCE;
2171             req->instance = wine_server_client_ptr( (void *)newval );
2172             break;
2173         case GWLP_WNDPROC:
2174             req->flags = SET_WIN_UNICODE;
2175             req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
2176             break;
2177         case GWLP_USERDATA:
2178             req->flags = SET_WIN_USERDATA;
2179             req->user_data = newval;
2180             break;
2181         default:
2182             req->flags = SET_WIN_EXTRA;
2183             req->extra_offset = offset;
2184             req->extra_size = size;
2185             set_win_data( &req->extra_value, newval, size );
2186         }
2187         if ((ok = !wine_server_call_err( req )))
2188         {
2189             switch(offset)
2190             {
2191             case GWL_STYLE:
2192                 wndPtr->dwStyle = newval;
2193                 retval = reply->old_style;
2194                 break;
2195             case GWL_EXSTYLE:
2196                 wndPtr->dwExStyle = newval;
2197                 retval = reply->old_ex_style;
2198                 break;
2199             case GWLP_ID:
2200                 wndPtr->wIDmenu = newval;
2201                 retval = reply->old_id;
2202                 break;
2203             case GWLP_HINSTANCE:
2204                 wndPtr->hInstance = (HINSTANCE)newval;
2205                 retval = (ULONG_PTR)wine_server_get_ptr( reply->old_instance );
2206                 break;
2207             case GWLP_WNDPROC:
2208                 break;
2209             case GWLP_USERDATA:
2210                 wndPtr->userdata = newval;
2211                 retval = reply->old_user_data;
2212                 break;
2213             default:
2214                 retval = get_win_data( (char *)wndPtr->wExtra + offset, size );
2215                 set_win_data( (char *)wndPtr->wExtra + offset, newval, size );
2216                 break;
2217             }
2218         }
2219     }
2220     SERVER_END_REQ;
2221     WIN_ReleasePtr( wndPtr );
2222
2223     if (!ok) return 0;
2224
2225     if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2226     {
2227         USER_Driver->pSetWindowStyle( hwnd, offset, &style );
2228         SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2229     }
2230
2231     return retval;
2232 }
2233
2234
2235 /**********************************************************************
2236  *              GetWindowWord (USER32.@)
2237  */
2238 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
2239 {
2240     switch(offset)
2241     {
2242     case GWLP_ID:
2243     case GWLP_HINSTANCE:
2244     case GWLP_HWNDPARENT:
2245         break;
2246     default:
2247         if (offset < 0)
2248         {
2249             WARN("Invalid offset %d\n", offset );
2250             SetLastError( ERROR_INVALID_INDEX );
2251             return 0;
2252         }
2253         break;
2254     }
2255     return WIN_GetWindowLong( hwnd, offset, sizeof(WORD), FALSE );
2256 }
2257
2258
2259 /**********************************************************************
2260  *              GetWindowLongA (USER32.@)
2261  */
2262 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2263 {
2264     return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), FALSE );
2265 }
2266
2267
2268 /**********************************************************************
2269  *              GetWindowLongW (USER32.@)
2270  */
2271 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2272 {
2273     return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), TRUE );
2274 }
2275
2276
2277 /**********************************************************************
2278  *              SetWindowWord (USER32.@)
2279  */
2280 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
2281 {
2282     switch(offset)
2283     {
2284     case GWLP_ID:
2285     case GWLP_HINSTANCE:
2286     case GWLP_HWNDPARENT:
2287         break;
2288     default:
2289         if (offset < 0)
2290         {
2291             WARN("Invalid offset %d\n", offset );
2292             SetLastError( ERROR_INVALID_INDEX );
2293             return 0;
2294         }
2295         break;
2296     }
2297     return WIN_SetWindowLong( hwnd, offset, sizeof(WORD), newval, FALSE );
2298 }
2299
2300
2301 /**********************************************************************
2302  *              SetWindowLongA (USER32.@)
2303  *
2304  * See SetWindowLongW.
2305  */
2306 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2307 {
2308     return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, FALSE );
2309 }
2310
2311
2312 /**********************************************************************
2313  *              SetWindowLongW (USER32.@) Set window attribute
2314  *
2315  * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2316  * value in a window's extra memory.
2317  *
2318  * The _hwnd_ parameter specifies the window.  is the handle to a
2319  * window that has extra memory. The _newval_ parameter contains the
2320  * new attribute or extra memory value.  If positive, the _offset_
2321  * parameter is the byte-addressed location in the window's extra
2322  * memory to set.  If negative, _offset_ specifies the window
2323  * attribute to set, and should be one of the following values:
2324  *
2325  * GWL_EXSTYLE      The window's extended window style
2326  *
2327  * GWL_STYLE        The window's window style.
2328  *
2329  * GWLP_WNDPROC     Pointer to the window's window procedure.
2330  *
2331  * GWLP_HINSTANCE   The window's pplication instance handle.
2332  *
2333  * GWLP_ID          The window's identifier.
2334  *
2335  * GWLP_USERDATA    The window's user-specified data.
2336  *
2337  * If the window is a dialog box, the _offset_ parameter can be one of
2338  * the following values:
2339  *
2340  * DWLP_DLGPROC     The address of the window's dialog box procedure.
2341  *
2342  * DWLP_MSGRESULT   The return value of a message
2343  *                  that the dialog box procedure processed.
2344  *
2345  * DWLP_USER        Application specific information.
2346  *
2347  * RETURNS
2348  *
2349  * If successful, returns the previous value located at _offset_. Otherwise,
2350  * returns 0.
2351  *
2352  * NOTES
2353  *
2354  * Extra memory for a window class is specified by a nonzero cbWndExtra
2355  * parameter of the WNDCLASS structure passed to RegisterClass() at the
2356  * time of class creation.
2357  *
2358  * Using GWL_WNDPROC to set a new window procedure effectively creates
2359  * a window subclass. Use CallWindowProc() in the new windows procedure
2360  * to pass messages to the superclass's window procedure.
2361  *
2362  * The user data is reserved for use by the application which created
2363  * the window.
2364  *
2365  * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2366  * instead, call the EnableWindow() function to change the window's
2367  * disabled state.
2368  *
2369  * Do not use GWL_HWNDPARENT to reset the window's parent, use
2370  * SetParent() instead.
2371  *
2372  * Win95:
2373  * When offset is GWL_STYLE and the calling app's ver is 4.0,
2374  * it sends WM_STYLECHANGING before changing the settings
2375  * and WM_STYLECHANGED afterwards.
2376  * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2377  */
2378 LONG WINAPI SetWindowLongW(
2379     HWND hwnd,  /* [in] window to alter */
2380     INT offset, /* [in] offset, in bytes, of location to alter */
2381     LONG newval /* [in] new value of location */
2382 ) {
2383     return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, TRUE );
2384 }
2385
2386
2387 /*******************************************************************
2388  *              GetWindowTextA (USER32.@)
2389  */
2390 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2391 {
2392     WCHAR *buffer;
2393
2394     if (!lpString) return 0;
2395
2396     if (WIN_IsCurrentProcess( hwnd ))
2397         return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2398
2399     /* when window belongs to other process, don't send a message */
2400     if (nMaxCount <= 0) return 0;
2401     if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2402     get_server_window_text( hwnd, buffer, nMaxCount );
2403     if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2404         lpString[nMaxCount-1] = 0;
2405     HeapFree( GetProcessHeap(), 0, buffer );
2406     return strlen(lpString);
2407 }
2408
2409
2410 /*******************************************************************
2411  *              InternalGetWindowText (USER32.@)
2412  */
2413 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2414 {
2415     WND *win;
2416
2417     if (nMaxCount <= 0) return 0;
2418     if (!(win = WIN_GetPtr( hwnd ))) return 0;
2419     if (win == WND_DESKTOP) lpString[0] = 0;
2420     else if (win != WND_OTHER_PROCESS)
2421     {
2422         if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2423         else lpString[0] = 0;
2424         WIN_ReleasePtr( win );
2425     }
2426     else
2427     {
2428         get_server_window_text( hwnd, lpString, nMaxCount );
2429     }
2430     return strlenW(lpString);
2431 }
2432
2433
2434 /*******************************************************************
2435  *              GetWindowTextW (USER32.@)
2436  */
2437 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2438 {
2439     if (!lpString) return 0;
2440
2441     if (WIN_IsCurrentProcess( hwnd ))
2442         return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2443
2444     /* when window belongs to other process, don't send a message */
2445     if (nMaxCount <= 0) return 0;
2446     get_server_window_text( hwnd, lpString, nMaxCount );
2447     return strlenW(lpString);
2448 }
2449
2450
2451 /*******************************************************************
2452  *              SetWindowTextA (USER32.@)
2453  *              SetWindowText  (USER32.@)
2454  */
2455 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2456 {
2457     if (is_broadcast(hwnd))
2458     {
2459         SetLastError( ERROR_INVALID_PARAMETER );
2460         return FALSE;
2461     }
2462     if (!WIN_IsCurrentProcess( hwnd ))
2463         WARN( "setting text %s of other process window %p should not use SendMessage\n",
2464                debugstr_a(lpString), hwnd );
2465     return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2466 }
2467
2468
2469 /*******************************************************************
2470  *              SetWindowTextW (USER32.@)
2471  */
2472 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2473 {
2474     if (is_broadcast(hwnd))
2475     {
2476         SetLastError( ERROR_INVALID_PARAMETER );
2477         return FALSE;
2478     }
2479     if (!WIN_IsCurrentProcess( hwnd ))
2480         WARN( "setting text %s of other process window %p should not use SendMessage\n",
2481                debugstr_w(lpString), hwnd );
2482     return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2483 }
2484
2485
2486 /*******************************************************************
2487  *              GetWindowTextLengthA (USER32.@)
2488  */
2489 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2490 {
2491     return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2492 }
2493
2494 /*******************************************************************
2495  *              GetWindowTextLengthW (USER32.@)
2496  */
2497 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2498 {
2499     return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2500 }
2501
2502
2503 /*******************************************************************
2504  *              IsWindow (USER32.@)
2505  */
2506 BOOL WINAPI IsWindow( HWND hwnd )
2507 {
2508     WND *ptr;
2509     BOOL ret;
2510
2511     if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2512     if (ptr == WND_DESKTOP) return TRUE;
2513
2514     if (ptr != WND_OTHER_PROCESS)
2515     {
2516         WIN_ReleasePtr( ptr );
2517         return TRUE;
2518     }
2519
2520     /* check other processes */
2521     SERVER_START_REQ( get_window_info )
2522     {
2523         req->handle = wine_server_user_handle( hwnd );
2524         ret = !wine_server_call_err( req );
2525     }
2526     SERVER_END_REQ;
2527     return ret;
2528 }
2529
2530
2531 /***********************************************************************
2532  *              GetWindowThreadProcessId (USER32.@)
2533  */
2534 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2535 {
2536     WND *ptr;
2537     DWORD tid = 0;
2538
2539     if (!(ptr = WIN_GetPtr( hwnd )))
2540     {
2541         SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2542         return 0;
2543     }
2544
2545     if (ptr != WND_OTHER_PROCESS && ptr != WND_DESKTOP)
2546     {
2547         /* got a valid window */
2548         tid = ptr->tid;
2549         if (process) *process = GetCurrentProcessId();
2550         WIN_ReleasePtr( ptr );
2551         return tid;
2552     }
2553
2554     /* check other processes */
2555     SERVER_START_REQ( get_window_info )
2556     {
2557         req->handle = wine_server_user_handle( hwnd );
2558         if (!wine_server_call_err( req ))
2559         {
2560             tid = (DWORD)reply->tid;
2561             if (process) *process = (DWORD)reply->pid;
2562         }
2563     }
2564     SERVER_END_REQ;
2565     return tid;
2566 }
2567
2568
2569 /*****************************************************************
2570  *              GetParent (USER32.@)
2571  */
2572 HWND WINAPI GetParent( HWND hwnd )
2573 {
2574     WND *wndPtr;
2575     HWND retvalue = 0;
2576
2577     if (!(wndPtr = WIN_GetPtr( hwnd )))
2578     {
2579         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2580         return 0;
2581     }
2582     if (wndPtr == WND_DESKTOP) return 0;
2583     if (wndPtr == WND_OTHER_PROCESS)
2584     {
2585         LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2586         if (style & (WS_POPUP | WS_CHILD))
2587         {
2588             SERVER_START_REQ( get_window_tree )
2589             {
2590                 req->handle = wine_server_user_handle( hwnd );
2591                 if (!wine_server_call_err( req ))
2592                 {
2593                     if (style & WS_POPUP) retvalue = wine_server_ptr_handle( reply->owner );
2594                     else if (style & WS_CHILD) retvalue = wine_server_ptr_handle( reply->parent );
2595                 }
2596             }
2597             SERVER_END_REQ;
2598         }
2599     }
2600     else
2601     {
2602         if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2603         else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2604         WIN_ReleasePtr( wndPtr );
2605     }
2606     return retvalue;
2607 }
2608
2609
2610 /*****************************************************************
2611  *              GetAncestor (USER32.@)
2612  */
2613 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2614 {
2615     WND *win;
2616     HWND *list, ret = 0;
2617
2618     switch(type)
2619     {
2620     case GA_PARENT:
2621         if (!(win = WIN_GetPtr( hwnd )))
2622         {
2623             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2624             return 0;
2625         }
2626         if (win == WND_DESKTOP) return 0;
2627         if (win != WND_OTHER_PROCESS)
2628         {
2629             ret = win->parent;
2630             WIN_ReleasePtr( win );
2631         }
2632         else /* need to query the server */
2633         {
2634             SERVER_START_REQ( get_window_tree )
2635             {
2636                 req->handle = wine_server_user_handle( hwnd );
2637                 if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->parent );
2638             }
2639             SERVER_END_REQ;
2640         }
2641         break;
2642
2643     case GA_ROOT:
2644         if (!(list = list_window_parents( hwnd ))) return 0;
2645
2646         if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd );  /* top-level window */
2647         else
2648         {
2649             int count = 2;
2650             while (list[count]) count++;
2651             ret = list[count - 2];  /* get the one before the desktop */
2652         }
2653         HeapFree( GetProcessHeap(), 0, list );
2654         break;
2655
2656     case GA_ROOTOWNER:
2657         if (is_desktop_window( hwnd )) return 0;
2658         ret = WIN_GetFullHandle( hwnd );
2659         for (;;)
2660         {
2661             HWND parent = GetParent( ret );
2662             if (!parent) break;
2663             ret = parent;
2664         }
2665         break;
2666     }
2667     return ret;
2668 }
2669
2670
2671 /*****************************************************************
2672  *              SetParent (USER32.@)
2673  */
2674 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2675 {
2676     HWND full_handle;
2677     HWND old_parent = 0;
2678     BOOL was_visible;
2679     WND *wndPtr;
2680     BOOL ret;
2681
2682     if (is_broadcast(hwnd) || is_broadcast(parent))
2683     {
2684         SetLastError(ERROR_INVALID_PARAMETER);
2685         return 0;
2686     }
2687
2688     if (!parent) parent = GetDesktopWindow();
2689     else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
2690     else parent = WIN_GetFullHandle( parent );
2691
2692     if (!IsWindow( parent ))
2693     {
2694         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2695         return 0;
2696     }
2697
2698     /* Some applications try to set a child as a parent */
2699     if (IsChild(hwnd, parent))
2700     {
2701         SetLastError( ERROR_INVALID_PARAMETER );
2702         return 0;
2703     }
2704
2705     if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2706         return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2707
2708     if (full_handle == parent)
2709     {
2710         SetLastError( ERROR_INVALID_PARAMETER );
2711         return 0;
2712     }
2713
2714     /* Windows hides the window first, then shows it again
2715      * including the WM_SHOWWINDOW messages and all */
2716     was_visible = ShowWindow( hwnd, SW_HIDE );
2717
2718     wndPtr = WIN_GetPtr( hwnd );
2719     if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
2720
2721     SERVER_START_REQ( set_parent )
2722     {
2723         req->handle = wine_server_user_handle( hwnd );
2724         req->parent = wine_server_user_handle( parent );
2725         if ((ret = !wine_server_call( req )))
2726         {
2727             old_parent = wine_server_ptr_handle( reply->old_parent );
2728             wndPtr->parent = parent = wine_server_ptr_handle( reply->full_parent );
2729         }
2730
2731     }
2732     SERVER_END_REQ;
2733     WIN_ReleasePtr( wndPtr );
2734     if (!ret) return 0;
2735
2736     USER_Driver->pSetParent( full_handle, parent, old_parent );
2737
2738     /* SetParent additionally needs to make hwnd the topmost window
2739        in the x-order and send the expected WM_WINDOWPOSCHANGING and
2740        WM_WINDOWPOSCHANGED notification messages.
2741     */
2742     SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0,
2743                   SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | (was_visible ? SWP_SHOWWINDOW : 0) );
2744     /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
2745      * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
2746
2747     return old_parent;
2748 }
2749
2750
2751 /*******************************************************************
2752  *              IsChild (USER32.@)
2753  */
2754 BOOL WINAPI IsChild( HWND parent, HWND child )
2755 {
2756     HWND *list = list_window_parents( child );
2757     int i;
2758     BOOL ret;
2759
2760     if (!list) return FALSE;
2761     parent = WIN_GetFullHandle( parent );
2762     for (i = 0; list[i]; i++) if (list[i] == parent) break;
2763     ret = list[i] && list[i+1];
2764     HeapFree( GetProcessHeap(), 0, list );
2765     return ret;
2766 }
2767
2768
2769 /***********************************************************************
2770  *              IsWindowVisible (USER32.@)
2771  */
2772 BOOL WINAPI IsWindowVisible( HWND hwnd )
2773 {
2774     HWND *list;
2775     BOOL retval = TRUE;
2776     int i;
2777
2778     if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2779     if (!(list = list_window_parents( hwnd ))) return TRUE;
2780     if (list[0])
2781     {
2782         for (i = 0; list[i+1]; i++)
2783             if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2784         retval = !list[i+1] && (list[i] == GetDesktopWindow());  /* top message window isn't visible */
2785     }
2786     HeapFree( GetProcessHeap(), 0, list );
2787     return retval;
2788 }
2789
2790
2791 /***********************************************************************
2792  *           WIN_IsWindowDrawable
2793  *
2794  * hwnd is drawable when it is visible, all parents are not
2795  * minimized, and it is itself not minimized unless we are
2796  * trying to draw its default class icon.
2797  */
2798 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2799 {
2800     HWND *list;
2801     BOOL retval = TRUE;
2802     int i;
2803     LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2804
2805     if (!(style & WS_VISIBLE)) return FALSE;
2806     if ((style & WS_MINIMIZE) && icon && GetClassLongPtrW( hwnd, GCLP_HICON ))  return FALSE;
2807
2808     if (!(list = list_window_parents( hwnd ))) return TRUE;
2809     if (list[0])
2810     {
2811         for (i = 0; list[i+1]; i++)
2812             if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2813                 break;
2814         retval = !list[i+1] && (list[i] == GetDesktopWindow());  /* top message window isn't visible */
2815     }
2816     HeapFree( GetProcessHeap(), 0, list );
2817     return retval;
2818 }
2819
2820
2821 /*******************************************************************
2822  *              GetTopWindow (USER32.@)
2823  */
2824 HWND WINAPI GetTopWindow( HWND hwnd )
2825 {
2826     if (!hwnd) hwnd = GetDesktopWindow();
2827     return GetWindow( hwnd, GW_CHILD );
2828 }
2829
2830
2831 /*******************************************************************
2832  *              GetWindow (USER32.@)
2833  */
2834 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2835 {
2836     HWND retval = 0;
2837
2838     if (rel == GW_OWNER)  /* this one may be available locally */
2839     {
2840         WND *wndPtr = WIN_GetPtr( hwnd );
2841         if (!wndPtr)
2842         {
2843             SetLastError( ERROR_INVALID_HANDLE );
2844             return 0;
2845         }
2846         if (wndPtr == WND_DESKTOP) return 0;
2847         if (wndPtr != WND_OTHER_PROCESS)
2848         {
2849             retval = wndPtr->owner;
2850             WIN_ReleasePtr( wndPtr );
2851             return retval;
2852         }
2853         /* else fall through to server call */
2854     }
2855
2856     SERVER_START_REQ( get_window_tree )
2857     {
2858         req->handle = wine_server_user_handle( hwnd );
2859         if (!wine_server_call_err( req ))
2860         {
2861             switch(rel)
2862             {
2863             case GW_HWNDFIRST:
2864                 retval = wine_server_ptr_handle( reply->first_sibling );
2865                 break;
2866             case GW_HWNDLAST:
2867                 retval = wine_server_ptr_handle( reply->last_sibling );
2868                 break;
2869             case GW_HWNDNEXT:
2870                 retval = wine_server_ptr_handle( reply->next_sibling );
2871                 break;
2872             case GW_HWNDPREV:
2873                 retval = wine_server_ptr_handle( reply->prev_sibling );
2874                 break;
2875             case GW_OWNER:
2876                 retval = wine_server_ptr_handle( reply->owner );
2877                 break;
2878             case GW_CHILD:
2879                 retval = wine_server_ptr_handle( reply->first_child );
2880                 break;
2881             }
2882         }
2883     }
2884     SERVER_END_REQ;
2885     return retval;
2886 }
2887
2888
2889 /*******************************************************************
2890  *              ShowOwnedPopups (USER32.@)
2891  */
2892 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2893 {
2894     int count = 0;
2895     WND *pWnd;
2896     HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2897
2898     if (!win_array) return TRUE;
2899
2900     while (win_array[count]) count++;
2901     while (--count >= 0)
2902     {
2903         if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2904         if (!(pWnd = WIN_GetPtr( win_array[count] ))) continue;
2905         if (pWnd == WND_OTHER_PROCESS) continue;
2906         if (fShow)
2907         {
2908             if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2909             {
2910                 WIN_ReleasePtr( pWnd );
2911                 /* In Windows, ShowOwnedPopups(TRUE) generates
2912                  * WM_SHOWWINDOW messages with SW_PARENTOPENING,
2913                  * regardless of the state of the owner
2914                  */
2915                 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
2916                 continue;
2917             }
2918         }
2919         else
2920         {
2921             if (pWnd->dwStyle & WS_VISIBLE)
2922             {
2923                 WIN_ReleasePtr( pWnd );
2924                 /* In Windows, ShowOwnedPopups(FALSE) generates
2925                  * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
2926                  * regardless of the state of the owner
2927                  */
2928                 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
2929                 continue;
2930             }
2931         }
2932         WIN_ReleasePtr( pWnd );
2933     }
2934     HeapFree( GetProcessHeap(), 0, win_array );
2935     return TRUE;
2936 }
2937
2938
2939 /*******************************************************************
2940  *              GetLastActivePopup (USER32.@)
2941  */
2942 HWND WINAPI GetLastActivePopup( HWND hwnd )
2943 {
2944     HWND retval = hwnd;
2945
2946     SERVER_START_REQ( get_window_info )
2947     {
2948         req->handle = wine_server_user_handle( hwnd );
2949         if (!wine_server_call_err( req )) retval = wine_server_ptr_handle( reply->last_active );
2950     }
2951     SERVER_END_REQ;
2952     return retval;
2953 }
2954
2955
2956 /*******************************************************************
2957  *           WIN_ListChildren
2958  *
2959  * Build an array of the children of a given window. The array must be
2960  * freed with HeapFree. Returns NULL when no windows are found.
2961  */
2962 HWND *WIN_ListChildren( HWND hwnd )
2963 {
2964     if (!hwnd)
2965     {
2966         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2967         return NULL;
2968     }
2969     return list_window_children( 0, hwnd, NULL, 0 );
2970 }
2971
2972
2973 /*******************************************************************
2974  *              EnumWindows (USER32.@)
2975  */
2976 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
2977 {
2978     HWND *list;
2979     BOOL ret = TRUE;
2980     int i;
2981
2982     USER_CheckNotLock();
2983
2984     /* We have to build a list of all windows first, to avoid */
2985     /* unpleasant side-effects, for instance if the callback */
2986     /* function changes the Z-order of the windows.          */
2987
2988     if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
2989
2990     /* Now call the callback function for every window */
2991
2992     for (i = 0; list[i]; i++)
2993     {
2994         /* Make sure that the window still exists */
2995         if (!IsWindow( list[i] )) continue;
2996         if (!(ret = lpEnumFunc( list[i], lParam ))) break;
2997     }
2998     HeapFree( GetProcessHeap(), 0, list );
2999     return ret;
3000 }
3001
3002
3003 /**********************************************************************
3004  *              EnumThreadWindows (USER32.@)
3005  */
3006 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
3007 {
3008     HWND *list;
3009     int i;
3010     BOOL ret = TRUE;
3011
3012     USER_CheckNotLock();
3013
3014     if (!(list = list_window_children( 0, GetDesktopWindow(), NULL, id ))) return TRUE;
3015
3016     /* Now call the callback function for every window */
3017
3018     for (i = 0; list[i]; i++)
3019         if (!(ret = func( list[i], lParam ))) break;
3020     HeapFree( GetProcessHeap(), 0, list );
3021     return ret;
3022 }
3023
3024
3025 /***********************************************************************
3026  *              EnumDesktopWindows   (USER32.@)
3027  */
3028 BOOL WINAPI EnumDesktopWindows( HDESK desktop, WNDENUMPROC func, LPARAM lparam )
3029 {
3030     HWND *list;
3031     int i;
3032
3033     USER_CheckNotLock();
3034
3035     if (!(list = list_window_children( desktop, 0, NULL, 0 ))) return TRUE;
3036
3037     for (i = 0; list[i]; i++)
3038         if (!func( list[i], lparam )) break;
3039     HeapFree( GetProcessHeap(), 0, list );
3040     return TRUE;
3041 }
3042
3043
3044 /**********************************************************************
3045  *           WIN_EnumChildWindows
3046  *
3047  * Helper function for EnumChildWindows().
3048  */
3049 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
3050 {
3051     HWND *childList;
3052     BOOL ret = FALSE;
3053
3054     for ( ; *list; list++)
3055     {
3056         /* Make sure that the window still exists */
3057         if (!IsWindow( *list )) continue;
3058         /* Build children list first */
3059         childList = WIN_ListChildren( *list );
3060
3061         ret = func( *list, lParam );
3062
3063         if (childList)
3064         {
3065             if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
3066             HeapFree( GetProcessHeap(), 0, childList );
3067         }
3068         if (!ret) return FALSE;
3069     }
3070     return TRUE;
3071 }
3072
3073
3074 /**********************************************************************
3075  *              EnumChildWindows (USER32.@)
3076  */
3077 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
3078 {
3079     HWND *list;
3080     BOOL ret;
3081
3082     USER_CheckNotLock();
3083
3084     if (!(list = WIN_ListChildren( parent ))) return FALSE;
3085     ret = WIN_EnumChildWindows( list, func, lParam );
3086     HeapFree( GetProcessHeap(), 0, list );
3087     return ret;
3088 }
3089
3090
3091 /*******************************************************************
3092  *              AnyPopup (USER32.@)
3093  */
3094 BOOL WINAPI AnyPopup(void)
3095 {
3096     int i;
3097     BOOL retvalue;
3098     HWND *list = WIN_ListChildren( GetDesktopWindow() );
3099
3100     if (!list) return FALSE;
3101     for (i = 0; list[i]; i++)
3102     {
3103         if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
3104     }
3105     retvalue = (list[i] != 0);
3106     HeapFree( GetProcessHeap(), 0, list );
3107     return retvalue;
3108 }
3109
3110
3111 /*******************************************************************
3112  *              FlashWindow (USER32.@)
3113  */
3114 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3115 {
3116     WND *wndPtr;
3117
3118     TRACE("%p\n", hWnd);
3119
3120     if (IsIconic( hWnd ))
3121     {
3122         RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
3123
3124         wndPtr = WIN_GetPtr(hWnd);
3125         if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3126         if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
3127         {
3128             wndPtr->flags |= WIN_NCACTIVATED;
3129         }
3130         else
3131         {
3132             wndPtr->flags &= ~WIN_NCACTIVATED;
3133         }
3134         WIN_ReleasePtr( wndPtr );
3135         return TRUE;
3136     }
3137     else
3138     {
3139         WPARAM wparam;
3140
3141         wndPtr = WIN_GetPtr(hWnd);
3142         if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3143         hWnd = wndPtr->obj.handle;  /* make it a full handle */
3144
3145         if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3146         else wparam = (hWnd == GetForegroundWindow());
3147
3148         WIN_ReleasePtr( wndPtr );
3149         SendMessageW( hWnd, WM_NCACTIVATE, wparam, 0 );
3150         return wparam;
3151     }
3152 }
3153
3154 /*******************************************************************
3155  *              FlashWindowEx (USER32.@)
3156  */
3157 BOOL WINAPI FlashWindowEx( PFLASHWINFO pfwi )
3158 {
3159     FIXME("%p\n", pfwi);
3160     return TRUE;
3161 }
3162
3163 /*******************************************************************
3164  *              GetWindowContextHelpId (USER32.@)
3165  */
3166 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3167 {
3168     DWORD retval;
3169     WND *wnd = WIN_GetPtr( hwnd );
3170     if (!wnd || wnd == WND_DESKTOP) return 0;
3171     if (wnd == WND_OTHER_PROCESS)
3172     {
3173         if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3174         return 0;
3175     }
3176     retval = wnd->helpContext;
3177     WIN_ReleasePtr( wnd );
3178     return retval;
3179 }
3180
3181
3182 /*******************************************************************
3183  *              SetWindowContextHelpId (USER32.@)
3184  */
3185 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3186 {
3187     WND *wnd = WIN_GetPtr( hwnd );
3188     if (!wnd || wnd == WND_DESKTOP) return FALSE;
3189     if (wnd == WND_OTHER_PROCESS)
3190     {
3191         if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3192         return 0;
3193     }
3194     wnd->helpContext = id;
3195     WIN_ReleasePtr( wnd );
3196     return TRUE;
3197 }
3198
3199
3200 /*******************************************************************
3201  *              DragDetect (USER32.@)
3202  */
3203 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3204 {
3205     MSG msg;
3206     RECT rect;
3207     WORD wDragWidth = GetSystemMetrics(SM_CXDRAG);
3208     WORD wDragHeight= GetSystemMetrics(SM_CYDRAG);
3209
3210     rect.left = pt.x - wDragWidth;
3211     rect.right = pt.x + wDragWidth;
3212
3213     rect.top = pt.y - wDragHeight;
3214     rect.bottom = pt.y + wDragHeight;
3215
3216     SetCapture(hWnd);
3217
3218     while(1)
3219     {
3220         while (PeekMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ))
3221         {
3222             if( msg.message == WM_LBUTTONUP )
3223             {
3224                 ReleaseCapture();
3225                 return 0;
3226             }
3227             if( msg.message == WM_MOUSEMOVE )
3228             {
3229                 POINT tmp;
3230                 tmp.x = (short)LOWORD(msg.lParam);
3231                 tmp.y = (short)HIWORD(msg.lParam);
3232                 if( !PtInRect( &rect, tmp ))
3233                 {
3234                     ReleaseCapture();
3235                     return 1;
3236                 }
3237             }
3238         }
3239         WaitMessage();
3240     }
3241     return 0;
3242 }
3243
3244 /******************************************************************************
3245  *              GetWindowModuleFileNameA (USER32.@)
3246  */
3247 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR module, UINT size )
3248 {
3249     WND *win;
3250     HINSTANCE hinst;
3251
3252     TRACE( "%p, %p, %u\n", hwnd, module, size );
3253
3254     win = WIN_GetPtr( hwnd );
3255     if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3256     {
3257         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3258         return 0;
3259     }
3260     hinst = win->hInstance;
3261     WIN_ReleasePtr( win );
3262
3263     return GetModuleFileNameA( hinst, module, size );
3264 }
3265
3266 /******************************************************************************
3267  *              GetWindowModuleFileNameW (USER32.@)
3268  */
3269 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR module, UINT size )
3270 {
3271     WND *win;
3272     HINSTANCE hinst;
3273
3274     TRACE( "%p, %p, %u\n", hwnd, module, size );
3275
3276     win = WIN_GetPtr( hwnd );
3277     if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3278     {
3279         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3280         return 0;
3281     }
3282     hinst = win->hInstance;
3283     WIN_ReleasePtr( win );
3284
3285     return GetModuleFileNameW( hinst, module, size );
3286 }
3287
3288 /******************************************************************************
3289  *              GetWindowInfo (USER32.@)
3290  *
3291  * Note: tests show that Windows doesn't check cbSize of the structure.
3292  */
3293 BOOL WINAPI GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3294 {
3295     if (!pwi) return FALSE;
3296     if (!IsWindow(hwnd)) return FALSE;
3297
3298     GetWindowRect(hwnd, &pwi->rcWindow);
3299     GetClientRect(hwnd, &pwi->rcClient);
3300     /* translate to screen coordinates */
3301     MapWindowPoints(hwnd, 0, (LPPOINT)&pwi->rcClient, 2);
3302
3303     pwi->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
3304     pwi->dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3305     pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3306
3307     pwi->cxWindowBorders = pwi->rcClient.left - pwi->rcWindow.left;
3308     pwi->cyWindowBorders = pwi->rcWindow.bottom - pwi->rcClient.bottom;
3309
3310     pwi->atomWindowType = GetClassLongW( hwnd, GCW_ATOM );
3311     pwi->wCreatorVersion = 0x0400;
3312
3313     return TRUE;
3314 }
3315
3316 /******************************************************************************
3317  *              SwitchDesktop (USER32.@)
3318  *
3319  * NOTES: Sets the current input or interactive desktop.
3320  */
3321 BOOL WINAPI SwitchDesktop( HDESK hDesktop)
3322 {
3323     FIXME("(hwnd %p) stub!\n", hDesktop);
3324     return TRUE;
3325 }
3326
3327 /*****************************************************************************
3328  *              SetLayeredWindowAttributes (USER32.@)
3329  */
3330 BOOL WINAPI SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, DWORD flags )
3331 {
3332     BOOL ret;
3333
3334     TRACE("(%p,%08x,%d,%x): stub!\n", hwnd, key, alpha, flags);
3335
3336     SERVER_START_REQ( set_window_layered_info )
3337     {
3338         req->handle = wine_server_user_handle( hwnd );
3339         req->color_key = key;
3340         req->alpha = alpha;
3341         req->flags = flags;
3342         ret = !wine_server_call_err( req );
3343     }
3344     SERVER_END_REQ;
3345
3346     if (ret) USER_Driver->pSetLayeredWindowAttributes( hwnd, key, alpha, flags );
3347
3348     return ret;
3349 }
3350
3351
3352 /*****************************************************************************
3353  *              GetLayeredWindowAttributes (USER32.@)
3354  */
3355 BOOL WINAPI GetLayeredWindowAttributes( HWND hwnd, COLORREF *key, BYTE *alpha, DWORD *flags )
3356 {
3357     BOOL ret;
3358
3359     SERVER_START_REQ( get_window_layered_info )
3360     {
3361         req->handle = wine_server_user_handle( hwnd );
3362         if ((ret = !wine_server_call_err( req )))
3363         {
3364             if (key) *key = reply->color_key;
3365             if (alpha) *alpha = reply->alpha;
3366             if (flags) *flags = reply->flags;
3367         }
3368     }
3369     SERVER_END_REQ;
3370
3371     return ret;
3372 }
3373
3374
3375 /*****************************************************************************
3376  *              UpdateLayeredWindowIndirect  (USER32.@)
3377  */
3378 BOOL WINAPI UpdateLayeredWindowIndirect( HWND hwnd, const UPDATELAYEREDWINDOWINFO *info )
3379 {
3380     BYTE alpha = 0xff;
3381
3382     if (!(info->dwFlags & ULW_EX_NORESIZE) && (info->pptDst || info->psize))
3383     {
3384         int x = 0, y = 0, cx = 0, cy = 0;
3385         DWORD flags = SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOSENDCHANGING;
3386
3387         if (info->pptDst)
3388         {
3389             x = info->pptDst->x;
3390             y = info->pptDst->y;
3391             flags &= ~SWP_NOMOVE;
3392         }
3393         if (info->psize)
3394         {
3395             cx = info->psize->cx;
3396             cy = info->psize->cy;
3397             flags &= ~SWP_NOSIZE;
3398         }
3399         TRACE( "moving window %p pos %d,%d %dx%d\n", hwnd, x, y, cx, cy );
3400         SetWindowPos( hwnd, 0, x, y, cx, cy, flags );
3401     }
3402
3403     if (info->hdcSrc)
3404     {
3405         HDC hdc = GetWindowDC( hwnd );
3406
3407         if (hdc)
3408         {
3409             int x = 0, y = 0;
3410             RECT rect;
3411
3412             GetWindowRect( hwnd, &rect );
3413             OffsetRect( &rect, -rect.left, -rect.top);
3414             if (info->pptSrc)
3415             {
3416                 x = info->pptSrc->x;
3417                 y = info->pptSrc->y;
3418             }
3419
3420             if (!info->prcDirty || (info->prcDirty && IntersectRect(&rect, &rect, info->prcDirty)))
3421             {
3422                 TRACE( "copying window %p pos %d,%d\n", hwnd, x, y );
3423                 BitBlt( hdc, rect.left, rect.top, rect.right, rect.bottom,
3424                         info->hdcSrc, rect.left + x, rect.top + y, SRCCOPY );
3425             }
3426             ReleaseDC( hwnd, hdc );
3427         }
3428     }
3429
3430     if (info->pblend && !(info->dwFlags & ULW_OPAQUE)) alpha = info->pblend->SourceConstantAlpha;
3431     TRACE( "setting window %p alpha %u\n", hwnd, alpha );
3432     USER_Driver->pSetLayeredWindowAttributes( hwnd, info->crKey, alpha,
3433                                               info->dwFlags & (LWA_ALPHA | LWA_COLORKEY) );
3434     return TRUE;
3435 }
3436
3437
3438 /*****************************************************************************
3439  *              UpdateLayeredWindow (USER32.@)
3440  */
3441 BOOL WINAPI UpdateLayeredWindow( HWND hwnd, HDC hdcDst, POINT *pptDst, SIZE *psize,
3442                                  HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend,
3443                                  DWORD dwFlags)
3444 {
3445     UPDATELAYEREDWINDOWINFO info;
3446
3447     info.cbSize   = sizeof(info);
3448     info.hdcDst   = hdcDst;
3449     info.pptDst   = pptDst;
3450     info.psize    = psize;
3451     info.hdcSrc   = hdcSrc;
3452     info.pptSrc   = pptSrc;
3453     info.crKey    = crKey;
3454     info.pblend   = pblend;
3455     info.dwFlags  = dwFlags;
3456     info.prcDirty = NULL;
3457     return UpdateLayeredWindowIndirect( hwnd, &info );
3458 }
3459
3460 /* 64bit versions */
3461
3462 #ifdef GetWindowLongPtrW
3463 #undef GetWindowLongPtrW
3464 #endif
3465
3466 #ifdef GetWindowLongPtrA
3467 #undef GetWindowLongPtrA
3468 #endif
3469
3470 #ifdef SetWindowLongPtrW
3471 #undef SetWindowLongPtrW
3472 #endif
3473
3474 #ifdef SetWindowLongPtrA
3475 #undef SetWindowLongPtrA
3476 #endif
3477
3478 /*****************************************************************************
3479  *              GetWindowLongPtrW (USER32.@)
3480  */
3481 LONG_PTR WINAPI GetWindowLongPtrW( HWND hwnd, INT offset )
3482 {
3483     return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), TRUE );
3484 }
3485
3486 /*****************************************************************************
3487  *              GetWindowLongPtrA (USER32.@)
3488  */
3489 LONG_PTR WINAPI GetWindowLongPtrA( HWND hwnd, INT offset )
3490 {
3491     return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), FALSE );
3492 }
3493
3494 /*****************************************************************************
3495  *              SetWindowLongPtrW (USER32.@)
3496  */
3497 LONG_PTR WINAPI SetWindowLongPtrW( HWND hwnd, INT offset, LONG_PTR newval )
3498 {
3499     return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, TRUE );
3500 }
3501
3502 /*****************************************************************************
3503  *              SetWindowLongPtrA (USER32.@)
3504  */
3505 LONG_PTR WINAPI SetWindowLongPtrA( HWND hwnd, INT offset, LONG_PTR newval )
3506 {
3507     return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, FALSE );
3508 }