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