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