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