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