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