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