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