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