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