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