winedd: Move shader_*_add_instruction_modifiers into the shader backend.
[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 = wine_server_client_ptr( 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       = wine_server_get_ptr( 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 = &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->pScroll        = NULL;
1077     wndPtr->userdata       = 0;
1078     wndPtr->hIcon          = 0;
1079     wndPtr->hIconSmall     = 0;
1080     wndPtr->hSysMenu       = 0;
1081     wndPtr->flags         |= (flags & WIN_ISWIN32);
1082
1083     wndPtr->min_pos.x = wndPtr->min_pos.y = -1;
1084     wndPtr->max_pos.x = wndPtr->max_pos.y = -1;
1085
1086     if (wndPtr->dwStyle & WS_SYSMENU) SetSystemMenu( hwnd, 0 );
1087
1088     /*
1089      * Correct the window styles.
1090      *
1091      * It affects only the style loaded into the WIN structure.
1092      */
1093
1094     if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1095     {
1096         wndPtr->dwStyle |= WS_CLIPSIBLINGS;
1097         if (!(wndPtr->dwStyle & WS_POPUP))
1098             wndPtr->dwStyle |= WS_CAPTION;
1099     }
1100
1101     /*
1102      * WS_EX_WINDOWEDGE appears to be enforced based on the other styles, so
1103      * why does the user get to set it?
1104      */
1105
1106     if ((wndPtr->dwExStyle & WS_EX_DLGMODALFRAME) ||
1107           (wndPtr->dwStyle & (WS_DLGFRAME | WS_THICKFRAME)))
1108         wndPtr->dwExStyle |= WS_EX_WINDOWEDGE;
1109     else
1110         wndPtr->dwExStyle &= ~WS_EX_WINDOWEDGE;
1111
1112     if (!(wndPtr->dwStyle & (WS_CHILD | WS_POPUP)))
1113         wndPtr->flags |= WIN_NEED_SIZE;
1114
1115     SERVER_START_REQ( set_window_info )
1116     {
1117         req->handle    = wine_server_user_handle( hwnd );
1118         req->flags     = SET_WIN_STYLE | SET_WIN_EXSTYLE | SET_WIN_INSTANCE | SET_WIN_UNICODE;
1119         req->style     = wndPtr->dwStyle;
1120         req->ex_style  = wndPtr->dwExStyle;
1121         req->instance  = wine_server_client_ptr( wndPtr->hInstance );
1122         req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
1123         req->extra_offset = -1;
1124         wine_server_call( req );
1125     }
1126     SERVER_END_REQ;
1127
1128     /* Set the window menu */
1129
1130     if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1131     {
1132         if (cs->hMenu)
1133         {
1134             if (!MENU_SetMenu(hwnd, cs->hMenu))
1135             {
1136                 WIN_ReleasePtr( wndPtr );
1137                 free_window_handle( hwnd );
1138                 return 0;
1139             }
1140         }
1141         else
1142         {
1143             LPCSTR menuName = (LPCSTR)GetClassLongPtrA( hwnd, GCLP_MENUNAME );
1144             if (menuName)
1145             {
1146                 if (!cs->hInstance || HIWORD(cs->hInstance))
1147                     cs->hMenu = LoadMenuA(cs->hInstance,menuName);
1148                 else
1149                     cs->hMenu = HMENU_32(LoadMenu16(HINSTANCE_16(cs->hInstance),menuName));
1150
1151                 if (cs->hMenu) MENU_SetMenu( hwnd, cs->hMenu );
1152             }
1153         }
1154     }
1155     else SetWindowLongPtrW( hwnd, GWLP_ID, (ULONG_PTR)cs->hMenu );
1156
1157     /* call the WH_CBT hook */
1158
1159     /* the window style passed to the hook must be the real window style,
1160      * rather than just the window style that the caller to CreateWindowEx
1161      * passed in, so we have to copy the original CREATESTRUCT and get the
1162      * the real style. */
1163     cbcs = *cs;
1164     cbcs.style = wndPtr->dwStyle;
1165     cbtc.lpcs = &cbcs;
1166     cbtc.hwndInsertAfter = HWND_TOP;
1167     WIN_ReleasePtr( wndPtr );
1168     if (HOOK_CallHooks( WH_CBT, HCBT_CREATEWND, (WPARAM)hwnd, (LPARAM)&cbtc, unicode )) goto failed;
1169
1170     /* send the WM_GETMINMAXINFO message and fix the size if needed */
1171
1172     cx = cs->cx;
1173     cy = cs->cy;
1174     if ((cs->style & WS_THICKFRAME) || !(cs->style & (WS_POPUP | WS_CHILD)))
1175     {
1176         POINT maxSize, maxPos, minTrack, maxTrack;
1177         WINPOS_GetMinMaxInfo( hwnd, &maxSize, &maxPos, &minTrack, &maxTrack);
1178         if (maxTrack.x < cx) cx = maxTrack.x;
1179         if (maxTrack.y < cy) cy = maxTrack.y;
1180         if (minTrack.x > cx) cx = minTrack.x;
1181         if (minTrack.y > cy) cy = minTrack.y;
1182     }
1183
1184     if (cx < 0) cx = 0;
1185     if (cy < 0) cy = 0;
1186     SetRect( &rect, cs->x, cs->y, cs->x + cx, cs->y + cy );
1187     /* check for wraparound */
1188     if (cs->x + cx < cs->x) rect.right = 0x7fffffff;
1189     if (cs->y + cy < cs->y) rect.bottom = 0x7fffffff;
1190     if (!set_window_pos( hwnd, 0, SWP_NOZORDER | SWP_NOACTIVATE, &rect, &rect, NULL )) goto failed;
1191
1192     /* send WM_NCCREATE */
1193
1194     TRACE( "hwnd %p cs %d,%d %dx%d\n", hwnd, cs->x, cs->y, cx, cy );
1195     if (unicode)
1196         result = SendMessageW( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1197     else
1198         result = SendMessageA( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1199     if (!result)
1200     {
1201         WARN( "%p: aborted by WM_NCCREATE\n", hwnd );
1202         goto failed;
1203     }
1204
1205     /* send WM_NCCALCSIZE */
1206
1207     if ((wndPtr = WIN_GetPtr(hwnd)))
1208     {
1209         /* yes, even if the CBT hook was called with HWND_TOP */
1210         POINT pt;
1211         HWND insert_after = (wndPtr->dwStyle & WS_CHILD) ? HWND_BOTTOM : HWND_TOP;
1212         RECT window_rect = wndPtr->rectWindow;
1213         RECT client_rect = window_rect;
1214         WIN_ReleasePtr( wndPtr );
1215
1216         /* the rectangle is in screen coords for WM_NCCALCSIZE when wparam is FALSE */
1217         pt.x = pt.y = 0;
1218         MapWindowPoints( parent, 0, &pt, 1 );
1219         OffsetRect( &client_rect, pt.x, pt.y );
1220         SendMessageW( hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&client_rect );
1221         OffsetRect( &client_rect, -pt.x, -pt.y );
1222         set_window_pos( hwnd, insert_after, SWP_NOACTIVATE, &window_rect, &client_rect, NULL );
1223     }
1224     else return 0;
1225
1226     /* send WM_CREATE */
1227
1228     if (unicode)
1229         result = SendMessageW( hwnd, WM_CREATE, 0, (LPARAM)cs );
1230     else
1231         result = SendMessageA( hwnd, WM_CREATE, 0, (LPARAM)cs );
1232     if (result == -1) goto failed;
1233
1234     /* call the driver */
1235
1236     if (!USER_Driver->pCreateWindow( hwnd )) goto failed;
1237
1238     NotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_WINDOW, 0);
1239
1240     /* send the size messages */
1241
1242     if (!(wndPtr = WIN_GetPtr( hwnd )) ||
1243           wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
1244     if (!(wndPtr->flags & WIN_NEED_SIZE))
1245     {
1246         rect = wndPtr->rectClient;
1247         WIN_ReleasePtr( wndPtr );
1248         SendMessageW( hwnd, WM_SIZE, SIZE_RESTORED,
1249                       MAKELONG(rect.right-rect.left, rect.bottom-rect.top));
1250         SendMessageW( hwnd, WM_MOVE, 0, MAKELONG( rect.left, rect.top ) );
1251     }
1252     else WIN_ReleasePtr( wndPtr );
1253
1254     /* Show the window, maximizing or minimizing if needed */
1255
1256     style = WIN_SetStyle( hwnd, 0, WS_MAXIMIZE | WS_MINIMIZE );
1257     if (style & (WS_MINIMIZE | WS_MAXIMIZE))
1258     {
1259         RECT newPos;
1260         UINT swFlag = (style & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;
1261
1262         swFlag = WINPOS_MinMaximize( hwnd, swFlag, &newPos );
1263         swFlag |= SWP_FRAMECHANGED; /* Frame always gets changed */
1264         if (!(style & WS_VISIBLE) || (style & WS_CHILD) || GetActiveWindow()) swFlag |= SWP_NOACTIVATE;
1265         SetWindowPos( hwnd, 0, newPos.left, newPos.top, newPos.right - newPos.left,
1266                       newPos.bottom - newPos.top, swFlag );
1267     }
1268
1269     /* Notify the parent window only */
1270
1271     send_parent_notify( hwnd, WM_CREATE );
1272     if (!IsWindow( hwnd )) return 0;
1273
1274     if (cs->style & WS_VISIBLE)
1275     {
1276         if (cs->style & WS_MAXIMIZE)
1277             sw = SW_SHOW;
1278         else if (cs->style & WS_MINIMIZE)
1279             sw = SW_SHOWMINIMIZED;
1280
1281         ShowWindow( hwnd, sw );
1282         if (cs->dwExStyle & WS_EX_MDICHILD)
1283         {
1284             SendMessageW(cs->hwndParent, WM_MDIREFRESHMENU, 0, 0);
1285             /* ShowWindow won't activate child windows */
1286             SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE );
1287         }
1288     }
1289
1290     /* Call WH_SHELL hook */
1291
1292     if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1293         HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0, TRUE );
1294
1295     TRACE("created window %p\n", hwnd);
1296     return hwnd;
1297
1298 failed:
1299     WIN_DestroyWindow( hwnd );
1300     return 0;
1301 }
1302
1303
1304 /***********************************************************************
1305  *              CreateWindow (USER.41)
1306  */
1307 HWND16 WINAPI CreateWindow16( LPCSTR className, LPCSTR windowName,
1308                               DWORD style, INT16 x, INT16 y, INT16 width,
1309                               INT16 height, HWND16 parent, HMENU16 menu,
1310                               HINSTANCE16 instance, LPVOID data )
1311 {
1312     return CreateWindowEx16( 0, className, windowName, style,
1313                              x, y, width, height, parent, menu, instance, data );
1314 }
1315
1316
1317 /***********************************************************************
1318  *              CreateWindowEx (USER.452)
1319  */
1320 HWND16 WINAPI CreateWindowEx16( DWORD exStyle, LPCSTR className,
1321                                 LPCSTR windowName, DWORD style, INT16 x,
1322                                 INT16 y, INT16 width, INT16 height,
1323                                 HWND16 parent, HMENU16 menu,
1324                                 HINSTANCE16 instance, LPVOID data )
1325 {
1326     CREATESTRUCTA cs;
1327     char buffer[256];
1328
1329     /* Fix the coordinates */
1330
1331     cs.x  = (x == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)x;
1332     cs.y  = (y == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)y;
1333     cs.cx = (width == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)width;
1334     cs.cy = (height == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)height;
1335
1336     /* Create the window */
1337
1338     cs.lpCreateParams = data;
1339     cs.hInstance      = HINSTANCE_32(instance);
1340     cs.hMenu          = HMENU_32(menu);
1341     cs.hwndParent     = WIN_Handle32( parent );
1342     cs.style          = style;
1343     cs.lpszName       = windowName;
1344     cs.lpszClass      = className;
1345     cs.dwExStyle      = exStyle;
1346
1347     if (!IS_INTRESOURCE(className))
1348     {
1349         WCHAR bufferW[256];
1350
1351         if (!MultiByteToWideChar( CP_ACP, 0, className, -1, bufferW, sizeof(bufferW)/sizeof(WCHAR) ))
1352             return 0;
1353         return HWND_16( WIN_CreateWindowEx( &cs, bufferW, 0 ));
1354     }
1355     else
1356     {
1357         if (!GlobalGetAtomNameA( LOWORD(className), buffer, sizeof(buffer) ))
1358         {
1359             ERR( "bad atom %x\n", LOWORD(className));
1360             return 0;
1361         }
1362         cs.lpszClass = buffer;
1363         return HWND_16( WIN_CreateWindowEx( &cs, (LPCWSTR)className, 0 ));
1364     }
1365 }
1366
1367
1368 /***********************************************************************
1369  *              CreateWindowExA (USER32.@)
1370  */
1371 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1372                                  LPCSTR windowName, DWORD style, INT x,
1373                                  INT y, INT width, INT height,
1374                                  HWND parent, HMENU menu,
1375                                  HINSTANCE instance, LPVOID data )
1376 {
1377     CREATESTRUCTA cs;
1378
1379     cs.lpCreateParams = data;
1380     cs.hInstance      = instance;
1381     cs.hMenu          = menu;
1382     cs.hwndParent     = parent;
1383     cs.x              = x;
1384     cs.y              = y;
1385     cs.cx             = width;
1386     cs.cy             = height;
1387     cs.style          = style;
1388     cs.lpszName       = windowName;
1389     cs.lpszClass      = className;
1390     cs.dwExStyle      = exStyle;
1391
1392     if (!IS_INTRESOURCE(className))
1393     {
1394         WCHAR bufferW[256];
1395         if (!MultiByteToWideChar( CP_ACP, 0, className, -1, bufferW, sizeof(bufferW)/sizeof(WCHAR) ))
1396             return 0;
1397         return WIN_CreateWindowEx( &cs, bufferW, WIN_ISWIN32 );
1398     }
1399     return WIN_CreateWindowEx( &cs, (LPCWSTR)className, WIN_ISWIN32 );
1400 }
1401
1402
1403 /***********************************************************************
1404  *              CreateWindowExW (USER32.@)
1405  */
1406 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1407                                  LPCWSTR windowName, DWORD style, INT x,
1408                                  INT y, INT width, INT height,
1409                                  HWND parent, HMENU menu,
1410                                  HINSTANCE instance, LPVOID data )
1411 {
1412     CREATESTRUCTW cs;
1413
1414     cs.lpCreateParams = data;
1415     cs.hInstance      = instance;
1416     cs.hMenu          = menu;
1417     cs.hwndParent     = parent;
1418     cs.x              = x;
1419     cs.y              = y;
1420     cs.cx             = width;
1421     cs.cy             = height;
1422     cs.style          = style;
1423     cs.lpszName       = windowName;
1424     cs.lpszClass      = className;
1425     cs.dwExStyle      = exStyle;
1426
1427     /* Note: we rely on the fact that CREATESTRUCTA and */
1428     /* CREATESTRUCTW have the same layout. */
1429     return WIN_CreateWindowEx( (CREATESTRUCTA *)&cs, className, WIN_ISWIN32 | WIN_ISUNICODE );
1430 }
1431
1432
1433 /***********************************************************************
1434  *           WIN_SendDestroyMsg
1435  */
1436 static void WIN_SendDestroyMsg( HWND hwnd )
1437 {
1438     GUITHREADINFO info;
1439
1440     if (GetGUIThreadInfo( GetCurrentThreadId(), &info ))
1441     {
1442         if (hwnd == info.hwndCaret) DestroyCaret();
1443         if (hwnd == info.hwndActive) WINPOS_ActivateOtherWindow( hwnd );
1444     }
1445
1446     /*
1447      * Send the WM_DESTROY to the window.
1448      */
1449     SendMessageW( hwnd, WM_DESTROY, 0, 0);
1450
1451     /*
1452      * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1453      * make sure that the window still exists when we come back.
1454      */
1455     if (IsWindow(hwnd))
1456     {
1457         HWND* pWndArray;
1458         int i;
1459
1460         if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1461
1462         for (i = 0; pWndArray[i]; i++)
1463         {
1464             if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1465         }
1466         HeapFree( GetProcessHeap(), 0, pWndArray );
1467     }
1468     else
1469       WARN("\tdestroyed itself while in WM_DESTROY!\n");
1470 }
1471
1472
1473 /***********************************************************************
1474  *              DestroyWindow (USER32.@)
1475  */
1476 BOOL WINAPI DestroyWindow( HWND hwnd )
1477 {
1478     BOOL is_child;
1479
1480     if (!(hwnd = WIN_IsCurrentThread( hwnd )) || is_desktop_window( hwnd ))
1481     {
1482         SetLastError( ERROR_ACCESS_DENIED );
1483         return FALSE;
1484     }
1485
1486     TRACE("(%p)\n", hwnd);
1487
1488       /* Call hooks */
1489
1490     if (HOOK_CallHooks( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0, TRUE )) return FALSE;
1491
1492     if (MENU_IsMenuActive() == hwnd)
1493         EndMenu();
1494
1495     is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;
1496
1497     if (is_child)
1498     {
1499         if (!USER_IsExitingThread( GetCurrentThreadId() ))
1500             send_parent_notify( hwnd, WM_DESTROY );
1501     }
1502     else if (!GetWindow( hwnd, GW_OWNER ))
1503     {
1504         HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
1505         /* FIXME: clean up palette - see "Internals" p.352 */
1506     }
1507
1508     if (!IsWindow(hwnd)) return TRUE;
1509
1510       /* Hide the window */
1511     if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)
1512     {
1513         /* Only child windows receive WM_SHOWWINDOW in DestroyWindow() */
1514         if (is_child)
1515             ShowWindow( hwnd, SW_HIDE );
1516         else
1517             SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE |
1518                           SWP_NOZORDER | SWP_NOACTIVATE | SWP_HIDEWINDOW );
1519     }
1520
1521     if (!IsWindow(hwnd)) return TRUE;
1522
1523       /* Recursively destroy owned windows */
1524
1525     if (!is_child)
1526     {
1527         for (;;)
1528         {
1529             int i, got_one = 0;
1530             HWND *list = WIN_ListChildren( GetDesktopWindow() );
1531             if (list)
1532             {
1533                 for (i = 0; list[i]; i++)
1534                 {
1535                     if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1536                     if (WIN_IsCurrentThread( list[i] ))
1537                     {
1538                         DestroyWindow( list[i] );
1539                         got_one = 1;
1540                         continue;
1541                     }
1542                     WIN_SetOwner( list[i], 0 );
1543                 }
1544                 HeapFree( GetProcessHeap(), 0, list );
1545             }
1546             if (!got_one) break;
1547         }
1548     }
1549
1550       /* Send destroy messages */
1551
1552     WIN_SendDestroyMsg( hwnd );
1553     if (!IsWindow( hwnd )) return TRUE;
1554
1555     if (GetClipboardOwner() == hwnd)
1556         CLIPBOARD_ReleaseOwner();
1557
1558       /* Destroy the window storage */
1559
1560     WIN_DestroyWindow( hwnd );
1561     return TRUE;
1562 }
1563
1564
1565 /***********************************************************************
1566  *              CloseWindow (USER32.@)
1567  */
1568 BOOL WINAPI CloseWindow( HWND hwnd )
1569 {
1570     if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1571     ShowWindow( hwnd, SW_MINIMIZE );
1572     return TRUE;
1573 }
1574
1575
1576 /***********************************************************************
1577  *              OpenIcon (USER32.@)
1578  */
1579 BOOL WINAPI OpenIcon( HWND hwnd )
1580 {
1581     if (!IsIconic( hwnd )) return FALSE;
1582     ShowWindow( hwnd, SW_SHOWNORMAL );
1583     return TRUE;
1584 }
1585
1586
1587 /***********************************************************************
1588  *              FindWindowExW (USER32.@)
1589  */
1590 HWND WINAPI FindWindowExW( HWND parent, HWND child, LPCWSTR className, LPCWSTR title )
1591 {
1592     HWND *list = NULL;
1593     HWND retvalue = 0;
1594     int i = 0, len = 0;
1595     WCHAR *buffer = NULL;
1596
1597     if (!parent && child) parent = GetDesktopWindow();
1598     else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
1599
1600     if (title)
1601     {
1602         len = strlenW(title) + 1;  /* one extra char to check for chars beyond the end */
1603         if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1604     }
1605
1606     if (!(list = list_window_children( 0, parent, className, 0 ))) goto done;
1607
1608     if (child)
1609     {
1610         child = WIN_GetFullHandle( child );
1611         while (list[i] && list[i] != child) i++;
1612         if (!list[i]) goto done;
1613         i++;  /* start from next window */
1614     }
1615
1616     if (title)
1617     {
1618         while (list[i])
1619         {
1620             if (GetWindowTextW( list[i], buffer, len + 1 ) && !strcmpiW( buffer, title )) break;
1621             i++;
1622         }
1623     }
1624     retvalue = list[i];
1625
1626  done:
1627     HeapFree( GetProcessHeap(), 0, list );
1628     HeapFree( GetProcessHeap(), 0, buffer );
1629     return retvalue;
1630 }
1631
1632
1633
1634 /***********************************************************************
1635  *              FindWindowA (USER32.@)
1636  */
1637 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1638 {
1639     HWND ret = FindWindowExA( 0, 0, className, title );
1640     if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1641     return ret;
1642 }
1643
1644
1645 /***********************************************************************
1646  *              FindWindowExA (USER32.@)
1647  */
1648 HWND WINAPI FindWindowExA( HWND parent, HWND child, LPCSTR className, LPCSTR title )
1649 {
1650     LPWSTR titleW = NULL;
1651     HWND hwnd = 0;
1652
1653     if (title)
1654     {
1655         DWORD len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
1656         if (!(titleW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
1657         MultiByteToWideChar( CP_ACP, 0, title, -1, titleW, len );
1658     }
1659
1660     if (!IS_INTRESOURCE(className))
1661     {
1662         WCHAR classW[256];
1663         if (MultiByteToWideChar( CP_ACP, 0, className, -1, classW, sizeof(classW)/sizeof(WCHAR) ))
1664             hwnd = FindWindowExW( parent, child, classW, titleW );
1665     }
1666     else
1667     {
1668         hwnd = FindWindowExW( parent, child, (LPCWSTR)className, titleW );
1669     }
1670
1671     HeapFree( GetProcessHeap(), 0, titleW );
1672     return hwnd;
1673 }
1674
1675
1676 /***********************************************************************
1677  *              FindWindowW (USER32.@)
1678  */
1679 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
1680 {
1681     return FindWindowExW( 0, 0, className, title );
1682 }
1683
1684
1685 /**********************************************************************
1686  *              GetDesktopWindow (USER32.@)
1687  */
1688 HWND WINAPI GetDesktopWindow(void)
1689 {
1690     struct user_thread_info *thread_info = get_user_thread_info();
1691
1692     if (thread_info->top_window) return thread_info->top_window;
1693
1694     SERVER_START_REQ( get_desktop_window )
1695     {
1696         req->force = 0;
1697         if (!wine_server_call( req ))
1698         {
1699             thread_info->top_window = wine_server_ptr_handle( reply->top_window );
1700             thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
1701         }
1702     }
1703     SERVER_END_REQ;
1704
1705     if (!thread_info->top_window)
1706     {
1707         USEROBJECTFLAGS flags;
1708         if (!GetUserObjectInformationW( GetProcessWindowStation(), UOI_FLAGS, &flags,
1709                                         sizeof(flags), NULL ) || (flags.dwFlags & WSF_VISIBLE))
1710         {
1711             static const WCHAR command_line[] = {'\\','e','x','p','l','o','r','e','r','.','e','x','e',' ','/','d','e','s','k','t','o','p',0};
1712             STARTUPINFOW si;
1713             PROCESS_INFORMATION pi;
1714             WCHAR cmdline[MAX_PATH + sizeof(command_line)/sizeof(WCHAR)];
1715
1716             memset( &si, 0, sizeof(si) );
1717             si.cb = sizeof(si);
1718             si.dwFlags = STARTF_USESTDHANDLES;
1719             si.hStdInput  = 0;
1720             si.hStdOutput = 0;
1721             si.hStdError  = GetStdHandle( STD_ERROR_HANDLE );
1722
1723             GetSystemDirectoryW( cmdline, MAX_PATH );
1724             lstrcatW( cmdline, command_line );
1725             if (CreateProcessW( NULL, cmdline, NULL, NULL, FALSE, DETACHED_PROCESS,
1726                                 NULL, NULL, &si, &pi ))
1727             {
1728                 TRACE( "started explorer pid %04x tid %04x\n", pi.dwProcessId, pi.dwThreadId );
1729                 WaitForInputIdle( pi.hProcess, 10000 );
1730                 CloseHandle( pi.hThread );
1731                 CloseHandle( pi.hProcess );
1732             }
1733             else WARN( "failed to start explorer, err %d\n", GetLastError() );
1734         }
1735         else TRACE( "not starting explorer since winstation is not visible\n" );
1736
1737         SERVER_START_REQ( get_desktop_window )
1738         {
1739             req->force = 1;
1740             if (!wine_server_call( req ))
1741             {
1742                 thread_info->top_window = wine_server_ptr_handle( reply->top_window );
1743                 thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
1744             }
1745         }
1746         SERVER_END_REQ;
1747     }
1748
1749     if (!thread_info->top_window || !USER_Driver->pCreateDesktopWindow( thread_info->top_window ))
1750         ERR( "failed to create desktop window\n" );
1751
1752     return thread_info->top_window;
1753 }
1754
1755
1756 /*******************************************************************
1757  *              EnableWindow (USER32.@)
1758  */
1759 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
1760 {
1761     BOOL retvalue;
1762     HWND full_handle;
1763
1764     if (is_broadcast(hwnd))
1765     {
1766         SetLastError( ERROR_INVALID_PARAMETER );
1767         return FALSE;
1768     }
1769
1770     if (!(full_handle = WIN_IsCurrentThread( hwnd )))
1771         return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
1772
1773     hwnd = full_handle;
1774
1775     TRACE("( %p, %d )\n", hwnd, enable);
1776
1777     retvalue = !IsWindowEnabled( hwnd );
1778
1779     if (enable && retvalue)
1780     {
1781         WIN_SetStyle( hwnd, 0, WS_DISABLED );
1782         SendMessageW( hwnd, WM_ENABLE, TRUE, 0 );
1783     }
1784     else if (!enable && !retvalue)
1785     {
1786         HWND capture_wnd;
1787
1788         SendMessageW( hwnd, WM_CANCELMODE, 0, 0);
1789
1790         WIN_SetStyle( hwnd, WS_DISABLED, 0 );
1791
1792         if (hwnd == GetFocus())
1793             SetFocus( 0 );  /* A disabled window can't have the focus */
1794
1795         capture_wnd = GetCapture();
1796         if (hwnd == capture_wnd || IsChild(hwnd, capture_wnd))
1797             ReleaseCapture();  /* A disabled window can't capture the mouse */
1798
1799         SendMessageW( hwnd, WM_ENABLE, FALSE, 0 );
1800     }
1801     return retvalue;
1802 }
1803
1804
1805 /***********************************************************************
1806  *              IsWindowEnabled (USER32.@)
1807  */
1808 BOOL WINAPI IsWindowEnabled(HWND hWnd)
1809 {
1810     return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
1811 }
1812
1813
1814 /***********************************************************************
1815  *              IsWindowUnicode (USER32.@)
1816  */
1817 BOOL WINAPI IsWindowUnicode( HWND hwnd )
1818 {
1819     WND * wndPtr;
1820     BOOL retvalue = FALSE;
1821
1822     if (!(wndPtr = WIN_GetPtr(hwnd))) return FALSE;
1823
1824     if (wndPtr == WND_DESKTOP) return TRUE;
1825
1826     if (wndPtr != WND_OTHER_PROCESS)
1827     {
1828         retvalue = (wndPtr->flags & WIN_ISUNICODE) != 0;
1829         WIN_ReleasePtr( wndPtr );
1830     }
1831     else
1832     {
1833         SERVER_START_REQ( get_window_info )
1834         {
1835             req->handle = wine_server_user_handle( hwnd );
1836             if (!wine_server_call_err( req )) retvalue = reply->is_unicode;
1837         }
1838         SERVER_END_REQ;
1839     }
1840     return retvalue;
1841 }
1842
1843
1844 /**********************************************************************
1845  *           WIN_GetWindowLong
1846  *
1847  * Helper function for GetWindowLong().
1848  */
1849 static LONG_PTR WIN_GetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicode )
1850 {
1851     LONG_PTR retvalue = 0;
1852     WND *wndPtr;
1853
1854     if (offset == GWLP_HWNDPARENT)
1855     {
1856         HWND parent = GetAncestor( hwnd, GA_PARENT );
1857         if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
1858         return (ULONG_PTR)parent;
1859     }
1860
1861     if (!(wndPtr = WIN_GetPtr( hwnd )))
1862     {
1863         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1864         return 0;
1865     }
1866
1867     if (wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP)
1868     {
1869         if (offset == GWLP_WNDPROC)
1870         {
1871             SetLastError( ERROR_ACCESS_DENIED );
1872             return 0;
1873         }
1874         SERVER_START_REQ( set_window_info )
1875         {
1876             req->handle = wine_server_user_handle( hwnd );
1877             req->flags  = 0;  /* don't set anything, just retrieve */
1878             req->extra_offset = (offset >= 0) ? offset : -1;
1879             req->extra_size = (offset >= 0) ? size : 0;
1880             if (!wine_server_call_err( req ))
1881             {
1882                 switch(offset)
1883                 {
1884                 case GWL_STYLE:      retvalue = reply->old_style; break;
1885                 case GWL_EXSTYLE:    retvalue = reply->old_ex_style; break;
1886                 case GWLP_ID:        retvalue = reply->old_id; break;
1887                 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wine_server_get_ptr( reply->old_instance ); break;
1888                 case GWLP_USERDATA:  retvalue = reply->old_user_data; break;
1889                 default:
1890                     if (offset >= 0) retvalue = get_win_data( &reply->old_extra_value, size );
1891                     else SetLastError( ERROR_INVALID_INDEX );
1892                     break;
1893                 }
1894             }
1895         }
1896         SERVER_END_REQ;
1897         return retvalue;
1898     }
1899
1900     /* now we have a valid wndPtr */
1901
1902     if (offset >= 0)
1903     {
1904         if (offset > (int)(wndPtr->cbWndExtra - size))
1905         {
1906             WARN("Invalid offset %d\n", offset );
1907             WIN_ReleasePtr( wndPtr );
1908             SetLastError( ERROR_INVALID_INDEX );
1909             return 0;
1910         }
1911         retvalue = get_win_data( (char *)wndPtr->wExtra + offset, size );
1912
1913         /* Special case for dialog window procedure */
1914         if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && (wndPtr->flags & WIN_ISDIALOG))
1915             retvalue = (LONG_PTR)WINPROC_GetProc( (WNDPROC)retvalue, unicode );
1916         WIN_ReleasePtr( wndPtr );
1917         return retvalue;
1918     }
1919
1920     switch(offset)
1921     {
1922     case GWLP_USERDATA:  retvalue = wndPtr->userdata; break;
1923     case GWL_STYLE:      retvalue = wndPtr->dwStyle; break;
1924     case GWL_EXSTYLE:    retvalue = wndPtr->dwExStyle; break;
1925     case GWLP_ID:        retvalue = wndPtr->wIDmenu; break;
1926     case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hInstance; break;
1927     case GWLP_WNDPROC:
1928         /* This looks like a hack only for the edit control (see tests). This makes these controls
1929          * more tolerant to A/W mismatches. The lack of W->A->W conversion for such a mismatch suggests
1930          * that the hack is in GetWindowLongPtr[AW], not in winprocs.
1931          */
1932         if (wndPtr->winproc == EDIT_winproc_handle && (!unicode != !(wndPtr->flags & WIN_ISUNICODE)))
1933             retvalue = (ULONG_PTR)wndPtr->winproc;
1934         else
1935             retvalue = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, unicode );
1936         break;
1937     default:
1938         WARN("Unknown offset %d\n", offset );
1939         SetLastError( ERROR_INVALID_INDEX );
1940         break;
1941     }
1942     WIN_ReleasePtr(wndPtr);
1943     return retvalue;
1944 }
1945
1946
1947 /**********************************************************************
1948  *           WIN_SetWindowLong
1949  *
1950  * Helper function for SetWindowLong().
1951  *
1952  * 0 is the failure code. However, in the case of failure SetLastError
1953  * must be set to distinguish between a 0 return value and a failure.
1954  */
1955 LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, UINT size, LONG_PTR newval, BOOL unicode )
1956 {
1957     STYLESTRUCT style;
1958     BOOL ok;
1959     LONG_PTR retval = 0;
1960     WND *wndPtr;
1961
1962     TRACE( "%p %d %lx %c\n", hwnd, offset, newval, unicode ? 'W' : 'A' );
1963
1964     if (is_broadcast(hwnd))
1965     {
1966         SetLastError( ERROR_INVALID_PARAMETER );
1967         return FALSE;
1968     }
1969
1970     if (!(wndPtr = WIN_GetPtr( hwnd )))
1971     {
1972         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1973         return 0;
1974     }
1975     if (wndPtr == WND_DESKTOP)
1976     {
1977         /* can't change anything on the desktop window */
1978         SetLastError( ERROR_ACCESS_DENIED );
1979         return 0;
1980     }
1981     if (wndPtr == WND_OTHER_PROCESS)
1982     {
1983         if (offset == GWLP_WNDPROC)
1984         {
1985             SetLastError( ERROR_ACCESS_DENIED );
1986             return 0;
1987         }
1988         if (offset > 32767 || offset < -32767)
1989         {
1990             SetLastError( ERROR_INVALID_INDEX );
1991             return 0;
1992         }
1993         return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, MAKEWPARAM( offset, size ), newval );
1994     }
1995
1996     /* first some special cases */
1997     switch( offset )
1998     {
1999     case GWL_STYLE:
2000     case GWL_EXSTYLE:
2001         style.styleOld =
2002             offset == GWL_STYLE ? wndPtr->dwStyle : wndPtr->dwExStyle;
2003         style.styleNew = newval;
2004         WIN_ReleasePtr( wndPtr );
2005         SendMessageW( hwnd, WM_STYLECHANGING, offset, (LPARAM)&style );
2006         if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2007         newval = style.styleNew;
2008         break;
2009     case GWLP_HWNDPARENT:
2010         if (wndPtr->parent == GetDesktopWindow())
2011         {
2012             WIN_ReleasePtr( wndPtr );
2013             return (ULONG_PTR)WIN_SetOwner( hwnd, (HWND)newval );
2014         }
2015         else
2016         {
2017             WIN_ReleasePtr( wndPtr );
2018             return (ULONG_PTR)SetParent( hwnd, (HWND)newval );
2019         }
2020     case GWLP_WNDPROC:
2021     {
2022         WNDPROC proc;
2023         UINT old_flags = wndPtr->flags;
2024         retval = WIN_GetWindowLong( hwnd, offset, size, unicode );
2025         if (unicode) proc = WINPROC_AllocProc( NULL, (WNDPROC)newval );
2026         else proc = WINPROC_AllocProc( (WNDPROC)newval, NULL );
2027         if (proc) wndPtr->winproc = proc;
2028         if (WINPROC_IsUnicode( proc, unicode )) wndPtr->flags |= WIN_ISUNICODE;
2029         else wndPtr->flags &= ~WIN_ISUNICODE;
2030         if (!((old_flags ^ wndPtr->flags) & WIN_ISUNICODE))
2031         {
2032             WIN_ReleasePtr( wndPtr );
2033             return retval;
2034         }
2035         /* update is_unicode flag on the server side */
2036         break;
2037     }
2038     case GWLP_ID:
2039     case GWLP_HINSTANCE:
2040     case GWLP_USERDATA:
2041         break;
2042     case DWLP_DLGPROC:
2043         if ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
2044             (size == sizeof(LONG_PTR)) && (wndPtr->flags & WIN_ISDIALOG))
2045         {
2046             WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWLP_DLGPROC);
2047             retval = (ULONG_PTR)WINPROC_GetProc( *ptr, unicode );
2048             if (unicode) *ptr = WINPROC_AllocProc( NULL, (WNDPROC)newval );
2049             else *ptr = WINPROC_AllocProc( (WNDPROC)newval, NULL );
2050             WIN_ReleasePtr( wndPtr );
2051             return retval;
2052         }
2053         /* fall through */
2054     default:
2055         if (offset < 0 || offset > (int)(wndPtr->cbWndExtra - size))
2056         {
2057             WARN("Invalid offset %d\n", offset );
2058             WIN_ReleasePtr( wndPtr );
2059             SetLastError( ERROR_INVALID_INDEX );
2060             return 0;
2061         }
2062         else if (get_win_data( (char *)wndPtr->wExtra + offset, size ) == newval)
2063         {
2064             /* already set to the same value */
2065             WIN_ReleasePtr( wndPtr );
2066             return newval;
2067         }
2068         break;
2069     }
2070
2071     SERVER_START_REQ( set_window_info )
2072     {
2073         req->handle = wine_server_user_handle( hwnd );
2074         req->extra_offset = -1;
2075         switch(offset)
2076         {
2077         case GWL_STYLE:
2078             req->flags = SET_WIN_STYLE;
2079             req->style = newval;
2080             break;
2081         case GWL_EXSTYLE:
2082             req->flags = SET_WIN_EXSTYLE;
2083             /* WS_EX_TOPMOST can only be changed through SetWindowPos */
2084             newval = (newval & ~WS_EX_TOPMOST) | (wndPtr->dwExStyle & WS_EX_TOPMOST);
2085             req->ex_style = newval;
2086             break;
2087         case GWLP_ID:
2088             req->flags = SET_WIN_ID;
2089             req->id = newval;
2090             break;
2091         case GWLP_HINSTANCE:
2092             req->flags = SET_WIN_INSTANCE;
2093             req->instance = wine_server_client_ptr( (void *)newval );
2094             break;
2095         case GWLP_WNDPROC:
2096             req->flags = SET_WIN_UNICODE;
2097             req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
2098             break;
2099         case GWLP_USERDATA:
2100             req->flags = SET_WIN_USERDATA;
2101             req->user_data = newval;
2102             break;
2103         default:
2104             req->flags = SET_WIN_EXTRA;
2105             req->extra_offset = offset;
2106             req->extra_size = size;
2107             set_win_data( &req->extra_value, newval, size );
2108         }
2109         if ((ok = !wine_server_call_err( req )))
2110         {
2111             switch(offset)
2112             {
2113             case GWL_STYLE:
2114                 wndPtr->dwStyle = newval;
2115                 retval = reply->old_style;
2116                 break;
2117             case GWL_EXSTYLE:
2118                 wndPtr->dwExStyle = newval;
2119                 retval = reply->old_ex_style;
2120                 break;
2121             case GWLP_ID:
2122                 wndPtr->wIDmenu = newval;
2123                 retval = reply->old_id;
2124                 break;
2125             case GWLP_HINSTANCE:
2126                 wndPtr->hInstance = (HINSTANCE)newval;
2127                 retval = (ULONG_PTR)wine_server_get_ptr( reply->old_instance );
2128                 break;
2129             case GWLP_WNDPROC:
2130                 break;
2131             case GWLP_USERDATA:
2132                 wndPtr->userdata = newval;
2133                 retval = reply->old_user_data;
2134                 break;
2135             default:
2136                 retval = get_win_data( (char *)wndPtr->wExtra + offset, size );
2137                 set_win_data( (char *)wndPtr->wExtra + offset, newval, size );
2138                 break;
2139             }
2140         }
2141     }
2142     SERVER_END_REQ;
2143     WIN_ReleasePtr( wndPtr );
2144
2145     if (!ok) return 0;
2146
2147     if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2148     {
2149         USER_Driver->pSetWindowStyle( hwnd, offset, &style );
2150         SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2151     }
2152
2153     return retval;
2154 }
2155
2156
2157 /**********************************************************************
2158  *              GetWindowLong (USER.135)
2159  */
2160 LONG WINAPI GetWindowLong16( HWND16 hwnd, INT16 offset )
2161 {
2162     WND *wndPtr;
2163     LONG_PTR retvalue;
2164     BOOL is_winproc = (offset == GWLP_WNDPROC);
2165
2166     if (offset >= 0)
2167     {
2168         if (!(wndPtr = WIN_GetPtr( WIN_Handle32(hwnd) )))
2169         {
2170             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2171             return 0;
2172         }
2173         if (wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
2174         {
2175             if (offset > (int)(wndPtr->cbWndExtra - sizeof(LONG)))
2176             {
2177                 /*
2178                  * Some programs try to access last element from 16 bit
2179                  * code using illegal offset value. Hopefully this is
2180                  * what those programs really expect.
2181                  */
2182                 if (wndPtr->cbWndExtra >= 4 && offset == wndPtr->cbWndExtra - sizeof(WORD))
2183                 {
2184                     INT offset2 = wndPtr->cbWndExtra - sizeof(LONG);
2185                     ERR( "- replaced invalid offset %d with %d\n", offset, offset2 );
2186                     offset = offset2;
2187                 }
2188                 else
2189                 {
2190                     WARN("Invalid offset %d\n", offset );
2191                     WIN_ReleasePtr( wndPtr );
2192                     SetLastError( ERROR_INVALID_INDEX );
2193                     return 0;
2194                 }
2195             }
2196             is_winproc = ((offset == DWLP_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG));
2197             WIN_ReleasePtr( wndPtr );
2198         }
2199     }
2200     retvalue = GetWindowLongA( WIN_Handle32(hwnd), offset );
2201     if (is_winproc) retvalue = (LONG_PTR)WINPROC_GetProc16( (WNDPROC)retvalue, FALSE );
2202     return retvalue;
2203 }
2204
2205
2206 /**********************************************************************
2207  *              GetWindowWord (USER32.@)
2208  */
2209 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
2210 {
2211     switch(offset)
2212     {
2213     case GWLP_ID:
2214     case GWLP_HINSTANCE:
2215     case GWLP_HWNDPARENT:
2216         break;
2217     default:
2218         if (offset < 0)
2219         {
2220             WARN("Invalid offset %d\n", offset );
2221             SetLastError( ERROR_INVALID_INDEX );
2222             return 0;
2223         }
2224         break;
2225     }
2226     return WIN_GetWindowLong( hwnd, offset, sizeof(WORD), FALSE );
2227 }
2228
2229
2230 /**********************************************************************
2231  *              GetWindowLongA (USER32.@)
2232  */
2233 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2234 {
2235     return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), FALSE );
2236 }
2237
2238
2239 /**********************************************************************
2240  *              GetWindowLongW (USER32.@)
2241  */
2242 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2243 {
2244     return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), TRUE );
2245 }
2246
2247
2248 /**********************************************************************
2249  *              SetWindowLong (USER.136)
2250  */
2251 LONG WINAPI SetWindowLong16( HWND16 hwnd, INT16 offset, LONG newval )
2252 {
2253     WND *wndPtr;
2254     BOOL is_winproc = (offset == GWLP_WNDPROC);
2255
2256     if (offset == DWLP_DLGPROC)
2257     {
2258         if (!(wndPtr = WIN_GetPtr( WIN_Handle32(hwnd) )))
2259         {
2260             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2261             return 0;
2262         }
2263         if (wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
2264         {
2265             is_winproc = ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
2266                           (wndPtr->flags & WIN_ISDIALOG));
2267             WIN_ReleasePtr( wndPtr );
2268         }
2269     }
2270
2271     if (is_winproc)
2272     {
2273         WNDPROC new_proc = WINPROC_AllocProc16( (WNDPROC16)newval );
2274         WNDPROC old_proc = (WNDPROC)SetWindowLongPtrA( WIN_Handle32(hwnd), offset, (LONG_PTR)new_proc );
2275         return (LONG)WINPROC_GetProc16( old_proc, FALSE );
2276     }
2277     else return SetWindowLongA( WIN_Handle32(hwnd), offset, newval );
2278 }
2279
2280
2281 /**********************************************************************
2282  *              SetWindowWord (USER32.@)
2283  */
2284 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
2285 {
2286     switch(offset)
2287     {
2288     case GWLP_ID:
2289     case GWLP_HINSTANCE:
2290     case GWLP_HWNDPARENT:
2291         break;
2292     default:
2293         if (offset < 0)
2294         {
2295             WARN("Invalid offset %d\n", offset );
2296             SetLastError( ERROR_INVALID_INDEX );
2297             return 0;
2298         }
2299         break;
2300     }
2301     return WIN_SetWindowLong( hwnd, offset, sizeof(WORD), newval, FALSE );
2302 }
2303
2304
2305 /**********************************************************************
2306  *              SetWindowLongA (USER32.@)
2307  *
2308  * See SetWindowLongW.
2309  */
2310 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2311 {
2312     return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, FALSE );
2313 }
2314
2315
2316 /**********************************************************************
2317  *              SetWindowLongW (USER32.@) Set window attribute
2318  *
2319  * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2320  * value in a window's extra memory.
2321  *
2322  * The _hwnd_ parameter specifies the window.  is the handle to a
2323  * window that has extra memory. The _newval_ parameter contains the
2324  * new attribute or extra memory value.  If positive, the _offset_
2325  * parameter is the byte-addressed location in the window's extra
2326  * memory to set.  If negative, _offset_ specifies the window
2327  * attribute to set, and should be one of the following values:
2328  *
2329  * GWL_EXSTYLE      The window's extended window style
2330  *
2331  * GWL_STYLE        The window's window style.
2332  *
2333  * GWLP_WNDPROC     Pointer to the window's window procedure.
2334  *
2335  * GWLP_HINSTANCE   The window's pplication instance handle.
2336  *
2337  * GWLP_ID          The window's identifier.
2338  *
2339  * GWLP_USERDATA    The window's user-specified data.
2340  *
2341  * If the window is a dialog box, the _offset_ parameter can be one of
2342  * the following values:
2343  *
2344  * DWLP_DLGPROC     The address of the window's dialog box procedure.
2345  *
2346  * DWLP_MSGRESULT   The return value of a message
2347  *                  that the dialog box procedure processed.
2348  *
2349  * DWLP_USER        Application specific information.
2350  *
2351  * RETURNS
2352  *
2353  * If successful, returns the previous value located at _offset_. Otherwise,
2354  * returns 0.
2355  *
2356  * NOTES
2357  *
2358  * Extra memory for a window class is specified by a nonzero cbWndExtra
2359  * parameter of the WNDCLASS structure passed to RegisterClass() at the
2360  * time of class creation.
2361  *
2362  * Using GWL_WNDPROC to set a new window procedure effectively creates
2363  * a window subclass. Use CallWindowProc() in the new windows procedure
2364  * to pass messages to the superclass's window procedure.
2365  *
2366  * The user data is reserved for use by the application which created
2367  * the window.
2368  *
2369  * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2370  * instead, call the EnableWindow() function to change the window's
2371  * disabled state.
2372  *
2373  * Do not use GWL_HWNDPARENT to reset the window's parent, use
2374  * SetParent() instead.
2375  *
2376  * Win95:
2377  * When offset is GWL_STYLE and the calling app's ver is 4.0,
2378  * it sends WM_STYLECHANGING before changing the settings
2379  * and WM_STYLECHANGED afterwards.
2380  * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2381  */
2382 LONG WINAPI SetWindowLongW(
2383     HWND hwnd,  /* [in] window to alter */
2384     INT offset, /* [in] offset, in bytes, of location to alter */
2385     LONG newval /* [in] new value of location */
2386 ) {
2387     return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, TRUE );
2388 }
2389
2390
2391 /*******************************************************************
2392  *              GetWindowTextA (USER32.@)
2393  */
2394 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2395 {
2396     WCHAR *buffer;
2397
2398     if (!lpString) return 0;
2399
2400     if (WIN_IsCurrentProcess( hwnd ))
2401         return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2402
2403     /* when window belongs to other process, don't send a message */
2404     if (nMaxCount <= 0) return 0;
2405     if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2406     get_server_window_text( hwnd, buffer, nMaxCount );
2407     if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2408         lpString[nMaxCount-1] = 0;
2409     HeapFree( GetProcessHeap(), 0, buffer );
2410     return strlen(lpString);
2411 }
2412
2413
2414 /*******************************************************************
2415  *              InternalGetWindowText (USER32.@)
2416  */
2417 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2418 {
2419     WND *win;
2420
2421     if (nMaxCount <= 0) return 0;
2422     if (!(win = WIN_GetPtr( hwnd ))) return 0;
2423     if (win == WND_DESKTOP) lpString[0] = 0;
2424     else if (win != WND_OTHER_PROCESS)
2425     {
2426         if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2427         else lpString[0] = 0;
2428         WIN_ReleasePtr( win );
2429     }
2430     else
2431     {
2432         get_server_window_text( hwnd, lpString, nMaxCount );
2433     }
2434     return strlenW(lpString);
2435 }
2436
2437
2438 /*******************************************************************
2439  *              GetWindowTextW (USER32.@)
2440  */
2441 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2442 {
2443     if (!lpString) return 0;
2444
2445     if (WIN_IsCurrentProcess( hwnd ))
2446         return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2447
2448     /* when window belongs to other process, don't send a message */
2449     if (nMaxCount <= 0) return 0;
2450     get_server_window_text( hwnd, lpString, nMaxCount );
2451     return strlenW(lpString);
2452 }
2453
2454
2455 /*******************************************************************
2456  *              SetWindowTextA (USER32.@)
2457  *              SetWindowText  (USER32.@)
2458  */
2459 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2460 {
2461     if (is_broadcast(hwnd))
2462     {
2463         SetLastError( ERROR_INVALID_PARAMETER );
2464         return FALSE;
2465     }
2466     if (!WIN_IsCurrentProcess( hwnd ))
2467         WARN( "setting text %s of other process window %p should not use SendMessage\n",
2468                debugstr_a(lpString), hwnd );
2469     return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2470 }
2471
2472
2473 /*******************************************************************
2474  *              SetWindowTextW (USER32.@)
2475  */
2476 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2477 {
2478     if (is_broadcast(hwnd))
2479     {
2480         SetLastError( ERROR_INVALID_PARAMETER );
2481         return FALSE;
2482     }
2483     if (!WIN_IsCurrentProcess( hwnd ))
2484         WARN( "setting text %s of other process window %p should not use SendMessage\n",
2485                debugstr_w(lpString), hwnd );
2486     return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2487 }
2488
2489
2490 /*******************************************************************
2491  *              GetWindowTextLengthA (USER32.@)
2492  */
2493 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2494 {
2495     return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2496 }
2497
2498 /*******************************************************************
2499  *              GetWindowTextLengthW (USER32.@)
2500  */
2501 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2502 {
2503     return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2504 }
2505
2506
2507 /*******************************************************************
2508  *              IsWindow (USER32.@)
2509  */
2510 BOOL WINAPI IsWindow( HWND hwnd )
2511 {
2512     WND *ptr;
2513     BOOL ret;
2514
2515     if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2516     if (ptr == WND_DESKTOP) return TRUE;
2517
2518     if (ptr != WND_OTHER_PROCESS)
2519     {
2520         WIN_ReleasePtr( ptr );
2521         return TRUE;
2522     }
2523
2524     /* check other processes */
2525     SERVER_START_REQ( get_window_info )
2526     {
2527         req->handle = wine_server_user_handle( hwnd );
2528         ret = !wine_server_call_err( req );
2529     }
2530     SERVER_END_REQ;
2531     return ret;
2532 }
2533
2534
2535 /***********************************************************************
2536  *              GetWindowThreadProcessId (USER32.@)
2537  */
2538 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2539 {
2540     WND *ptr;
2541     DWORD tid = 0;
2542
2543     if (!(ptr = WIN_GetPtr( hwnd )))
2544     {
2545         SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2546         return 0;
2547     }
2548
2549     if (ptr != WND_OTHER_PROCESS && ptr != WND_DESKTOP)
2550     {
2551         /* got a valid window */
2552         tid = ptr->tid;
2553         if (process) *process = GetCurrentProcessId();
2554         WIN_ReleasePtr( ptr );
2555         return tid;
2556     }
2557
2558     /* check other processes */
2559     SERVER_START_REQ( get_window_info )
2560     {
2561         req->handle = wine_server_user_handle( hwnd );
2562         if (!wine_server_call_err( req ))
2563         {
2564             tid = (DWORD)reply->tid;
2565             if (process) *process = (DWORD)reply->pid;
2566         }
2567     }
2568     SERVER_END_REQ;
2569     return tid;
2570 }
2571
2572
2573 /*****************************************************************
2574  *              GetParent (USER32.@)
2575  */
2576 HWND WINAPI GetParent( HWND hwnd )
2577 {
2578     WND *wndPtr;
2579     HWND retvalue = 0;
2580
2581     if (!(wndPtr = WIN_GetPtr( hwnd )))
2582     {
2583         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2584         return 0;
2585     }
2586     if (wndPtr == WND_DESKTOP) return 0;
2587     if (wndPtr == WND_OTHER_PROCESS)
2588     {
2589         LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2590         if (style & (WS_POPUP | WS_CHILD))
2591         {
2592             SERVER_START_REQ( get_window_tree )
2593             {
2594                 req->handle = wine_server_user_handle( hwnd );
2595                 if (!wine_server_call_err( req ))
2596                 {
2597                     if (style & WS_POPUP) retvalue = wine_server_ptr_handle( reply->owner );
2598                     else if (style & WS_CHILD) retvalue = wine_server_ptr_handle( reply->parent );
2599                 }
2600             }
2601             SERVER_END_REQ;
2602         }
2603     }
2604     else
2605     {
2606         if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2607         else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2608         WIN_ReleasePtr( wndPtr );
2609     }
2610     return retvalue;
2611 }
2612
2613
2614 /*****************************************************************
2615  *              GetAncestor (USER32.@)
2616  */
2617 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2618 {
2619     WND *win;
2620     HWND *list, ret = 0;
2621
2622     switch(type)
2623     {
2624     case GA_PARENT:
2625         if (!(win = WIN_GetPtr( hwnd )))
2626         {
2627             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2628             return 0;
2629         }
2630         if (win == WND_DESKTOP) return 0;
2631         if (win != WND_OTHER_PROCESS)
2632         {
2633             ret = win->parent;
2634             WIN_ReleasePtr( win );
2635         }
2636         else /* need to query the server */
2637         {
2638             SERVER_START_REQ( get_window_tree )
2639             {
2640                 req->handle = wine_server_user_handle( hwnd );
2641                 if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->parent );
2642             }
2643             SERVER_END_REQ;
2644         }
2645         break;
2646
2647     case GA_ROOT:
2648         if (!(list = list_window_parents( hwnd ))) return 0;
2649
2650         if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd );  /* top-level window */
2651         else
2652         {
2653             int count = 2;
2654             while (list[count]) count++;
2655             ret = list[count - 2];  /* get the one before the desktop */
2656         }
2657         HeapFree( GetProcessHeap(), 0, list );
2658         break;
2659
2660     case GA_ROOTOWNER:
2661         if (is_desktop_window( hwnd )) return 0;
2662         ret = WIN_GetFullHandle( hwnd );
2663         for (;;)
2664         {
2665             HWND parent = GetParent( ret );
2666             if (!parent) break;
2667             ret = parent;
2668         }
2669         break;
2670     }
2671     return ret;
2672 }
2673
2674
2675 /*****************************************************************
2676  *              SetParent (USER32.@)
2677  */
2678 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2679 {
2680     HWND full_handle;
2681     HWND old_parent = 0;
2682     BOOL was_visible;
2683     WND *wndPtr;
2684     BOOL ret;
2685
2686     if (is_broadcast(hwnd) || is_broadcast(parent))
2687     {
2688         SetLastError(ERROR_INVALID_PARAMETER);
2689         return 0;
2690     }
2691
2692     if (!parent) parent = GetDesktopWindow();
2693     else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
2694     else parent = WIN_GetFullHandle( parent );
2695
2696     if (!IsWindow( parent ))
2697     {
2698         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2699         return 0;
2700     }
2701
2702     /* Some applications try to set a child as a parent */
2703     if (IsChild(hwnd, parent))
2704     {
2705         SetLastError( ERROR_INVALID_PARAMETER );
2706         return 0;
2707     }
2708
2709     if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2710         return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2711
2712     /* Windows hides the window first, then shows it again
2713      * including the WM_SHOWWINDOW messages and all */
2714     was_visible = ShowWindow( hwnd, SW_HIDE );
2715
2716     wndPtr = WIN_GetPtr( hwnd );
2717     if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
2718
2719     SERVER_START_REQ( set_parent )
2720     {
2721         req->handle = wine_server_user_handle( hwnd );
2722         req->parent = wine_server_user_handle( parent );
2723         if ((ret = !wine_server_call( req )))
2724         {
2725             old_parent = wine_server_ptr_handle( reply->old_parent );
2726             wndPtr->parent = parent = wine_server_ptr_handle( reply->full_parent );
2727         }
2728
2729     }
2730     SERVER_END_REQ;
2731     WIN_ReleasePtr( wndPtr );
2732     if (!ret) return 0;
2733
2734     USER_Driver->pSetParent( full_handle, parent, old_parent );
2735
2736     /* SetParent additionally needs to make hwnd the topmost window
2737        in the x-order and send the expected WM_WINDOWPOSCHANGING and
2738        WM_WINDOWPOSCHANGED notification messages.
2739     */
2740     SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0,
2741                   SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | (was_visible ? SWP_SHOWWINDOW : 0) );
2742     /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
2743      * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
2744
2745     return old_parent;
2746 }
2747
2748
2749 /*******************************************************************
2750  *              IsChild (USER32.@)
2751  */
2752 BOOL WINAPI IsChild( HWND parent, HWND child )
2753 {
2754     HWND *list = list_window_parents( child );
2755     int i;
2756     BOOL ret;
2757
2758     if (!list) return FALSE;
2759     parent = WIN_GetFullHandle( parent );
2760     for (i = 0; list[i]; i++) if (list[i] == parent) break;
2761     ret = list[i] && list[i+1];
2762     HeapFree( GetProcessHeap(), 0, list );
2763     return ret;
2764 }
2765
2766
2767 /***********************************************************************
2768  *              IsWindowVisible (USER32.@)
2769  */
2770 BOOL WINAPI IsWindowVisible( HWND hwnd )
2771 {
2772     HWND *list;
2773     BOOL retval = TRUE;
2774     int i;
2775
2776     if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2777     if (!(list = list_window_parents( hwnd ))) return TRUE;
2778     if (list[0])
2779     {
2780         for (i = 0; list[i+1]; i++)
2781             if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2782         retval = !list[i+1] && (list[i] == GetDesktopWindow());  /* top message window isn't visible */
2783     }
2784     HeapFree( GetProcessHeap(), 0, list );
2785     return retval;
2786 }
2787
2788
2789 /***********************************************************************
2790  *           WIN_IsWindowDrawable
2791  *
2792  * hwnd is drawable when it is visible, all parents are not
2793  * minimized, and it is itself not minimized unless we are
2794  * trying to draw its default class icon.
2795  */
2796 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2797 {
2798     HWND *list;
2799     BOOL retval = TRUE;
2800     int i;
2801     LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2802
2803     if (!(style & WS_VISIBLE)) return FALSE;
2804     if ((style & WS_MINIMIZE) && icon && GetClassLongPtrW( hwnd, GCLP_HICON ))  return FALSE;
2805
2806     if (!(list = list_window_parents( hwnd ))) return TRUE;
2807     if (list[0])
2808     {
2809         for (i = 0; list[i+1]; i++)
2810             if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2811                 break;
2812         retval = !list[i+1] && (list[i] == GetDesktopWindow());  /* top message window isn't visible */
2813     }
2814     HeapFree( GetProcessHeap(), 0, list );
2815     return retval;
2816 }
2817
2818
2819 /*******************************************************************
2820  *              GetTopWindow (USER32.@)
2821  */
2822 HWND WINAPI GetTopWindow( HWND hwnd )
2823 {
2824     if (!hwnd) hwnd = GetDesktopWindow();
2825     return GetWindow( hwnd, GW_CHILD );
2826 }
2827
2828
2829 /*******************************************************************
2830  *              GetWindow (USER32.@)
2831  */
2832 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2833 {
2834     HWND retval = 0;
2835
2836     if (rel == GW_OWNER)  /* this one may be available locally */
2837     {
2838         WND *wndPtr = WIN_GetPtr( hwnd );
2839         if (!wndPtr)
2840         {
2841             SetLastError( ERROR_INVALID_HANDLE );
2842             return 0;
2843         }
2844         if (wndPtr == WND_DESKTOP) return 0;
2845         if (wndPtr != WND_OTHER_PROCESS)
2846         {
2847             retval = wndPtr->owner;
2848             WIN_ReleasePtr( wndPtr );
2849             return retval;
2850         }
2851         /* else fall through to server call */
2852     }
2853
2854     SERVER_START_REQ( get_window_tree )
2855     {
2856         req->handle = wine_server_user_handle( hwnd );
2857         if (!wine_server_call_err( req ))
2858         {
2859             switch(rel)
2860             {
2861             case GW_HWNDFIRST:
2862                 retval = wine_server_ptr_handle( reply->first_sibling );
2863                 break;
2864             case GW_HWNDLAST:
2865                 retval = wine_server_ptr_handle( reply->last_sibling );
2866                 break;
2867             case GW_HWNDNEXT:
2868                 retval = wine_server_ptr_handle( reply->next_sibling );
2869                 break;
2870             case GW_HWNDPREV:
2871                 retval = wine_server_ptr_handle( reply->prev_sibling );
2872                 break;
2873             case GW_OWNER:
2874                 retval = wine_server_ptr_handle( reply->owner );
2875                 break;
2876             case GW_CHILD:
2877                 retval = wine_server_ptr_handle( reply->first_child );
2878                 break;
2879             }
2880         }
2881     }
2882     SERVER_END_REQ;
2883     return retval;
2884 }
2885
2886
2887 /*******************************************************************
2888  *              ShowOwnedPopups (USER32.@)
2889  */
2890 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2891 {
2892     int count = 0;
2893     WND *pWnd;
2894     HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2895
2896     if (!win_array) return TRUE;
2897
2898     while (win_array[count]) count++;
2899     while (--count >= 0)
2900     {
2901         if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2902         if (!(pWnd = WIN_GetPtr( win_array[count] ))) continue;
2903         if (pWnd == WND_OTHER_PROCESS) continue;
2904         if (fShow)
2905         {
2906             if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2907             {
2908                 WIN_ReleasePtr( pWnd );
2909                 /* In Windows, ShowOwnedPopups(TRUE) generates
2910                  * WM_SHOWWINDOW messages with SW_PARENTOPENING,
2911                  * regardless of the state of the owner
2912                  */
2913                 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
2914                 continue;
2915             }
2916         }
2917         else
2918         {
2919             if (pWnd->dwStyle & WS_VISIBLE)
2920             {
2921                 WIN_ReleasePtr( pWnd );
2922                 /* In Windows, ShowOwnedPopups(FALSE) generates
2923                  * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
2924                  * regardless of the state of the owner
2925                  */
2926                 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
2927                 continue;
2928             }
2929         }
2930         WIN_ReleasePtr( pWnd );
2931     }
2932     HeapFree( GetProcessHeap(), 0, win_array );
2933     return TRUE;
2934 }
2935
2936
2937 /*******************************************************************
2938  *              GetLastActivePopup (USER32.@)
2939  */
2940 HWND WINAPI GetLastActivePopup( HWND hwnd )
2941 {
2942     HWND retval = hwnd;
2943
2944     SERVER_START_REQ( get_window_info )
2945     {
2946         req->handle = wine_server_user_handle( hwnd );
2947         if (!wine_server_call_err( req )) retval = wine_server_ptr_handle( reply->last_active );
2948     }
2949     SERVER_END_REQ;
2950     return retval;
2951 }
2952
2953
2954 /*******************************************************************
2955  *           WIN_ListChildren
2956  *
2957  * Build an array of the children of a given window. The array must be
2958  * freed with HeapFree. Returns NULL when no windows are found.
2959  */
2960 HWND *WIN_ListChildren( HWND hwnd )
2961 {
2962     if (!hwnd)
2963     {
2964         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2965         return NULL;
2966     }
2967     return list_window_children( 0, hwnd, NULL, 0 );
2968 }
2969
2970
2971 /*******************************************************************
2972  *              EnumWindows (USER32.@)
2973  */
2974 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
2975 {
2976     HWND *list;
2977     BOOL ret = TRUE;
2978     int i;
2979
2980     USER_CheckNotLock();
2981
2982     /* We have to build a list of all windows first, to avoid */
2983     /* unpleasant side-effects, for instance if the callback */
2984     /* function changes the Z-order of the windows.          */
2985
2986     if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
2987
2988     /* Now call the callback function for every window */
2989
2990     for (i = 0; list[i]; i++)
2991     {
2992         /* Make sure that the window still exists */
2993         if (!IsWindow( list[i] )) continue;
2994         if (!(ret = lpEnumFunc( list[i], lParam ))) break;
2995     }
2996     HeapFree( GetProcessHeap(), 0, list );
2997     return ret;
2998 }
2999
3000
3001 /**********************************************************************
3002  *              EnumThreadWindows (USER32.@)
3003  */
3004 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
3005 {
3006     HWND *list;
3007     int i;
3008
3009     USER_CheckNotLock();
3010
3011     if (!(list = list_window_children( 0, GetDesktopWindow(), NULL, id ))) return TRUE;
3012
3013     /* Now call the callback function for every window */
3014
3015     for (i = 0; list[i]; i++)
3016         if (!func( list[i], lParam )) break;
3017     HeapFree( GetProcessHeap(), 0, list );
3018     return TRUE;
3019 }
3020
3021
3022 /***********************************************************************
3023  *              EnumDesktopWindows   (USER32.@)
3024  */
3025 BOOL WINAPI EnumDesktopWindows( HDESK desktop, WNDENUMPROC func, LPARAM lparam )
3026 {
3027     HWND *list;
3028     int i;
3029
3030     USER_CheckNotLock();
3031
3032     if (!(list = list_window_children( desktop, 0, NULL, 0 ))) return TRUE;
3033
3034     for (i = 0; list[i]; i++)
3035         if (!func( list[i], lparam )) break;
3036     HeapFree( GetProcessHeap(), 0, list );
3037     return TRUE;
3038 }
3039
3040
3041 /**********************************************************************
3042  *           WIN_EnumChildWindows
3043  *
3044  * Helper function for EnumChildWindows().
3045  */
3046 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
3047 {
3048     HWND *childList;
3049     BOOL ret = FALSE;
3050
3051     for ( ; *list; list++)
3052     {
3053         /* Make sure that the window still exists */
3054         if (!IsWindow( *list )) continue;
3055         /* Build children list first */
3056         childList = WIN_ListChildren( *list );
3057
3058         ret = func( *list, lParam );
3059
3060         if (childList)
3061         {
3062             if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
3063             HeapFree( GetProcessHeap(), 0, childList );
3064         }
3065         if (!ret) return FALSE;
3066     }
3067     return TRUE;
3068 }
3069
3070
3071 /**********************************************************************
3072  *              EnumChildWindows (USER32.@)
3073  */
3074 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
3075 {
3076     HWND *list;
3077     BOOL ret;
3078
3079     USER_CheckNotLock();
3080
3081     if (!(list = WIN_ListChildren( parent ))) return FALSE;
3082     ret = WIN_EnumChildWindows( list, func, lParam );
3083     HeapFree( GetProcessHeap(), 0, list );
3084     return ret;
3085 }
3086
3087
3088 /*******************************************************************
3089  *              AnyPopup (USER.52)
3090  */
3091 BOOL16 WINAPI AnyPopup16(void)
3092 {
3093     return AnyPopup();
3094 }
3095
3096
3097 /*******************************************************************
3098  *              AnyPopup (USER32.@)
3099  */
3100 BOOL WINAPI AnyPopup(void)
3101 {
3102     int i;
3103     BOOL retvalue;
3104     HWND *list = WIN_ListChildren( GetDesktopWindow() );
3105
3106     if (!list) return FALSE;
3107     for (i = 0; list[i]; i++)
3108     {
3109         if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
3110     }
3111     retvalue = (list[i] != 0);
3112     HeapFree( GetProcessHeap(), 0, list );
3113     return retvalue;
3114 }
3115
3116
3117 /*******************************************************************
3118  *              FlashWindow (USER32.@)
3119  */
3120 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3121 {
3122     WND *wndPtr;
3123
3124     TRACE("%p\n", hWnd);
3125
3126     if (IsIconic( hWnd ))
3127     {
3128         RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
3129
3130         wndPtr = WIN_GetPtr(hWnd);
3131         if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3132         if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
3133         {
3134             wndPtr->flags |= WIN_NCACTIVATED;
3135         }
3136         else
3137         {
3138             wndPtr->flags &= ~WIN_NCACTIVATED;
3139         }
3140         WIN_ReleasePtr( wndPtr );
3141         return TRUE;
3142     }
3143     else
3144     {
3145         WPARAM wparam;
3146
3147         wndPtr = WIN_GetPtr(hWnd);
3148         if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3149         hWnd = wndPtr->hwndSelf;  /* make it a full handle */
3150
3151         if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3152         else wparam = (hWnd == GetForegroundWindow());
3153
3154         WIN_ReleasePtr( wndPtr );
3155         SendMessageW( hWnd, WM_NCACTIVATE, wparam, 0 );
3156         return wparam;
3157     }
3158 }
3159
3160 /*******************************************************************
3161  *              FlashWindowEx (USER32.@)
3162  */
3163 BOOL WINAPI FlashWindowEx( PFLASHWINFO pfwi )
3164 {
3165     FIXME("%p\n", pfwi);
3166     return TRUE;
3167 }
3168
3169 /*******************************************************************
3170  *              GetWindowContextHelpId (USER32.@)
3171  */
3172 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3173 {
3174     DWORD retval;
3175     WND *wnd = WIN_GetPtr( hwnd );
3176     if (!wnd || wnd == WND_DESKTOP) return 0;
3177     if (wnd == WND_OTHER_PROCESS)
3178     {
3179         if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3180         return 0;
3181     }
3182     retval = wnd->helpContext;
3183     WIN_ReleasePtr( wnd );
3184     return retval;
3185 }
3186
3187
3188 /*******************************************************************
3189  *              SetWindowContextHelpId (USER32.@)
3190  */
3191 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3192 {
3193     WND *wnd = WIN_GetPtr( hwnd );
3194     if (!wnd || wnd == WND_DESKTOP) return FALSE;
3195     if (wnd == WND_OTHER_PROCESS)
3196     {
3197         if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3198         return 0;
3199     }
3200     wnd->helpContext = id;
3201     WIN_ReleasePtr( wnd );
3202     return TRUE;
3203 }
3204
3205
3206 /*******************************************************************
3207  *              DragDetect (USER32.@)
3208  */
3209 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3210 {
3211     MSG msg;
3212     RECT rect;
3213     WORD wDragWidth = GetSystemMetrics(SM_CXDRAG);
3214     WORD wDragHeight= GetSystemMetrics(SM_CYDRAG);
3215
3216     rect.left = pt.x - wDragWidth;
3217     rect.right = pt.x + wDragWidth;
3218
3219     rect.top = pt.y - wDragHeight;
3220     rect.bottom = pt.y + wDragHeight;
3221
3222     SetCapture(hWnd);
3223
3224     while(1)
3225     {
3226         while (PeekMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ))
3227         {
3228             if( msg.message == WM_LBUTTONUP )
3229             {
3230                 ReleaseCapture();
3231                 return 0;
3232             }
3233             if( msg.message == WM_MOUSEMOVE )
3234             {
3235                 POINT tmp;
3236                 tmp.x = (short)LOWORD(msg.lParam);
3237                 tmp.y = (short)HIWORD(msg.lParam);
3238                 if( !PtInRect( &rect, tmp ))
3239                 {
3240                     ReleaseCapture();
3241                     return 1;
3242                 }
3243             }
3244         }
3245         WaitMessage();
3246     }
3247     return 0;
3248 }
3249
3250 /******************************************************************************
3251  *              GetWindowModuleFileNameA (USER32.@)
3252  */
3253 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR module, UINT size )
3254 {
3255     WND *win;
3256     HINSTANCE hinst;
3257
3258     TRACE( "%p, %p, %u\n", hwnd, module, size );
3259
3260     win = WIN_GetPtr( hwnd );
3261     if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3262     {
3263         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3264         return 0;
3265     }
3266     hinst = win->hInstance;
3267     WIN_ReleasePtr( win );
3268
3269     return GetModuleFileNameA( hinst, module, size );
3270 }
3271
3272 /******************************************************************************
3273  *              GetWindowModuleFileNameW (USER32.@)
3274  */
3275 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR module, UINT size )
3276 {
3277     WND *win;
3278     HINSTANCE hinst;
3279
3280     TRACE( "%p, %p, %u\n", hwnd, module, size );
3281
3282     win = WIN_GetPtr( hwnd );
3283     if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3284     {
3285         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3286         return 0;
3287     }
3288     hinst = win->hInstance;
3289     WIN_ReleasePtr( win );
3290
3291     return GetModuleFileNameW( hinst, module, size );
3292 }
3293
3294 /******************************************************************************
3295  *              GetWindowInfo (USER32.@)
3296  *
3297  * Note: tests show that Windows doesn't check cbSize of the structure.
3298  */
3299 BOOL WINAPI GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3300 {
3301     if (!pwi) return FALSE;
3302     if (!IsWindow(hwnd)) return FALSE;
3303
3304     GetWindowRect(hwnd, &pwi->rcWindow);
3305     GetClientRect(hwnd, &pwi->rcClient);
3306     /* translate to screen coordinates */
3307     MapWindowPoints(hwnd, 0, (LPPOINT)&pwi->rcClient, 2);
3308
3309     pwi->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
3310     pwi->dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3311     pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3312
3313     pwi->cxWindowBorders = pwi->rcClient.left - pwi->rcWindow.left;
3314     pwi->cyWindowBorders = pwi->rcWindow.bottom - pwi->rcClient.bottom;
3315
3316     pwi->atomWindowType = GetClassLongW( hwnd, GCW_ATOM );
3317     pwi->wCreatorVersion = 0x0400;
3318
3319     return TRUE;
3320 }
3321
3322 /******************************************************************************
3323  *              SwitchDesktop (USER32.@)
3324  *
3325  * NOTES: Sets the current input or interactive desktop.
3326  */
3327 BOOL WINAPI SwitchDesktop( HDESK hDesktop)
3328 {
3329     FIXME("SwitchDesktop(hwnd %p) stub!\n", hDesktop);
3330     return TRUE;
3331 }
3332
3333 /*****************************************************************************
3334  *              SetLayeredWindowAttributes (USER32.@)
3335  */
3336 BOOL WINAPI SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, DWORD flags )
3337 {
3338     BOOL ret;
3339
3340     TRACE("(%p,%08x,%d,%x): stub!\n", hwnd, key, alpha, flags);
3341
3342     SERVER_START_REQ( set_window_layered_info )
3343     {
3344         req->handle = wine_server_user_handle( hwnd );
3345         req->color_key = key;
3346         req->alpha = alpha;
3347         req->flags = flags;
3348         ret = !wine_server_call_err( req );
3349     }
3350     SERVER_END_REQ;
3351
3352     if (ret) USER_Driver->pSetLayeredWindowAttributes( hwnd, key, alpha, flags );
3353
3354     return ret;
3355 }
3356
3357
3358 /*****************************************************************************
3359  *              GetLayeredWindowAttributes (USER32.@)
3360  */
3361 BOOL WINAPI GetLayeredWindowAttributes( HWND hwnd, COLORREF *key, BYTE *alpha, DWORD *flags )
3362 {
3363     BOOL ret;
3364
3365     SERVER_START_REQ( get_window_layered_info )
3366     {
3367         req->handle = wine_server_user_handle( hwnd );
3368         if ((ret = !wine_server_call_err( req )))
3369         {
3370             if (key) *key = reply->color_key;
3371             if (alpha) *alpha = reply->alpha;
3372             if (flags) *flags = reply->flags;
3373         }
3374     }
3375     SERVER_END_REQ;
3376
3377     return ret;
3378 }
3379
3380
3381 /*****************************************************************************
3382  *              UpdateLayeredWindowIndirect  (USER32.@)
3383  */
3384 BOOL WINAPI UpdateLayeredWindowIndirect( HWND hwnd, const UPDATELAYEREDWINDOWINFO *info )
3385 {
3386     BYTE alpha = 0xff;
3387
3388     if (!(info->dwFlags & ULW_EX_NORESIZE) && (info->pptDst || info->psize))
3389     {
3390         int x = 0, y = 0, cx = 0, cy = 0;
3391         DWORD flags = SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOSENDCHANGING;
3392
3393         if (info->pptDst)
3394         {
3395             x = info->pptDst->x;
3396             y = info->pptDst->y;
3397             flags &= ~SWP_NOMOVE;
3398         }
3399         if (info->psize)
3400         {
3401             cx = info->psize->cx;
3402             cy = info->psize->cy;
3403             flags &= ~SWP_NOSIZE;
3404         }
3405         TRACE( "moving window %p pos %d,%d %dx%x\n", hwnd, x, y, cx, cy );
3406         SetWindowPos( hwnd, 0, x, y, cx, cy, flags );
3407     }
3408
3409     if (info->hdcSrc)
3410     {
3411         RECT rect;
3412         HDC hdc = GetDCEx( hwnd, 0, DCX_CACHE );
3413
3414         if (hdc)
3415         {
3416             int x = 0, y = 0;
3417
3418             GetClientRect( hwnd, &rect );
3419             if (info->pptSrc)
3420             {
3421                 x = info->pptSrc->x;
3422                 y = info->pptSrc->y;
3423             }
3424             /* FIXME: intersect rect with info->prcDirty */
3425             TRACE( "copying window %p pos %d,%d\n", hwnd, x, y );
3426             BitBlt( hdc, rect.left, rect.top, rect.right, rect.bottom,
3427                     info->hdcSrc, rect.left + x, rect.top + y, SRCCOPY );
3428             ReleaseDC( hwnd, hdc );
3429         }
3430     }
3431
3432     if (info->pblend && !(info->dwFlags & ULW_OPAQUE)) alpha = info->pblend->SourceConstantAlpha;
3433     TRACE( "setting window %p alpha %u\n", hwnd, alpha );
3434     USER_Driver->pSetLayeredWindowAttributes( hwnd, info->crKey, alpha,
3435                                               info->dwFlags & (LWA_ALPHA | LWA_COLORKEY) );
3436     return TRUE;
3437 }
3438
3439
3440 /*****************************************************************************
3441  *              UpdateLayeredWindow (USER32.@)
3442  */
3443 BOOL WINAPI UpdateLayeredWindow( HWND hwnd, HDC hdcDst, POINT *pptDst, SIZE *psize,
3444                                  HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend,
3445                                  DWORD dwFlags)
3446 {
3447     UPDATELAYEREDWINDOWINFO info;
3448
3449     info.cbSize   = sizeof(info);
3450     info.hdcDst   = hdcDst;
3451     info.pptDst   = pptDst;
3452     info.psize    = psize;
3453     info.hdcSrc   = hdcSrc;
3454     info.pptSrc   = pptSrc;
3455     info.crKey    = crKey;
3456     info.pblend   = pblend;
3457     info.dwFlags  = dwFlags;
3458     info.prcDirty = NULL;
3459     return UpdateLayeredWindowIndirect( hwnd, &info );
3460 }
3461
3462 /* 64bit versions */
3463
3464 #ifdef GetWindowLongPtrW
3465 #undef GetWindowLongPtrW
3466 #endif
3467
3468 #ifdef GetWindowLongPtrA
3469 #undef GetWindowLongPtrA
3470 #endif
3471
3472 #ifdef SetWindowLongPtrW
3473 #undef SetWindowLongPtrW
3474 #endif
3475
3476 #ifdef SetWindowLongPtrA
3477 #undef SetWindowLongPtrA
3478 #endif
3479
3480 /*****************************************************************************
3481  *              GetWindowLongPtrW (USER32.@)
3482  */
3483 LONG_PTR WINAPI GetWindowLongPtrW( HWND hwnd, INT offset )
3484 {
3485     return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), TRUE );
3486 }
3487
3488 /*****************************************************************************
3489  *              GetWindowLongPtrA (USER32.@)
3490  */
3491 LONG_PTR WINAPI GetWindowLongPtrA( HWND hwnd, INT offset )
3492 {
3493     return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), FALSE );
3494 }
3495
3496 /*****************************************************************************
3497  *              SetWindowLongPtrW (USER32.@)
3498  */
3499 LONG_PTR WINAPI SetWindowLongPtrW( HWND hwnd, INT offset, LONG_PTR newval )
3500 {
3501     return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, TRUE );
3502 }
3503
3504 /*****************************************************************************
3505  *              SetWindowLongPtrA (USER32.@)
3506  */
3507 LONG_PTR WINAPI SetWindowLongPtrA( HWND hwnd, INT offset, LONG_PTR newval )
3508 {
3509     return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, FALSE );
3510 }