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