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