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