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