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