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