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