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