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