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