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