Map a window if it is shown by a direct style change.
[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                 retval = wndPtr->dwStyle;
1766                 style.styleOld = wndPtr->dwStyle;
1767                 style.styleNew = newval;
1768                 SendMessageA(hwnd,WM_STYLECHANGING,GWL_STYLE,(LPARAM)&style);
1769                 wndPtr->dwStyle = style.styleNew;
1770                 if (USER_Driver.pSetWindowStyle) USER_Driver.pSetWindowStyle( hwnd, retval );
1771                 SendMessageA(hwnd,WM_STYLECHANGED,GWL_STYLE,(LPARAM)&style);
1772                 retval = style.styleOld;
1773                 goto end;
1774         case GWL_EXSTYLE:
1775                 style.styleOld = wndPtr->dwExStyle;
1776                 style.styleNew = newval;
1777                 SendMessageA(hwnd,WM_STYLECHANGING,GWL_EXSTYLE,(LPARAM)&style);
1778                 wndPtr->dwExStyle = style.styleNew;
1779                 SendMessageA(hwnd,WM_STYLECHANGED,GWL_EXSTYLE,(LPARAM)&style);
1780                 retval = style.styleOld;
1781                 goto end;
1782
1783         default:
1784             WARN("Invalid offset %d\n", offset );
1785
1786             /* Don't think this is right error but it should do */
1787             SetLastError( ERROR_OUTOFMEMORY );
1788
1789             retval = 0;
1790             goto end;
1791     }
1792     retval = *ptr;
1793     *ptr = newval;
1794 end:
1795     WIN_ReleaseWndPtr(wndPtr);
1796     return retval;
1797 }
1798
1799
1800 /**********************************************************************
1801  *              GetWindowLong (USER.135)
1802  */
1803 LONG WINAPI GetWindowLong16( HWND16 hwnd, INT16 offset )
1804 {
1805     return WIN_GetWindowLong( WIN_Handle32(hwnd), offset, WIN_PROC_16 );
1806 }
1807
1808
1809 /**********************************************************************
1810  *              GetWindowLongA (USER32.@)
1811  */
1812 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
1813 {
1814     return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32A );
1815 }
1816
1817
1818 /**********************************************************************
1819  *              GetWindowLongW (USER32.@)
1820  */
1821 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
1822 {
1823     return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32W );
1824 }
1825
1826
1827 /**********************************************************************
1828  *              SetWindowLong (USER.136)
1829  */
1830 LONG WINAPI SetWindowLong16( HWND16 hwnd, INT16 offset, LONG newval )
1831 {
1832     return WIN_SetWindowLong( WIN_Handle32(hwnd), offset, newval, WIN_PROC_16 );
1833 }
1834
1835
1836 /**********************************************************************
1837  *              SetWindowLongA (USER32.@)
1838  */
1839 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
1840 {
1841     return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32A );
1842 }
1843
1844
1845 /**********************************************************************
1846  *              SetWindowLongW (USER32.@) Set window attribute
1847  *
1848  * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
1849  * value in a window's extra memory.
1850  *
1851  * The _hwnd_ parameter specifies the window.  is the handle to a
1852  * window that has extra memory. The _newval_ parameter contains the
1853  * new attribute or extra memory value.  If positive, the _offset_
1854  * parameter is the byte-addressed location in the window's extra
1855  * memory to set.  If negative, _offset_ specifies the window
1856  * attribute to set, and should be one of the following values:
1857  *
1858  * GWL_EXSTYLE      The window's extended window style
1859  *
1860  * GWL_STYLE        The window's window style.
1861  *
1862  * GWL_WNDPROC      Pointer to the window's window procedure.
1863  *
1864  * GWL_HINSTANCE    The window's pplication instance handle.
1865  *
1866  * GWL_ID           The window's identifier.
1867  *
1868  * GWL_USERDATA     The window's user-specified data.
1869  *
1870  * If the window is a dialog box, the _offset_ parameter can be one of
1871  * the following values:
1872  *
1873  * DWL_DLGPROC      The address of the window's dialog box procedure.
1874  *
1875  * DWL_MSGRESULT    The return value of a message
1876  *                  that the dialog box procedure processed.
1877  *
1878  * DWL_USER         Application specific information.
1879  *
1880  * RETURNS
1881  *
1882  * If successful, returns the previous value located at _offset_. Otherwise,
1883  * returns 0.
1884  *
1885  * NOTES
1886  *
1887  * Extra memory for a window class is specified by a nonzero cbWndExtra
1888  * parameter of the WNDCLASS structure passed to RegisterClass() at the
1889  * time of class creation.
1890  *
1891  * Using GWL_WNDPROC to set a new window procedure effectively creates
1892  * a window subclass. Use CallWindowProc() in the new windows procedure
1893  * to pass messages to the superclass's window procedure.
1894  *
1895  * The user data is reserved for use by the application which created
1896  * the window.
1897  *
1898  * Do not use GWL_STYLE to change the window's WS_DISABLE style;
1899  * instead, call the EnableWindow() function to change the window's
1900  * disabled state.
1901  *
1902  * Do not use GWL_HWNDPARENT to reset the window's parent, use
1903  * SetParent() instead.
1904  *
1905  * Win95:
1906  * When offset is GWL_STYLE and the calling app's ver is 4.0,
1907  * it sends WM_STYLECHANGING before changing the settings
1908  * and WM_STYLECHANGED afterwards.
1909  * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
1910  *
1911  * BUGS
1912  *
1913  * GWL_STYLE does not dispatch WM_STYLE... messages.
1914  *
1915  * CONFORMANCE
1916  *
1917  * ECMA-234, Win32
1918  *
1919  */
1920 LONG WINAPI SetWindowLongW(
1921     HWND hwnd,  /* [in] window to alter */
1922     INT offset, /* [in] offset, in bytes, of location to alter */
1923     LONG newval /* [in] new value of location */
1924 ) {
1925     return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32W );
1926 }
1927
1928
1929 /*******************************************************************
1930  *              GetWindowTextA (USER32.@)
1931  */
1932 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
1933 {
1934     return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount,
1935                                   (LPARAM)lpString );
1936 }
1937
1938 /*******************************************************************
1939  *              InternalGetWindowText (USER32.@)
1940  */
1941 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
1942 {
1943     WND *win = WIN_FindWndPtr( hwnd );
1944     if (!win) return 0;
1945     if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
1946     else lpString[0] = 0;
1947     WIN_ReleaseWndPtr( win );
1948     return strlenW(lpString);
1949 }
1950
1951
1952 /*******************************************************************
1953  *              GetWindowTextW (USER32.@)
1954  */
1955 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
1956 {
1957     return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount,
1958                                   (LPARAM)lpString );
1959 }
1960
1961
1962 /*******************************************************************
1963  *              SetWindowText  (USER32.@)
1964  *              SetWindowTextA (USER32.@)
1965  */
1966 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
1967 {
1968     return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
1969 }
1970
1971
1972 /*******************************************************************
1973  *              SetWindowTextW (USER32.@)
1974  */
1975 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
1976 {
1977     return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
1978 }
1979
1980
1981 /*******************************************************************
1982  *              GetWindowTextLengthA (USER32.@)
1983  */
1984 INT WINAPI GetWindowTextLengthA( HWND hwnd )
1985 {
1986     return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
1987 }
1988
1989 /*******************************************************************
1990  *              GetWindowTextLengthW (USER32.@)
1991  */
1992 INT WINAPI GetWindowTextLengthW( HWND hwnd )
1993 {
1994     return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
1995 }
1996
1997
1998 /*******************************************************************
1999  *              IsWindow (USER32.@)
2000  */
2001 BOOL WINAPI IsWindow( HWND hwnd )
2002 {
2003     WND *ptr;
2004     BOOL ret;
2005
2006     if ((ptr = get_wnd_ptr( hwnd )))
2007     {
2008         if (ptr == BAD_WND_PTR) return FALSE;
2009         USER_Unlock();
2010         return TRUE;
2011     }
2012
2013     /* check other processes */
2014     SERVER_START_REQ( get_window_info )
2015     {
2016         req->handle = hwnd;
2017         ret = !SERVER_CALL_ERR();
2018     }
2019     SERVER_END_REQ;
2020     return ret;
2021 }
2022
2023
2024 /***********************************************************************
2025  *              GetWindowThreadProcessId (USER32.@)
2026  */
2027 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2028 {
2029     WND *ptr;
2030     DWORD tid = 0;
2031
2032     if ((ptr = get_wnd_ptr( hwnd )))
2033     {
2034         if (ptr != BAD_WND_PTR)
2035         {
2036             /* got a valid window */
2037             tid = ptr->tid;
2038             if (process) *process = GetCurrentProcessId();
2039             USER_Unlock();
2040         }
2041         else SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2042         return tid;
2043     }
2044
2045     /* check other processes */
2046     SERVER_START_REQ( get_window_info )
2047     {
2048         req->handle = hwnd;
2049         if (!SERVER_CALL_ERR())
2050         {
2051             tid = (DWORD)req->tid;
2052             if (process) *process = (DWORD)req->pid;
2053         }
2054     }
2055     SERVER_END_REQ;
2056     return tid;
2057 }
2058
2059
2060 /*****************************************************************
2061  *              GetParent (USER32.@)
2062  */
2063 HWND WINAPI GetParent( HWND hwnd )
2064 {
2065     WND *wndPtr;
2066     HWND retvalue = 0;
2067
2068     if ((wndPtr = WIN_FindWndPtr(hwnd)))
2069     {
2070         if (wndPtr->dwStyle & WS_CHILD)
2071             retvalue = wndPtr->parent->hwndSelf;
2072         else if (wndPtr->dwStyle & WS_POPUP)
2073             retvalue = wndPtr->owner;
2074         WIN_ReleaseWndPtr(wndPtr);
2075     }
2076     return retvalue;
2077 }
2078
2079
2080 /*****************************************************************
2081  *              GetAncestor (USER32.@)
2082  */
2083 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2084 {
2085     HWND ret = 0;
2086     WND *wndPtr;
2087
2088     if (!(wndPtr = WIN_FindWndPtr(hwnd))) return 0;
2089     if (wndPtr->hwndSelf == GetDesktopWindow()) goto done;
2090
2091     switch(type)
2092     {
2093     case GA_PARENT:
2094         WIN_UpdateWndPtr( &wndPtr, wndPtr->parent );
2095         break;
2096     case GA_ROOT:
2097         while (wndPtr->parent->hwndSelf != GetDesktopWindow())
2098             WIN_UpdateWndPtr( &wndPtr, wndPtr->parent );
2099         break;
2100     case GA_ROOTOWNER:
2101         while (wndPtr->parent->hwndSelf != GetDesktopWindow())
2102             WIN_UpdateWndPtr( &wndPtr, wndPtr->parent );
2103         while (wndPtr && wndPtr->owner)
2104         {
2105             WND *ptr = WIN_FindWndPtr( wndPtr->owner );
2106             WIN_ReleaseWndPtr( wndPtr );
2107             wndPtr = ptr;
2108         }
2109         break;
2110     }
2111     ret = wndPtr ? wndPtr->hwndSelf : 0;
2112  done:
2113     WIN_ReleaseWndPtr( wndPtr );
2114     return ret;
2115 }
2116
2117
2118 /*****************************************************************
2119  *              SetParent (USER32.@)
2120  */
2121 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2122 {
2123     WND *wndPtr;
2124     DWORD dwStyle;
2125     HWND retvalue;
2126
2127     if (!parent) parent = GetDesktopWindow();
2128     else parent = WIN_GetFullHandle( parent );
2129
2130     /* sanity checks */
2131     if (WIN_GetFullHandle(hwnd) == GetDesktopWindow() || !IsWindow( parent ))
2132     {
2133         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2134         return 0;
2135     }
2136
2137     if (USER_Driver.pSetParent)
2138         return USER_Driver.pSetParent( hwnd, parent );
2139
2140     if (!(wndPtr = WIN_FindWndPtr(hwnd))) return 0;
2141
2142     dwStyle = wndPtr->dwStyle;
2143
2144     /* Windows hides the window first, then shows it again
2145      * including the WM_SHOWWINDOW messages and all */
2146     if (dwStyle & WS_VISIBLE) ShowWindow( hwnd, SW_HIDE );
2147
2148     retvalue = wndPtr->parent->hwndSelf;  /* old parent */
2149     if (parent != retvalue)
2150     {
2151         WIN_LinkWindow( hwnd, parent, HWND_TOP );
2152
2153         if (parent != GetDesktopWindow()) /* a child window */
2154         {
2155             if (!(dwStyle & WS_CHILD))
2156             {
2157                 HMENU menu = (HMENU)SetWindowLongW( hwnd, GWL_ID, 0 );
2158                 if (menu) DestroyMenu( menu );
2159             }
2160         }
2161     }
2162     WIN_ReleaseWndPtr( wndPtr );
2163
2164     /* SetParent additionally needs to make hwnd the topmost window
2165        in the x-order and send the expected WM_WINDOWPOSCHANGING and
2166        WM_WINDOWPOSCHANGED notification messages.
2167     */
2168     SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0,
2169                   SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|
2170                   ((dwStyle & WS_VISIBLE)?SWP_SHOWWINDOW:0));
2171     /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
2172      * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
2173     return retvalue;
2174 }
2175
2176
2177 /*******************************************************************
2178  *              IsChild (USER32.@)
2179  */
2180 BOOL WINAPI IsChild( HWND parent, HWND child )
2181 {
2182     HWND *list = WIN_ListParents( child );
2183     int i;
2184     BOOL ret;
2185
2186     if (!list) return FALSE;
2187     parent = WIN_GetFullHandle( parent );
2188     for (i = 0; list[i]; i++) if (list[i] == parent) break;
2189     ret = (list[i] != 0);
2190     HeapFree( GetProcessHeap(), 0, list );
2191     return ret;
2192 }
2193
2194
2195 /***********************************************************************
2196  *              IsWindowVisible (USER32.@)
2197  */
2198 BOOL WINAPI IsWindowVisible( HWND hwnd )
2199 {
2200     HWND *list;
2201     BOOL retval;
2202     int i;
2203
2204     if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2205     if (!(list = WIN_ListParents( hwnd ))) return TRUE;
2206     for (i = 0; list[i]; i++)
2207         if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2208     retval = !list[i];
2209     HeapFree( GetProcessHeap(), 0, list );
2210     return retval;
2211 }
2212
2213
2214 /***********************************************************************
2215  *           WIN_IsWindowDrawable
2216  *
2217  * hwnd is drawable when it is visible, all parents are not
2218  * minimized, and it is itself not minimized unless we are
2219  * trying to draw its default class icon.
2220  */
2221 BOOL WIN_IsWindowDrawable( WND* wnd, BOOL icon )
2222 {
2223     HWND *list;
2224     BOOL retval;
2225     int i;
2226
2227     if (!(wnd->dwStyle & WS_VISIBLE)) return FALSE;
2228     if ((wnd->dwStyle & WS_MINIMIZE) &&
2229         icon && GetClassLongA( wnd->hwndSelf, GCL_HICON ))  return FALSE;
2230
2231     if (!(list = WIN_ListParents( wnd->hwndSelf ))) return TRUE;
2232     for (i = 0; list[i]; i++)
2233         if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2234             break;
2235     retval = !list[i];
2236     HeapFree( GetProcessHeap(), 0, list );
2237     return retval;
2238 }
2239
2240
2241 /*******************************************************************
2242  *              GetTopWindow (USER32.@)
2243  */
2244 HWND WINAPI GetTopWindow( HWND hwnd )
2245 {
2246     if (!hwnd) hwnd = GetDesktopWindow();
2247     return GetWindow( hwnd, GW_CHILD );
2248 }
2249
2250
2251 /*******************************************************************
2252  *              GetWindow (USER32.@)
2253  */
2254 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2255 {
2256     HWND retval = 0;
2257
2258     if (rel == GW_OWNER)  /* special case: not fully supported in the server yet */
2259     {
2260         WND *wndPtr = WIN_FindWndPtr( hwnd );
2261         if (!wndPtr) return 0;
2262         retval = wndPtr->owner;
2263         WIN_ReleaseWndPtr( wndPtr );
2264         return retval;
2265     }
2266
2267     SERVER_START_REQ( get_window_tree )
2268     {
2269         req->handle = hwnd;
2270         if (!SERVER_CALL_ERR())
2271         {
2272             switch(rel)
2273             {
2274             case GW_HWNDFIRST:
2275                 retval = req->first_sibling;
2276                 break;
2277             case GW_HWNDLAST:
2278                 retval = req->last_sibling;
2279                 break;
2280             case GW_HWNDNEXT:
2281                 retval = req->next_sibling;
2282                 break;
2283             case GW_HWNDPREV:
2284                 retval = req->prev_sibling;
2285                 break;
2286             case GW_CHILD:
2287                 retval = req->first_child;
2288                 break;
2289             }
2290         }
2291     }
2292     SERVER_END_REQ;
2293     return retval;
2294 }
2295
2296
2297 /***********************************************************************
2298  *           WIN_InternalShowOwnedPopups
2299  *
2300  * Internal version of ShowOwnedPopups; Wine functions should use this
2301  * to avoid interfering with application calls to ShowOwnedPopups
2302  * and to make sure the application can't prevent showing/hiding.
2303  *
2304  * Set unmanagedOnly to TRUE to show/hide unmanaged windows only.
2305  *
2306  */
2307
2308 BOOL WIN_InternalShowOwnedPopups( HWND owner, BOOL fShow, BOOL unmanagedOnly )
2309 {
2310     int count = 0;
2311     WND *pWnd;
2312     HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2313
2314     if (!win_array) return TRUE;
2315
2316     /*
2317      * Show windows Lowest first, Highest last to preserve Z-Order
2318      */
2319     while (win_array[count]) count++;
2320     while (--count >= 0)
2321     {
2322         if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2323         if (!(pWnd = WIN_FindWndPtr( win_array[count] ))) continue;
2324
2325         if (pWnd->dwStyle & WS_POPUP)
2326         {
2327             if (fShow)
2328             {
2329                 /* check in window was flagged for showing in previous WIN_InternalShowOwnedPopups call */
2330                 if (pWnd->flags & WIN_NEEDS_INTERNALSOP)
2331                 {
2332                     /*
2333                      * Call ShowWindow directly because an application can intercept WM_SHOWWINDOW messages
2334                      */
2335                     ShowWindow(pWnd->hwndSelf,SW_SHOW);
2336                     pWnd->flags &= ~WIN_NEEDS_INTERNALSOP; /* remove the flag */
2337                 }
2338             }
2339             else
2340             {
2341                 if ( IsWindowVisible(pWnd->hwndSelf) &&                   /* hide only if window is visible */
2342                      !( pWnd->flags & WIN_NEEDS_INTERNALSOP ) &&          /* don't hide if previous call already did it */
2343                      !( unmanagedOnly && (pWnd->dwExStyle & WS_EX_MANAGED) ) ) /* don't hide managed windows if unmanagedOnly is TRUE */
2344                 {
2345                     /*
2346                      * Call ShowWindow directly because an application can intercept WM_SHOWWINDOW messages
2347                      */
2348                     ShowWindow(pWnd->hwndSelf,SW_HIDE);
2349                     /* flag the window for showing on next WIN_InternalShowOwnedPopups call */
2350                     pWnd->flags |= WIN_NEEDS_INTERNALSOP;
2351                 }
2352             }
2353         }
2354         WIN_ReleaseWndPtr( pWnd );
2355     }
2356     HeapFree( GetProcessHeap(), 0, win_array );
2357
2358     return TRUE;
2359 }
2360
2361 /*******************************************************************
2362  *              ShowOwnedPopups (USER32.@)
2363  */
2364 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2365 {
2366     int count = 0;
2367     WND *pWnd;
2368     HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2369
2370     if (!win_array) return TRUE;
2371
2372     while (win_array[count]) count++;
2373     while (--count >= 0)
2374     {
2375         if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2376         if (!(pWnd = WIN_FindWndPtr( win_array[count] ))) continue;
2377
2378         if (pWnd->dwStyle & WS_POPUP)
2379         {
2380             if (fShow)
2381             {
2382                 if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2383                 {
2384                     /* In Windows, ShowOwnedPopups(TRUE) generates
2385                      * WM_SHOWWINDOW messages with SW_PARENTOPENING,
2386                      * regardless of the state of the owner
2387                      */
2388                     SendMessageA(pWnd->hwndSelf, WM_SHOWWINDOW, SW_SHOW, SW_PARENTOPENING);
2389                     pWnd->flags &= ~WIN_NEEDS_SHOW_OWNEDPOPUP;
2390                 }
2391             }
2392             else
2393             {
2394                 if (IsWindowVisible(pWnd->hwndSelf))
2395                 {
2396                     /* In Windows, ShowOwnedPopups(FALSE) generates
2397                      * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
2398                      * regardless of the state of the owner
2399                      */
2400                     SendMessageA(pWnd->hwndSelf, WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
2401                     pWnd->flags |= WIN_NEEDS_SHOW_OWNEDPOPUP;
2402                 }
2403             }
2404         }
2405         WIN_ReleaseWndPtr( pWnd );
2406     }
2407     HeapFree( GetProcessHeap(), 0, win_array );
2408     return TRUE;
2409 }
2410
2411
2412 /*******************************************************************
2413  *              GetLastActivePopup (USER32.@)
2414  */
2415 HWND WINAPI GetLastActivePopup( HWND hwnd )
2416 {
2417     HWND retval;
2418     WND *wndPtr =WIN_FindWndPtr(hwnd);
2419     if (!wndPtr) return hwnd;
2420     retval = wndPtr->hwndLastActive;
2421     if (!IsWindow( retval )) retval = wndPtr->hwndSelf;
2422     WIN_ReleaseWndPtr(wndPtr);
2423     return retval;
2424 }
2425
2426
2427 /*******************************************************************
2428  *           WIN_ListParents
2429  *
2430  * Build an array of all parents of a given window, starting with
2431  * the immediate parent. The array must be freed with HeapFree.
2432  * Returns NULL if window is a top-level window.
2433  */
2434 HWND *WIN_ListParents( HWND hwnd )
2435 {
2436     HWND *list = NULL;
2437
2438     SERVER_START_VAR_REQ( get_window_parents, REQUEST_MAX_VAR_SIZE )
2439     {
2440         req->handle = hwnd;
2441         if (!SERVER_CALL())
2442         {
2443             user_handle_t *data = server_data_ptr(req);
2444             int i, count = server_data_size(req) / sizeof(*data);
2445             if (count && ((list = HeapAlloc( GetProcessHeap(), 0, (count + 1) * sizeof(HWND) ))))
2446             {
2447                 for (i = 0; i < count; i++) list[i] = data[i];
2448                 list[i] = 0;
2449             }
2450         }
2451     }
2452     SERVER_END_VAR_REQ;
2453     return list;
2454 }
2455
2456
2457 /*******************************************************************
2458  *           WIN_ListChildren
2459  *
2460  * Build an array of the children of a given window. The array must be
2461  * freed with HeapFree. Returns NULL when no windows are found.
2462  */
2463 HWND *WIN_ListChildren( HWND hwnd )
2464 {
2465     HWND *list = NULL;
2466
2467     SERVER_START_VAR_REQ( get_window_children, REQUEST_MAX_VAR_SIZE )
2468     {
2469         req->parent = hwnd;
2470         if (!SERVER_CALL())
2471         {
2472             user_handle_t *data = server_data_ptr(req);
2473             int i, count = server_data_size(req) / sizeof(*data);
2474             if (count && ((list = HeapAlloc( GetProcessHeap(), 0, (count + 1) * sizeof(HWND) ))))
2475             {
2476                 for (i = 0; i < count; i++) list[i] = data[i];
2477                 list[i] = 0;
2478             }
2479         }
2480     }
2481     SERVER_END_VAR_REQ;
2482     return list;
2483 }
2484
2485
2486 /*******************************************************************
2487  *              EnumWindows (USER32.@)
2488  */
2489 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
2490 {
2491     HWND *list;
2492     BOOL ret = TRUE;
2493     int i, iWndsLocks;
2494
2495     /* We have to build a list of all windows first, to avoid */
2496     /* unpleasant side-effects, for instance if the callback */
2497     /* function changes the Z-order of the windows.          */
2498
2499     if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return FALSE;
2500
2501     /* Now call the callback function for every window */
2502
2503     iWndsLocks = WIN_SuspendWndsLock();
2504     for (i = 0; list[i]; i++)
2505     {
2506         /* Make sure that the window still exists */
2507         if (!IsWindow( list[i] )) continue;
2508         if (!(ret = lpEnumFunc( list[i], lParam ))) break;
2509     }
2510     WIN_RestoreWndsLock(iWndsLocks);
2511     HeapFree( GetProcessHeap(), 0, list );
2512     return ret;
2513 }
2514
2515
2516 /**********************************************************************
2517  *              EnumTaskWindows16   (USER.225)
2518  */
2519 BOOL16 WINAPI EnumTaskWindows16( HTASK16 hTask, WNDENUMPROC16 func,
2520                                  LPARAM lParam )
2521 {
2522     TDB *tdb = TASK_GetPtr( hTask );
2523     if (!tdb) return FALSE;
2524     return EnumThreadWindows( (DWORD)tdb->teb->tid, (WNDENUMPROC)func, lParam );
2525 }
2526
2527
2528 /**********************************************************************
2529  *              EnumThreadWindows (USER32.@)
2530  */
2531 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
2532 {
2533     HWND *list;
2534     int i, iWndsLocks;
2535
2536     if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return FALSE;
2537
2538     /* Now call the callback function for every window */
2539
2540     iWndsLocks = WIN_SuspendWndsLock();
2541     for (i = 0; list[i]; i++)
2542     {
2543         if (GetWindowThreadProcessId( list[i], NULL ) != id) continue;
2544         if (!func( list[i], lParam )) break;
2545     }
2546     WIN_RestoreWndsLock(iWndsLocks);
2547     HeapFree( GetProcessHeap(), 0, list );
2548     return TRUE;
2549 }
2550
2551
2552 /**********************************************************************
2553  *           WIN_EnumChildWindows
2554  *
2555  * Helper function for EnumChildWindows().
2556  */
2557 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
2558 {
2559     HWND *childList;
2560     BOOL ret = FALSE;
2561
2562     for ( ; *list; list++)
2563     {
2564         /* Make sure that the window still exists */
2565         if (!IsWindow( *list )) continue;
2566         /* skip owned windows */
2567         if (GetWindow( *list, GW_OWNER )) continue;
2568         /* Build children list first */
2569         childList = WIN_ListChildren( *list );
2570
2571         ret = func( *list, lParam );
2572
2573         if (childList)
2574         {
2575             if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
2576             HeapFree( GetProcessHeap(), 0, childList );
2577         }
2578         if (!ret) return FALSE;
2579     }
2580     return TRUE;
2581 }
2582
2583
2584 /**********************************************************************
2585  *              EnumChildWindows (USER32.@)
2586  */
2587 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
2588 {
2589     HWND *list;
2590     int iWndsLocks;
2591
2592     if (!(list = WIN_ListChildren( parent ))) return FALSE;
2593     iWndsLocks = WIN_SuspendWndsLock();
2594     WIN_EnumChildWindows( list, func, lParam );
2595     WIN_RestoreWndsLock(iWndsLocks);
2596     HeapFree( GetProcessHeap(), 0, list );
2597     return TRUE;
2598 }
2599
2600
2601 /*******************************************************************
2602  *              AnyPopup (USER.52)
2603  */
2604 BOOL16 WINAPI AnyPopup16(void)
2605 {
2606     return AnyPopup();
2607 }
2608
2609
2610 /*******************************************************************
2611  *              AnyPopup (USER32.@)
2612  */
2613 BOOL WINAPI AnyPopup(void)
2614 {
2615     int i;
2616     BOOL retvalue;
2617     HWND *list = WIN_ListChildren( GetDesktopWindow() );
2618
2619     if (!list) return FALSE;
2620     for (i = 0; list[i]; i++)
2621     {
2622         if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
2623     }
2624     retvalue = (list[i] != 0);
2625     HeapFree( GetProcessHeap(), 0, list );
2626     return retvalue;
2627 }
2628
2629
2630 /*******************************************************************
2631  *              FlashWindow (USER32.@)
2632  */
2633 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
2634 {
2635     WND *wndPtr = WIN_FindWndPtr(hWnd);
2636
2637     TRACE("%04x\n", hWnd);
2638
2639     if (!wndPtr) return FALSE;
2640     hWnd = wndPtr->hwndSelf;  /* make it a full handle */
2641
2642     if (wndPtr->dwStyle & WS_MINIMIZE)
2643     {
2644         if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
2645         {
2646             HDC hDC = GetDC(hWnd);
2647
2648             if (!SendMessageW( hWnd, WM_ERASEBKGND, (WPARAM16)hDC, 0 ))
2649                 wndPtr->flags |= WIN_NEEDS_ERASEBKGND;
2650
2651             ReleaseDC( hWnd, hDC );
2652             wndPtr->flags |= WIN_NCACTIVATED;
2653         }
2654         else
2655         {
2656             RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
2657             wndPtr->flags &= ~WIN_NCACTIVATED;
2658         }
2659         WIN_ReleaseWndPtr(wndPtr);
2660         return TRUE;
2661     }
2662     else
2663     {
2664         WPARAM16 wparam;
2665         if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
2666         else wparam = (hWnd == GetActiveWindow());
2667
2668         WIN_ReleaseWndPtr(wndPtr);
2669         SendMessageW( hWnd, WM_NCACTIVATE, wparam, (LPARAM)0 );
2670         return wparam;
2671     }
2672 }
2673
2674
2675 /*******************************************************************
2676  *              GetWindowContextHelpId (USER32.@)
2677  */
2678 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
2679 {
2680     DWORD retval;
2681     WND *wnd = WIN_FindWndPtr( hwnd );
2682     if (!wnd) return 0;
2683     retval = wnd->helpContext;
2684     WIN_ReleaseWndPtr(wnd);
2685     return retval;
2686 }
2687
2688
2689 /*******************************************************************
2690  *              SetWindowContextHelpId (USER32.@)
2691  */
2692 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
2693 {
2694     WND *wnd = WIN_FindWndPtr( hwnd );
2695     if (!wnd) return FALSE;
2696     wnd->helpContext = id;
2697     WIN_ReleaseWndPtr(wnd);
2698     return TRUE;
2699 }
2700
2701
2702 /*******************************************************************
2703  *                      DRAG_QueryUpdate
2704  *
2705  * recursively find a child that contains spDragInfo->pt point
2706  * and send WM_QUERYDROPOBJECT
2707  */
2708 BOOL16 DRAG_QueryUpdate( HWND hQueryWnd, SEGPTR spDragInfo, BOOL bNoSend )
2709 {
2710     BOOL16 wParam, bResult = 0;
2711     POINT pt;
2712     LPDRAGINFO16 ptrDragInfo = MapSL(spDragInfo);
2713     RECT tempRect;
2714
2715     if (!ptrDragInfo) return FALSE;
2716
2717     CONV_POINT16TO32( &ptrDragInfo->pt, &pt );
2718
2719     GetWindowRect(hQueryWnd,&tempRect);
2720
2721     if( !PtInRect(&tempRect,pt) || !IsWindowEnabled(hQueryWnd)) return FALSE;
2722
2723     if (!IsIconic( hQueryWnd ))
2724     {
2725         GetClientRect( hQueryWnd, &tempRect );
2726         MapWindowPoints( hQueryWnd, 0, (LPPOINT)&tempRect, 2 );
2727
2728         if (PtInRect( &tempRect, pt))
2729         {
2730             int i;
2731             HWND *list = WIN_ListChildren( hQueryWnd );
2732
2733             wParam = 0;
2734
2735             if (list)
2736             {
2737                 for (i = 0; list[i]; i++)
2738                 {
2739                     if (GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)
2740                     {
2741                         GetWindowRect( list[i], &tempRect );
2742                         if (PtInRect( &tempRect, pt )) break;
2743                     }
2744                 }
2745                 if (list[i])
2746                 {
2747                     if (IsWindowEnabled( list[i] ))
2748                         bResult = DRAG_QueryUpdate( list[i], spDragInfo, bNoSend );
2749                 }
2750                 HeapFree( GetProcessHeap(), 0, list );
2751             }
2752             if(bResult) return bResult;
2753         }
2754         else wParam = 1;
2755     }
2756     else wParam = 1;
2757
2758     ScreenToClient16(hQueryWnd,&ptrDragInfo->pt);
2759
2760     ptrDragInfo->hScope = hQueryWnd;
2761
2762     if (bNoSend) bResult = (GetWindowLongA( hQueryWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES) != 0;
2763     else bResult = SendMessage16( hQueryWnd, WM_QUERYDROPOBJECT, (WPARAM16)wParam, spDragInfo );
2764
2765     if( !bResult ) CONV_POINT32TO16( &pt, &ptrDragInfo->pt );
2766
2767     return bResult;
2768 }
2769
2770
2771 /*******************************************************************
2772  *              DragDetect (USER32.@)
2773  */
2774 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
2775 {
2776     MSG msg;
2777     RECT rect;
2778
2779     rect.left = pt.x - wDragWidth;
2780     rect.right = pt.x + wDragWidth;
2781
2782     rect.top = pt.y - wDragHeight;
2783     rect.bottom = pt.y + wDragHeight;
2784
2785     SetCapture(hWnd);
2786
2787     while(1)
2788     {
2789         while(PeekMessageA(&msg ,0 ,WM_MOUSEFIRST ,WM_MOUSELAST ,PM_REMOVE))
2790         {
2791             if( msg.message == WM_LBUTTONUP )
2792             {
2793                 ReleaseCapture();
2794                 return 0;
2795             }
2796             if( msg.message == WM_MOUSEMOVE )
2797             {
2798                 POINT tmp;
2799                 tmp.x = LOWORD(msg.lParam);
2800                 tmp.y = HIWORD(msg.lParam);
2801                 if( !PtInRect( &rect, tmp ))
2802                 {
2803                     ReleaseCapture();
2804                     return 1;
2805                 }
2806             }
2807         }
2808         WaitMessage();
2809     }
2810     return 0;
2811 }
2812
2813 /******************************************************************************
2814  *              DragObject (USER.464)
2815  */
2816 DWORD WINAPI DragObject16( HWND16 hwndScope, HWND16 hWnd, UINT16 wObj,
2817                            HANDLE16 hOfStruct, WORD szList, HCURSOR16 hCursor )
2818 {
2819     MSG msg;
2820     LPDRAGINFO16 lpDragInfo;
2821     SEGPTR      spDragInfo;
2822     HCURSOR16   hDragCursor=0, hOldCursor=0, hBummer=0;
2823     HGLOBAL16   hDragInfo  = GlobalAlloc16( GMEM_SHARE | GMEM_ZEROINIT, 2*sizeof(DRAGINFO16));
2824     HCURSOR16   hCurrentCursor = 0;
2825     HWND16      hCurrentWnd = 0;
2826
2827     lpDragInfo = (LPDRAGINFO16) GlobalLock16(hDragInfo);
2828     spDragInfo = K32WOWGlobalLock16(hDragInfo);
2829
2830     if( !lpDragInfo || !spDragInfo ) return 0L;
2831
2832     if (!(hBummer = LoadCursorA(0, MAKEINTRESOURCEA(OCR_NO))))
2833     {
2834         GlobalFree16(hDragInfo);
2835         return 0L;
2836     }
2837
2838     if(hCursor)
2839     {
2840         if( !(hDragCursor = CURSORICON_IconToCursor(hCursor, FALSE)) )
2841         {
2842             GlobalFree16(hDragInfo);
2843             return 0L;
2844         }
2845
2846         if( hDragCursor == hCursor ) hDragCursor = 0;
2847         else hCursor = hDragCursor;
2848
2849         hOldCursor = SetCursor(hDragCursor);
2850     }
2851
2852     lpDragInfo->hWnd   = hWnd;
2853     lpDragInfo->hScope = 0;
2854     lpDragInfo->wFlags = wObj;
2855     lpDragInfo->hList  = szList; /* near pointer! */
2856     lpDragInfo->hOfStruct = hOfStruct;
2857     lpDragInfo->l = 0L;
2858
2859     SetCapture(hWnd);
2860     ShowCursor( TRUE );
2861
2862     do
2863     {
2864         GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST );
2865
2866        *(lpDragInfo+1) = *lpDragInfo;
2867
2868         lpDragInfo->pt.x = msg.pt.x;
2869         lpDragInfo->pt.y = msg.pt.y;
2870
2871         /* update DRAGINFO struct */
2872         TRACE_(msg)("lpDI->hScope = %04x\n",lpDragInfo->hScope);
2873
2874         if( DRAG_QueryUpdate(hwndScope, spDragInfo, FALSE) > 0 )
2875             hCurrentCursor = hCursor;
2876         else
2877         {
2878             hCurrentCursor = hBummer;
2879             lpDragInfo->hScope = 0;
2880         }
2881         if( hCurrentCursor )
2882             SetCursor(hCurrentCursor);
2883
2884         /* send WM_DRAGLOOP */
2885         SendMessage16( hWnd, WM_DRAGLOOP, (WPARAM16)(hCurrentCursor != hBummer),
2886                                           (LPARAM) spDragInfo );
2887         /* send WM_DRAGSELECT or WM_DRAGMOVE */
2888         if( hCurrentWnd != lpDragInfo->hScope )
2889         {
2890             if( hCurrentWnd )
2891                 SendMessage16( hCurrentWnd, WM_DRAGSELECT, 0,
2892                        (LPARAM)MAKELONG(LOWORD(spDragInfo)+sizeof(DRAGINFO16),
2893                                         HIWORD(spDragInfo)) );
2894             hCurrentWnd = lpDragInfo->hScope;
2895             if( hCurrentWnd )
2896                 SendMessage16( hCurrentWnd, WM_DRAGSELECT, 1, (LPARAM)spDragInfo);
2897         }
2898         else
2899             if( hCurrentWnd )
2900                 SendMessage16( hCurrentWnd, WM_DRAGMOVE, 0, (LPARAM)spDragInfo);
2901
2902     } while( msg.message != WM_LBUTTONUP && msg.message != WM_NCLBUTTONUP );
2903
2904     ReleaseCapture();
2905     ShowCursor( FALSE );
2906
2907     if( hCursor )
2908     {
2909         SetCursor( hOldCursor );
2910         if (hDragCursor) DestroyCursor( hDragCursor );
2911     }
2912
2913     if( hCurrentCursor != hBummer )
2914         msg.lParam = SendMessage16( lpDragInfo->hScope, WM_DROPOBJECT,
2915                                    (WPARAM16)hWnd, (LPARAM)spDragInfo );
2916     else
2917         msg.lParam = 0;
2918     GlobalFree16(hDragInfo);
2919
2920     return (DWORD)(msg.lParam);
2921 }
2922
2923
2924 /******************************************************************************
2925  *              GetWindowModuleFileNameA (USER32.@)
2926  */
2927 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR lpszFileName, UINT cchFileNameMax)
2928 {
2929     FIXME("GetWindowModuleFileNameA(hwnd 0x%x, lpszFileName %p, cchFileNameMax %u) stub!\n",
2930           hwnd, lpszFileName, cchFileNameMax);
2931     return 0;
2932 }
2933
2934 /******************************************************************************
2935  *              GetWindowModuleFileNameW (USER32.@)
2936  */
2937 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPSTR lpszFileName, UINT cchFileNameMax)
2938 {
2939     FIXME("GetWindowModuleFileNameW(hwnd 0x%x, lpszFileName %p, cchFileNameMax %u) stub!\n",
2940           hwnd, lpszFileName, cchFileNameMax);
2941     return 0;
2942 }