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