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