Fix the Z-order of maximized/minimized child windows.
[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 "options.h"
10 #include "class.h"
11 #include "win.h"
12 #include "heap.h"
13 #include "user.h"
14 #include "dce.h"
15 #include "sysmetrics.h"
16 #include "cursoricon.h"
17 #include "heap.h"
18 #include "hook.h"
19 #include "menu.h"
20 #include "message.h"
21 #include "nonclient.h"
22 #include "queue.h"
23 #include "winpos.h"
24 #include "shm_main_blk.h"
25 #include "dde_proc.h"
26 #include "clipboard.h"
27 #include "winproc.h"
28 #include "thread.h"
29 #include "process.h"
30 #include "debug.h"
31 #include "winerror.h"
32 #include "mdi.h"
33
34 extern WND_DRIVER X11DRV_WND_Driver;
35
36 /* Desktop window */
37 static WND *pWndDesktop = NULL;
38
39 static HWND32 hwndSysModal = 0;
40
41 static WORD wDragWidth = 4;
42 static WORD wDragHeight= 3;
43
44 /***********************************************************************
45  *           WIN_FindWndPtr
46  *
47  * Return a pointer to the WND structure corresponding to a HWND.
48  */
49 WND * WIN_FindWndPtr( HWND32 hwnd )
50 {
51     WND * ptr;
52     
53     if (!hwnd || HIWORD(hwnd)) return NULL;
54     ptr = (WND *) USER_HEAP_LIN_ADDR( hwnd );
55     if (ptr->dwMagic != WND_MAGIC) return NULL;
56     if (ptr->hwndSelf != hwnd)
57     {
58         ERR( win, "Can't happen: hwnd %04x self pointer is %04x\n",
59                  hwnd, ptr->hwndSelf );
60         return NULL;
61     }
62     return ptr;
63 }
64
65
66 /***********************************************************************
67  *           WIN_DumpWindow
68  *
69  * Dump the content of a window structure to stderr.
70  */
71 void WIN_DumpWindow( HWND32 hwnd )
72 {
73     WND *ptr;
74     char className[80];
75     int i;
76
77     if (!(ptr = WIN_FindWndPtr( hwnd )))
78     {
79         WARN( win, "%04x is not a window handle\n", hwnd );
80         return;
81     }
82
83     if (!GetClassName32A( hwnd, className, sizeof(className ) ))
84         strcpy( className, "#NULL#" );
85
86     TRACE( win, "Window %04x (%p):\n", hwnd, ptr );
87     DUMP(    "next=%p  child=%p  parent=%p  owner=%p  class=%p '%s'\n"
88              "inst=%04x  taskQ=%04x  updRgn=%04x  active=%04x dce=%p  idmenu=%08x\n"
89              "style=%08lx  exstyle=%08lx  wndproc=%08x  text='%s'\n"
90              "client=%d,%d-%d,%d  window=%d,%d-%d,%d"
91              "sysmenu=%04x  flags=%04x  props=%p  vscroll=%p  hscroll=%p\n",
92              ptr->next, ptr->child, ptr->parent, ptr->owner,
93              ptr->class, className, ptr->hInstance, ptr->hmemTaskQ,
94              ptr->hrgnUpdate, ptr->hwndLastActive, ptr->dce, ptr->wIDmenu,
95              ptr->dwStyle, ptr->dwExStyle, (UINT32)ptr->winproc,
96              ptr->text ? ptr->text : "",
97              ptr->rectClient.left, ptr->rectClient.top, ptr->rectClient.right,
98              ptr->rectClient.bottom, ptr->rectWindow.left, ptr->rectWindow.top,
99              ptr->rectWindow.right, ptr->rectWindow.bottom, ptr->hSysMenu,
100              ptr->flags, ptr->pProp, ptr->pVScroll, ptr->pHScroll );
101
102     if (ptr->class->cbWndExtra)
103     {
104         DUMP( "extra bytes:" );
105         for (i = 0; i < ptr->class->cbWndExtra; i++)
106             DUMP( " %02x", *((BYTE*)ptr->wExtra+i) );
107         DUMP( "\n" );
108     }
109     DUMP( "\n" );
110 }
111
112
113 /***********************************************************************
114  *           WIN_WalkWindows
115  *
116  * Walk the windows tree and print each window on stderr.
117  */
118 void WIN_WalkWindows( HWND32 hwnd, int indent )
119 {
120     WND *ptr;
121     char className[80];
122
123     ptr = hwnd ? WIN_FindWndPtr( hwnd ) : pWndDesktop;
124     if (!ptr)
125     {
126         WARN( win, "Invalid window handle %04x\n", hwnd );
127         return;
128     }
129
130     if (!indent)  /* first time around */
131        DUMP( "%-16.16s %-8.8s %-6.6s %-17.17s %-8.8s %s\n",
132                  "hwnd", " wndPtr", "queue", "Class Name", " Style", " WndProc"
133                  " Text");
134
135     while (ptr)
136     {
137         DUMP( "%*s%04x%*s", indent, "", ptr->hwndSelf, 13-indent,"");
138
139         GlobalGetAtomName16(ptr->class->atomName,className,sizeof(className));
140         
141         DUMP( "%08lx %-6.4x %-17.17s %08x %08x %.14s\n",
142                  (DWORD)ptr, ptr->hmemTaskQ, className,
143                  (UINT32)ptr->dwStyle, (UINT32)ptr->winproc,
144                  ptr->text?ptr->text:"<null>");
145         
146         if (ptr->child) WIN_WalkWindows( ptr->child->hwndSelf, indent+1 );
147         ptr = ptr->next;
148     }
149 }
150
151 /***********************************************************************
152  *           WIN_UnlinkWindow
153  *
154  * Remove a window from the siblings linked list.
155  */
156 BOOL32 WIN_UnlinkWindow( HWND32 hwnd )
157 {    
158     WND *wndPtr, **ppWnd;
159
160     if (!(wndPtr = WIN_FindWndPtr( hwnd )) || !wndPtr->parent) return FALSE;
161     ppWnd = &wndPtr->parent->child;
162     while (*ppWnd != wndPtr) ppWnd = &(*ppWnd)->next;
163     *ppWnd = wndPtr->next;
164     return TRUE;
165 }
166
167
168 /***********************************************************************
169  *           WIN_LinkWindow
170  *
171  * Insert a window into the siblings linked list.
172  * The window is inserted after the specified window, which can also
173  * be specified as HWND_TOP or HWND_BOTTOM.
174  */
175 BOOL32 WIN_LinkWindow( HWND32 hwnd, HWND32 hwndInsertAfter )
176 {    
177     WND *wndPtr, **ppWnd;
178
179     if (!(wndPtr = WIN_FindWndPtr( hwnd )) || !wndPtr->parent) return FALSE;
180
181     if ((hwndInsertAfter == HWND_TOP) || (hwndInsertAfter == HWND_BOTTOM))
182     {
183         ppWnd = &wndPtr->parent->child;  /* Point to first sibling hwnd */
184         if (hwndInsertAfter == HWND_BOTTOM)  /* Find last sibling hwnd */
185             while (*ppWnd) ppWnd = &(*ppWnd)->next;
186     }
187     else  /* Normal case */
188     {
189         WND * afterPtr = WIN_FindWndPtr( hwndInsertAfter );
190         if (!afterPtr) return FALSE;
191         ppWnd = &afterPtr->next;
192     }
193     wndPtr->next = *ppWnd;
194     *ppWnd = wndPtr;
195     return TRUE;
196 }
197
198
199 /***********************************************************************
200  *           WIN_FindWinToRepaint
201  *
202  * Find a window that needs repaint.
203  */
204 HWND32 WIN_FindWinToRepaint( HWND32 hwnd, HQUEUE16 hQueue )
205 {
206     HWND32 hwndRet;
207     WND *pWnd = pWndDesktop;
208
209     /* Note: the desktop window never gets WM_PAINT messages 
210      * The real reason why is because Windows DesktopWndProc
211      * does ValidateRgn inside WM_ERASEBKGND handler.
212      */
213
214     pWnd = hwnd ? WIN_FindWndPtr( hwnd ) : pWndDesktop->child;
215
216     for ( ; pWnd ; pWnd = pWnd->next )
217     {
218         if (!(pWnd->dwStyle & WS_VISIBLE))
219         {
220             TRACE(win, "skipping window %04x\n",
221                          pWnd->hwndSelf );
222             continue;
223         }
224         if ((pWnd->hmemTaskQ == hQueue) &&
225             (pWnd->hrgnUpdate || (pWnd->flags & WIN_INTERNAL_PAINT))) break;
226         
227         if (pWnd->child )
228             if ((hwndRet = WIN_FindWinToRepaint( pWnd->child->hwndSelf, hQueue )) )
229                 return hwndRet;
230     }
231     
232     if (!pWnd) return 0;
233     
234     hwndRet = pWnd->hwndSelf;
235
236     /* look among siblings if we got a transparent window */
237     while (pWnd && ((pWnd->dwExStyle & WS_EX_TRANSPARENT) ||
238                     !(pWnd->hrgnUpdate || (pWnd->flags & WIN_INTERNAL_PAINT))))
239     {
240         pWnd = pWnd->next;
241     }
242     if (pWnd) hwndRet = pWnd->hwndSelf;
243     TRACE(win,"found %04x\n",hwndRet);
244     return hwndRet;
245 }
246
247
248 /***********************************************************************
249  *           WIN_DestroyWindow
250  *
251  * Destroy storage associated to a window. "Internals" p.358
252  */
253 static WND* WIN_DestroyWindow( WND* wndPtr )
254 {
255     HWND32 hwnd = wndPtr->hwndSelf;
256     WND *pWnd;
257
258     TRACE(win, "%04x\n", wndPtr->hwndSelf );
259
260 #ifdef CONFIG_IPC
261     if (main_block)
262         DDE_DestroyWindow(wndPtr->hwndSelf);
263 #endif  /* CONFIG_IPC */
264         
265     /* free child windows */
266
267     while ((pWnd = wndPtr->child))
268         wndPtr->child = WIN_DestroyWindow( pWnd );
269
270     SendMessage32A( wndPtr->hwndSelf, WM_NCDESTROY, 0, 0);
271
272     /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
273
274     WINPOS_CheckInternalPos( hwnd );
275     if( hwnd == GetCapture32()) ReleaseCapture();
276
277     /* free resources associated with the window */
278
279     TIMER_RemoveWindowTimers( wndPtr->hwndSelf );
280     PROPERTY_RemoveWindowProps( wndPtr );
281
282     wndPtr->dwMagic = 0;  /* Mark it as invalid */
283
284     if ((wndPtr->hrgnUpdate) || (wndPtr->flags & WIN_INTERNAL_PAINT))
285     {
286         if (wndPtr->hrgnUpdate > 1) DeleteObject32( wndPtr->hrgnUpdate );
287         QUEUE_DecPaintCount( wndPtr->hmemTaskQ );
288     }
289
290     /* toss stale messages from the queue */
291
292     if( wndPtr->hmemTaskQ )
293     {
294         int           pos;
295         BOOL32        bPostQuit = FALSE;
296         WPARAM32      wQuitParam = 0;
297         MESSAGEQUEUE* msgQ = (MESSAGEQUEUE*) GlobalLock16(wndPtr->hmemTaskQ);
298
299         while( (pos = QUEUE_FindMsg(msgQ, hwnd, 0, 0)) != -1 )
300         {
301             if( msgQ->messages[pos].msg.message == WM_QUIT ) 
302             {
303                 bPostQuit = TRUE;
304                 wQuitParam = msgQ->messages[pos].msg.wParam;
305             }
306             QUEUE_RemoveMsg(msgQ, pos);
307         }
308         /* repost WM_QUIT to make sure this app exits its message loop */
309         if( bPostQuit ) PostQuitMessage32(wQuitParam);
310         wndPtr->hmemTaskQ = 0;
311     }
312
313     if (!(wndPtr->dwStyle & WS_CHILD))
314        if (wndPtr->wIDmenu) DestroyMenu32( (HMENU32)wndPtr->wIDmenu );
315     if (wndPtr->hSysMenu) DestroyMenu32( wndPtr->hSysMenu );
316     wndPtr->pDriver->pDestroyWindow( wndPtr );
317     DCE_FreeWindowDCE( wndPtr );    /* Always do this to catch orphaned DCs */ 
318     WINPROC_FreeProc( wndPtr->winproc, WIN_PROC_WINDOW );
319     wndPtr->hwndSelf = 0;
320     wndPtr->class->cWindows--;
321     wndPtr->class = NULL;
322     pWnd = wndPtr->next;
323
324     USER_HEAP_FREE( hwnd );
325     return pWnd;
326 }
327
328 /***********************************************************************
329  *           WIN_ResetQueueWindows
330  *
331  * Reset the queue of all the children of a given window.
332  * Return TRUE if something was done.
333  */
334 BOOL32 WIN_ResetQueueWindows( WND* wnd, HQUEUE16 hQueue, HQUEUE16 hNew )
335 {
336     BOOL32 ret = FALSE;
337
338     if (hNew)  /* Set a new queue */
339     {
340         for (wnd = wnd->child; (wnd); wnd = wnd->next)
341         {
342             if (wnd->hmemTaskQ == hQueue)
343             {
344                 wnd->hmemTaskQ = hNew;
345                 ret = TRUE;
346             }
347             if (wnd->child)
348                 ret |= WIN_ResetQueueWindows( wnd, hQueue, hNew );
349         }
350     }
351     else  /* Queue is being destroyed */
352     {
353         while (wnd->child)
354         {
355             WND *tmp = wnd->child;
356             ret = FALSE;
357             while (tmp)
358             {
359                 if (tmp->hmemTaskQ == hQueue)
360                 {
361                     DestroyWindow32( tmp->hwndSelf );
362                     ret = TRUE;
363                     break;
364                 }
365                 if (tmp->child && WIN_ResetQueueWindows(tmp->child,hQueue,0))
366                     ret = TRUE;
367                 else
368                     tmp = tmp->next;
369             }
370             if (!ret) break;
371         }
372     }
373     return ret;
374 }
375
376 /***********************************************************************
377  *           WIN_CreateDesktopWindow
378  *
379  * Create the desktop window.
380  */
381 BOOL32 WIN_CreateDesktopWindow(void)
382 {
383     CLASS *class;
384     HWND32 hwndDesktop;
385
386     TRACE(win,"Creating desktop window\n");
387
388     if (!ICONTITLE_Init() ||
389         !WINPOS_CreateInternalPosAtom() ||
390         !(class = CLASS_FindClassByAtom( DESKTOP_CLASS_ATOM, 0 )))
391         return FALSE;
392
393     hwndDesktop = USER_HEAP_ALLOC( sizeof(WND)+class->cbWndExtra );
394     if (!hwndDesktop) return FALSE;
395     pWndDesktop = (WND *) USER_HEAP_LIN_ADDR( hwndDesktop );
396
397     pWndDesktop->next              = NULL;
398     pWndDesktop->child             = NULL;
399     pWndDesktop->parent            = NULL;
400     pWndDesktop->owner             = NULL;
401     pWndDesktop->class             = class;
402     pWndDesktop->dwMagic           = WND_MAGIC;
403     pWndDesktop->hwndSelf          = hwndDesktop;
404     pWndDesktop->hInstance         = 0;
405     pWndDesktop->rectWindow.left   = 0;
406     pWndDesktop->rectWindow.top    = 0;
407     pWndDesktop->rectWindow.right  = SYSMETRICS_CXSCREEN;
408     pWndDesktop->rectWindow.bottom = SYSMETRICS_CYSCREEN;
409     pWndDesktop->rectClient        = pWndDesktop->rectWindow;
410     pWndDesktop->text              = NULL;
411     pWndDesktop->hmemTaskQ         = 0; /* Desktop does not belong to a task */
412     pWndDesktop->hrgnUpdate        = 0;
413     pWndDesktop->hwndLastActive    = hwndDesktop;
414     pWndDesktop->dwStyle           = WS_VISIBLE | WS_CLIPCHILDREN |
415                                      WS_CLIPSIBLINGS;
416     pWndDesktop->dwExStyle         = 0;
417     pWndDesktop->dce               = NULL;
418     pWndDesktop->pVScroll          = NULL;
419     pWndDesktop->pHScroll          = NULL;
420     pWndDesktop->pProp             = NULL;
421     pWndDesktop->wIDmenu           = 0;
422     pWndDesktop->helpContext       = 0;
423     pWndDesktop->flags             = 0;
424     pWndDesktop->hSysMenu          = 0;
425     pWndDesktop->userdata          = 0;
426     pWndDesktop->pDriver           = &X11DRV_WND_Driver;
427     pWndDesktop->winproc = (WNDPROC16)class->winproc;
428
429     /* FIXME: How do we know if it should be Unicode or not */
430     if(!pWndDesktop->pDriver->pCreateDesktopWindow(pWndDesktop, class, FALSE))
431       return FALSE;
432     
433     SendMessage32A( hwndDesktop, WM_NCCREATE, 0, 0 );
434     pWndDesktop->flags |= WIN_NEEDS_ERASEBKGND;
435     return TRUE;
436 }
437
438
439 /***********************************************************************
440  *           WIN_CreateWindowEx
441  *
442  * Implementation of CreateWindowEx().
443  */
444 static HWND32 WIN_CreateWindowEx( CREATESTRUCT32A *cs, ATOM classAtom,
445                                   BOOL32 win32, BOOL32 unicode )
446 {
447     CLASS *classPtr;
448     WND *wndPtr;
449     HWND16 hwnd, hwndLinkAfter;
450     POINT32 maxSize, maxPos, minTrack, maxTrack;
451     LRESULT (CALLBACK *localSend32)(HWND32, UINT32, WPARAM32, LPARAM);
452
453     TRACE(win, "%s %s %08lx %08lx %d,%d %dx%d %04x %04x %08x %p\n",
454           unicode ? debugres_w((LPWSTR)cs->lpszName) : debugres_a(cs->lpszName), 
455           unicode ? debugres_w((LPWSTR)cs->lpszClass) : debugres_a(cs->lpszClass),
456           cs->dwExStyle, cs->style, cs->x, cs->y, cs->cx, cs->cy,
457           cs->hwndParent, cs->hMenu, cs->hInstance, cs->lpCreateParams );
458
459     /* Find the parent window */
460
461     if (cs->hwndParent)
462     {
463         /* Make sure parent is valid */
464         if (!IsWindow32( cs->hwndParent ))
465         {
466             WARN( win, "Bad parent %04x\n", cs->hwndParent );
467             return 0;
468         }
469     } else if ((cs->style & WS_CHILD) && !(cs->style & WS_POPUP)) {
470         WARN( win, "No parent for child window\n" );
471         return 0;  /* WS_CHILD needs a parent, but WS_POPUP doesn't */
472     }
473
474     /* Find the window class */
475     if (!(classPtr = CLASS_FindClassByAtom( classAtom, win32?cs->hInstance:GetExePtr(cs->hInstance) )))
476     {
477         char buffer[256];
478         GlobalGetAtomName32A( classAtom, buffer, sizeof(buffer) );
479         WARN( win, "Bad class '%s'\n", buffer );
480         return 0;
481     }
482
483     /* Fix the coordinates */
484
485     if (cs->x == CW_USEDEFAULT32) 
486     {
487         PDB32 *pdb = PROCESS_Current();
488         if (   !(cs->style & (WS_CHILD | WS_POPUP))
489             &&  (pdb->env_db->startup_info->dwFlags & STARTF_USEPOSITION) )
490         {
491             cs->x = pdb->env_db->startup_info->dwX;
492             cs->y = pdb->env_db->startup_info->dwY;
493         }
494         else
495         {
496             cs->x = 0;
497             cs->y = 0;
498         }
499     }
500     if (cs->cx == CW_USEDEFAULT32)
501     {
502         PDB32 *pdb = PROCESS_Current();
503         if (   !(cs->style & (WS_CHILD | WS_POPUP))
504             &&  (pdb->env_db->startup_info->dwFlags & STARTF_USESIZE) )
505         {
506             cs->cx = pdb->env_db->startup_info->dwXSize;
507             cs->cy = pdb->env_db->startup_info->dwYSize;
508         }
509         else
510         {
511             cs->cx = 600; /* FIXME */
512             cs->cy = 400;
513         }
514     }
515
516     /* Create the window structure */
517
518     if (!(hwnd = USER_HEAP_ALLOC( sizeof(*wndPtr) + classPtr->cbWndExtra
519                                   - sizeof(wndPtr->wExtra) )))
520     {
521         TRACE(win, "out of memory\n" );
522         return 0;
523     }
524
525     /* Fill the window structure */
526
527     wndPtr = (WND *) USER_HEAP_LIN_ADDR( hwnd );
528     wndPtr->next  = NULL;
529     wndPtr->child = NULL;
530
531     if ((cs->style & WS_CHILD) && cs->hwndParent)
532     {
533         wndPtr->parent = WIN_FindWndPtr( cs->hwndParent );
534         wndPtr->owner  = NULL;
535     }
536     else
537     {
538         wndPtr->parent = pWndDesktop;
539         if (!cs->hwndParent || (cs->hwndParent == pWndDesktop->hwndSelf))
540             wndPtr->owner = NULL;
541         else
542             wndPtr->owner = WIN_GetTopParentPtr(WIN_FindWndPtr(cs->hwndParent));
543     }
544
545     wndPtr->pDriver        = &X11DRV_WND_Driver;
546     wndPtr->window         = 0;
547     wndPtr->class          = classPtr;
548     wndPtr->winproc        = classPtr->winproc;
549     wndPtr->dwMagic        = WND_MAGIC;
550     wndPtr->hwndSelf       = hwnd;
551     wndPtr->hInstance      = cs->hInstance;
552     wndPtr->text           = NULL;
553     wndPtr->hmemTaskQ      = GetTaskQueue(0);
554     wndPtr->hrgnUpdate     = 0;
555     wndPtr->hwndLastActive = hwnd;
556     wndPtr->dwStyle        = cs->style & ~WS_VISIBLE;
557     wndPtr->dwExStyle      = cs->dwExStyle;
558     wndPtr->wIDmenu        = 0;
559     wndPtr->helpContext    = 0;
560     wndPtr->flags          = win32 ? WIN_ISWIN32 : 0;
561     wndPtr->pVScroll       = NULL;
562     wndPtr->pHScroll       = NULL;
563     wndPtr->pProp          = NULL;
564     wndPtr->userdata       = 0;
565     wndPtr->hSysMenu       = (wndPtr->dwStyle & WS_SYSMENU)
566                              ? MENU_GetSysMenu( hwnd, 0 ) : 0;
567
568     if (classPtr->cbWndExtra) memset( wndPtr->wExtra, 0, classPtr->cbWndExtra);
569
570     /* Call the WH_CBT hook */
571
572     hwndLinkAfter = ((cs->style & (WS_CHILD|WS_MAXIMIZE)) == WS_CHILD)
573  ? HWND_BOTTOM : HWND_TOP;
574
575     if (HOOK_IsHooked( WH_CBT ))
576     {
577         CBT_CREATEWND32A cbtc;
578         LRESULT ret;
579
580         cbtc.lpcs = cs;
581         cbtc.hwndInsertAfter = hwndLinkAfter;
582         ret = unicode ? HOOK_CallHooks32W(WH_CBT, HCBT_CREATEWND, hwnd, (LPARAM)&cbtc)
583                       : HOOK_CallHooks32A(WH_CBT, HCBT_CREATEWND, hwnd, (LPARAM)&cbtc);
584         if (ret)
585         {
586             TRACE(win, "CBT-hook returned 0\n");
587             USER_HEAP_FREE( hwnd );
588             return 0;
589         }
590     }
591
592     /* Increment class window counter */
593
594     classPtr->cWindows++;
595
596     /* Correct the window style */
597
598     if (!(cs->style & (WS_POPUP | WS_CHILD)))  /* Overlapped window */
599     {
600         wndPtr->dwStyle |= WS_CAPTION | WS_CLIPSIBLINGS;
601         wndPtr->flags |= WIN_NEED_SIZE;
602     }
603     if (cs->dwExStyle & WS_EX_DLGMODALFRAME) wndPtr->dwStyle &= ~WS_THICKFRAME;
604
605     /* Get class or window DC if needed */
606
607     if (classPtr->style & CS_OWNDC) wndPtr->dce = DCE_AllocDCE(hwnd,DCE_WINDOW_DC);
608     else if (classPtr->style & CS_CLASSDC) wndPtr->dce = classPtr->dce;
609     else wndPtr->dce = NULL;
610
611     /* Send the WM_GETMINMAXINFO message and fix the size if needed */
612
613     if ((cs->style & WS_THICKFRAME) || !(cs->style & (WS_POPUP | WS_CHILD)))
614     {
615         WINPOS_GetMinMaxInfo( wndPtr, &maxSize, &maxPos, &minTrack, &maxTrack);
616         if (maxSize.x < cs->cx) cs->cx = maxSize.x;
617         if (maxSize.y < cs->cy) cs->cy = maxSize.y;
618         if (cs->cx < minTrack.x ) cs->cx = minTrack.x;
619         if (cs->cy < minTrack.y ) cs->cy = minTrack.y;
620     }
621
622     if(cs->style & WS_CHILD)
623     {
624         if(cs->cx < 0) cs->cx = 0;
625         if(cs->cy < 0) cs->cy = 0;
626     }
627     else
628     {
629         if (cs->cx <= 0) cs->cx = 1;
630         if (cs->cy <= 0) cs->cy = 1;
631     }
632
633     wndPtr->rectWindow.left   = cs->x;
634     wndPtr->rectWindow.top    = cs->y;
635     wndPtr->rectWindow.right  = cs->x + cs->cx;
636     wndPtr->rectWindow.bottom = cs->y + cs->cy;
637     wndPtr->rectClient        = wndPtr->rectWindow;
638
639     if(!wndPtr->pDriver->pCreateWindow(wndPtr, classPtr, cs, unicode))
640        return FALSE;
641
642     /* Set the window menu */
643
644     if ((wndPtr->dwStyle & (WS_CAPTION | WS_CHILD)) == WS_CAPTION )
645     {
646         if (cs->hMenu) SetMenu32(hwnd, cs->hMenu);
647         else
648         {
649 #if 0  /* FIXME: should check if classPtr->menuNameW can be used as is */
650             if (classPtr->menuNameA)
651                 cs->hMenu = HIWORD(classPtr->menuNameA) ?
652                        LoadMenu(cs->hInstance,SEGPTR_GET(classPtr->menuNameA)):
653                        LoadMenu(cs->hInstance,(SEGPTR)classPtr->menuNameA);
654 #else
655             SEGPTR menuName = (SEGPTR)GetClassLong16( hwnd, GCL_MENUNAME );
656             if (menuName)
657             {
658                 if (HIWORD(cs->hInstance))
659                     cs->hMenu = LoadMenu32A(cs->hInstance,PTR_SEG_TO_LIN(menuName));
660                 else
661                     cs->hMenu = LoadMenu16(cs->hInstance,menuName);
662
663                 if (cs->hMenu) SetMenu32( hwnd, cs->hMenu );
664             }
665 #endif
666         }
667     }
668     else wndPtr->wIDmenu = (UINT32)cs->hMenu;
669
670     /* Send the WM_CREATE message 
671      * Perhaps we shouldn't allow width/height changes as well. 
672      * See p327 in "Internals". 
673      */
674
675     maxPos.x = wndPtr->rectWindow.left; maxPos.y = wndPtr->rectWindow.top;
676
677     localSend32 = unicode ? SendMessage32W : SendMessage32A;
678     if( (*localSend32)( hwnd, WM_NCCREATE, 0, (LPARAM)cs) )
679     {
680         /* Insert the window in the linked list */
681
682         WIN_LinkWindow( hwnd, hwndLinkAfter );
683
684         WINPOS_SendNCCalcSize( hwnd, FALSE, &wndPtr->rectWindow,
685                                NULL, NULL, 0, &wndPtr->rectClient );
686         OffsetRect32(&wndPtr->rectWindow, maxPos.x - wndPtr->rectWindow.left,
687                                           maxPos.y - wndPtr->rectWindow.top);
688         if( ((*localSend32)( hwnd, WM_CREATE, 0, (LPARAM)cs )) != -1 )
689         {
690             /* Send the size messages */
691
692             if (!(wndPtr->flags & WIN_NEED_SIZE))
693             {
694                 /* send it anyway */
695                 if (((wndPtr->rectClient.right-wndPtr->rectClient.left) <0)
696                     ||((wndPtr->rectClient.bottom-wndPtr->rectClient.top)<0))
697                   WARN(win,"sending bogus WM_SIZE message 0x%08lx\n",
698                         MAKELONG(wndPtr->rectClient.right-wndPtr->rectClient.left,
699                                  wndPtr->rectClient.bottom-wndPtr->rectClient.top));
700                 SendMessage32A( hwnd, WM_SIZE, SIZE_RESTORED,
701                                 MAKELONG(wndPtr->rectClient.right-wndPtr->rectClient.left,
702                                          wndPtr->rectClient.bottom-wndPtr->rectClient.top));
703                 SendMessage32A( hwnd, WM_MOVE, 0,
704                                 MAKELONG( wndPtr->rectClient.left,
705                                           wndPtr->rectClient.top ) );
706             }
707
708             /* Show the window, maximizing or minimizing if needed */
709
710             if (wndPtr->dwStyle & (WS_MINIMIZE | WS_MAXIMIZE))
711             {
712                 RECT16 newPos;
713                 UINT16 swFlag = (wndPtr->dwStyle & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;
714                 wndPtr->dwStyle &= ~(WS_MAXIMIZE | WS_MINIMIZE);
715                 WINPOS_MinMaximize( wndPtr, swFlag, &newPos );
716                 swFlag = ((wndPtr->dwStyle & WS_CHILD) || GetActiveWindow32())
717                     ? SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED
718                     : SWP_NOZORDER | SWP_FRAMECHANGED;
719                 SetWindowPos32( hwnd, 0, newPos.left, newPos.top,
720                                 newPos.right, newPos.bottom, swFlag );
721             }
722
723             if( wndPtr->dwStyle & WS_CHILD && !(wndPtr->dwExStyle & WS_EX_NOPARENTNOTIFY) )
724             {
725                 /* Notify the parent window only */
726
727                 SendMessage32A( wndPtr->parent->hwndSelf, WM_PARENTNOTIFY,
728                                 MAKEWPARAM(WM_CREATE, wndPtr->wIDmenu), (LPARAM)hwnd );
729                 if( !IsWindow32(hwnd) ) return 0;
730             }
731
732             if (cs->style & WS_VISIBLE) ShowWindow32( hwnd, SW_SHOW );
733
734             /* Call WH_SHELL hook */
735
736             if (!(wndPtr->dwStyle & WS_CHILD) && !wndPtr->owner)
737                 HOOK_CallHooks16( WH_SHELL, HSHELL_WINDOWCREATED, hwnd, 0 );
738
739             TRACE(win, "created window %04x\n", hwnd);
740             return hwnd;
741         }
742         WIN_UnlinkWindow( hwnd );
743     }
744
745     /* Abort window creation */
746
747     WARN(win, "aborted by WM_xxCREATE!\n");
748     WIN_DestroyWindow( wndPtr );
749     return 0;
750 }
751
752
753 /***********************************************************************
754  *           CreateWindow16   (USER.41)
755  */
756 HWND16 WINAPI CreateWindow16( LPCSTR className, LPCSTR windowName,
757                               DWORD style, INT16 x, INT16 y, INT16 width,
758                               INT16 height, HWND16 parent, HMENU16 menu,
759                               HINSTANCE16 instance, LPVOID data ) 
760 {
761     return CreateWindowEx16( 0, className, windowName, style,
762                            x, y, width, height, parent, menu, instance, data );
763 }
764
765
766 /***********************************************************************
767  *           CreateWindowEx16   (USER.452)
768  */
769 HWND16 WINAPI CreateWindowEx16( DWORD exStyle, LPCSTR className,
770                                 LPCSTR windowName, DWORD style, INT16 x,
771                                 INT16 y, INT16 width, INT16 height,
772                                 HWND16 parent, HMENU16 menu,
773                                 HINSTANCE16 instance, LPVOID data ) 
774 {
775     ATOM classAtom;
776     CREATESTRUCT32A cs;
777
778     /* Find the class atom */
779
780     if (!(classAtom = GlobalFindAtom32A( className )))
781     {
782         fprintf( stderr, "CreateWindowEx16: bad class name " );
783         if (!HIWORD(className)) fprintf( stderr, "%04x\n", LOWORD(className) );
784         else fprintf( stderr, "'%s'\n", className );
785         return 0;
786     }
787
788     /* Fix the coordinates */
789
790     cs.x  = (x == CW_USEDEFAULT16) ? CW_USEDEFAULT32 : (INT32)x;
791     cs.y  = (y == CW_USEDEFAULT16) ? CW_USEDEFAULT32 : (INT32)y;
792     cs.cx = (width == CW_USEDEFAULT16) ? CW_USEDEFAULT32 : (INT32)width;
793     cs.cy = (height == CW_USEDEFAULT16) ? CW_USEDEFAULT32 : (INT32)height;
794
795     /* Create the window */
796
797     cs.lpCreateParams = data;
798     cs.hInstance      = (HINSTANCE32)instance;
799     cs.hMenu          = (HMENU32)menu;
800     cs.hwndParent     = (HWND32)parent;
801     cs.style          = style;
802     cs.lpszName       = windowName;
803     cs.lpszClass      = className;
804     cs.dwExStyle      = exStyle;
805     return WIN_CreateWindowEx( &cs, classAtom, FALSE, FALSE );
806 }
807
808
809 /***********************************************************************
810  *           CreateWindowEx32A   (USER32.83)
811  */
812 HWND32 WINAPI CreateWindowEx32A( DWORD exStyle, LPCSTR className,
813                                  LPCSTR windowName, DWORD style, INT32 x,
814                                  INT32 y, INT32 width, INT32 height,
815                                  HWND32 parent, HMENU32 menu,
816                                  HINSTANCE32 instance, LPVOID data )
817 {
818     ATOM classAtom;
819     CREATESTRUCT32A cs;
820
821     if(exStyle & WS_EX_MDICHILD)
822         return MDI_CreateMDIWindow32A(className, windowName, style, x, y, width, height, parent, instance, data);
823     /* Find the class atom */
824
825     if (!(classAtom = GlobalFindAtom32A( className )))
826     {
827         fprintf( stderr, "CreateWindowEx32A: bad class name " );
828         if (!HIWORD(className)) fprintf( stderr, "%04x\n", LOWORD(className) );
829         else fprintf( stderr, "'%s'\n", className );
830         return 0;
831     }
832
833     /* Create the window */
834
835     cs.lpCreateParams = data;
836     cs.hInstance      = instance;
837     cs.hMenu          = menu;
838     cs.hwndParent     = parent;
839     cs.x              = x;
840     cs.y              = y;
841     cs.cx             = width;
842     cs.cy             = height;
843     cs.style          = style;
844     cs.lpszName       = windowName;
845     cs.lpszClass      = className;
846     cs.dwExStyle      = exStyle;
847     return WIN_CreateWindowEx( &cs, classAtom, TRUE, FALSE );
848 }
849
850
851 /***********************************************************************
852  *           CreateWindowEx32W   (USER32.84)
853  */
854 HWND32 WINAPI CreateWindowEx32W( DWORD exStyle, LPCWSTR className,
855                                  LPCWSTR windowName, DWORD style, INT32 x,
856                                  INT32 y, INT32 width, INT32 height,
857                                  HWND32 parent, HMENU32 menu,
858                                  HINSTANCE32 instance, LPVOID data )
859 {
860     ATOM classAtom;
861     CREATESTRUCT32W cs;
862
863     if(exStyle & WS_EX_MDICHILD)
864         return MDI_CreateMDIWindow32W(className, windowName, style, x, y, width, height, parent, instance, data);
865
866     /* Find the class atom */
867
868     if (!(classAtom = GlobalFindAtom32W( className )))
869     {
870         if (HIWORD(className))
871         {
872             LPSTR cn = HEAP_strdupWtoA( GetProcessHeap(), 0, className );
873             WARN( win, "Bad class name '%s'\n",cn);
874             HeapFree( GetProcessHeap(), 0, cn );
875         }
876         else
877             WARN( win, "Bad class name %p\n", className );
878         return 0;
879     }
880
881     /* Create the window */
882
883     cs.lpCreateParams = data;
884     cs.hInstance      = instance;
885     cs.hMenu          = menu;
886     cs.hwndParent     = parent;
887     cs.x              = x;
888     cs.y              = y;
889     cs.cx             = width;
890     cs.cy             = height;
891     cs.style          = style;
892     cs.lpszName       = windowName;
893     cs.lpszClass      = className;
894     cs.dwExStyle      = exStyle;
895     /* Note: we rely on the fact that CREATESTRUCT32A and */
896     /* CREATESTRUCT32W have the same layout. */
897     return WIN_CreateWindowEx( (CREATESTRUCT32A *)&cs, classAtom, TRUE, TRUE );
898 }
899
900
901 /***********************************************************************
902  *           WIN_CheckFocus
903  */
904 static void WIN_CheckFocus( WND* pWnd )
905 {
906     if( GetFocus16() == pWnd->hwndSelf )
907         SetFocus16( (pWnd->dwStyle & WS_CHILD) ? pWnd->parent->hwndSelf : 0 ); 
908 }
909
910 /***********************************************************************
911  *           WIN_SendDestroyMsg
912  */
913 static void WIN_SendDestroyMsg( WND* pWnd )
914 {
915     WIN_CheckFocus(pWnd);
916
917     if( CARET_GetHwnd() == pWnd->hwndSelf ) DestroyCaret32();
918     if( !pWnd->window ) CLIPBOARD_GetDriver()->pResetOwner( pWnd ); 
919   
920     SendMessage32A( pWnd->hwndSelf, WM_DESTROY, 0, 0);
921
922     if( IsWindow32(pWnd->hwndSelf) )
923     {
924         WND* pChild = pWnd->child;
925         while( pChild )
926         {
927             WIN_SendDestroyMsg( pChild );
928             pChild = pChild->next;
929         }
930         WIN_CheckFocus(pWnd);
931     }
932     else
933         WARN(win, "\tdestroyed itself while in WM_DESTROY!\n");
934 }
935
936
937 /***********************************************************************
938  *           DestroyWindow16   (USER.53)
939  */
940 BOOL16 WINAPI DestroyWindow16( HWND16 hwnd )
941 {
942     return DestroyWindow32(hwnd);
943 }
944
945
946 /***********************************************************************
947  *           DestroyWindow32   (USER32.135)
948  */
949 BOOL32 WINAPI DestroyWindow32( HWND32 hwnd )
950 {
951     WND * wndPtr;
952
953     TRACE(win, "(%04x)\n", hwnd);
954     
955       /* Initialization */
956
957     if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
958     if (wndPtr == pWndDesktop) return FALSE; /* Can't destroy desktop */
959
960       /* Call hooks */
961
962     if( HOOK_CallHooks16( WH_CBT, HCBT_DESTROYWND, hwnd, 0L) )
963         return FALSE;
964
965     if (!(wndPtr->dwStyle & WS_CHILD) && !wndPtr->owner)
966     {
967         HOOK_CallHooks16( WH_SHELL, HSHELL_WINDOWDESTROYED, hwnd, 0L );
968         /* FIXME: clean up palette - see "Internals" p.352 */
969     }
970
971     if( !QUEUE_IsExitingQueue(wndPtr->hmemTaskQ) )
972         if( wndPtr->dwStyle & WS_CHILD && !(wndPtr->dwExStyle & WS_EX_NOPARENTNOTIFY) )
973         {
974             /* Notify the parent window only */
975             SendMessage32A( wndPtr->parent->hwndSelf, WM_PARENTNOTIFY,
976                             MAKEWPARAM(WM_DESTROY, wndPtr->wIDmenu), (LPARAM)hwnd );
977             if( !IsWindow32(hwnd) ) return TRUE;
978         }
979
980     if( wndPtr->window ) CLIPBOARD_GetDriver()->pResetOwner( wndPtr ); /* before the window is unmapped */
981
982       /* Hide the window */
983
984     if (wndPtr->dwStyle & WS_VISIBLE)
985     {
986         SetWindowPos32( hwnd, 0, 0, 0, 0, 0, SWP_HIDEWINDOW |
987                         SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE|
988                         ((QUEUE_IsExitingQueue(wndPtr->hmemTaskQ))?SWP_DEFERERASE:0) );
989         if (!IsWindow32(hwnd)) return TRUE;
990     }
991
992       /* Recursively destroy owned windows */
993
994     if( !(wndPtr->dwStyle & WS_CHILD) )
995     {
996       /* make sure top menu popup doesn't get destroyed */
997       MENU_PatchResidentPopup( (HQUEUE16)0xFFFF, wndPtr );
998
999       for (;;)
1000       {
1001         WND *siblingPtr = wndPtr->parent->child;  /* First sibling */
1002         while (siblingPtr)
1003         {
1004             if (siblingPtr->owner == wndPtr)
1005             {
1006                if (siblingPtr->hmemTaskQ == wndPtr->hmemTaskQ)
1007                    break;
1008                else 
1009                    siblingPtr->owner = NULL;
1010             }
1011             siblingPtr = siblingPtr->next;
1012         }
1013         if (siblingPtr) DestroyWindow32( siblingPtr->hwndSelf );
1014         else break;
1015       }
1016
1017       if( !Options.managed || EVENT_CheckFocus() )
1018           WINPOS_ActivateOtherWindow(wndPtr);
1019
1020       if( wndPtr->owner &&
1021           wndPtr->owner->hwndLastActive == wndPtr->hwndSelf )
1022           wndPtr->owner->hwndLastActive = wndPtr->owner->hwndSelf;
1023     }
1024
1025       /* Send destroy messages */
1026
1027     WIN_SendDestroyMsg( wndPtr );
1028     if (!IsWindow32(hwnd)) return TRUE;
1029
1030       /* Unlink now so we won't bother with the children later on */
1031
1032     if( wndPtr->parent ) WIN_UnlinkWindow(hwnd);
1033
1034       /* Destroy the window storage */
1035
1036     WIN_DestroyWindow( wndPtr );
1037     return TRUE;
1038 }
1039
1040
1041 /***********************************************************************
1042  *           CloseWindow16   (USER.43)
1043  */
1044 BOOL16 WINAPI CloseWindow16( HWND16 hwnd )
1045 {
1046     return CloseWindow32( hwnd );
1047 }
1048
1049  
1050 /***********************************************************************
1051  *           CloseWindow32   (USER32.56)
1052  */
1053 BOOL32 WINAPI CloseWindow32( HWND32 hwnd )
1054 {
1055     WND * wndPtr = WIN_FindWndPtr( hwnd );
1056     if (!wndPtr || (wndPtr->dwStyle & WS_CHILD)) return FALSE;
1057     ShowWindow32( hwnd, SW_MINIMIZE );
1058     return TRUE;
1059 }
1060
1061  
1062 /***********************************************************************
1063  *           OpenIcon16   (USER.44)
1064  */
1065 BOOL16 WINAPI OpenIcon16( HWND16 hwnd )
1066 {
1067     return OpenIcon32( hwnd );
1068 }
1069
1070
1071 /***********************************************************************
1072  *           OpenIcon32   (USER32.410)
1073  */
1074 BOOL32 WINAPI OpenIcon32( HWND32 hwnd )
1075 {
1076     if (!IsIconic32( hwnd )) return FALSE;
1077     ShowWindow32( hwnd, SW_SHOWNORMAL );
1078     return TRUE;
1079 }
1080
1081
1082 /***********************************************************************
1083  *           WIN_FindWindow
1084  *
1085  * Implementation of FindWindow() and FindWindowEx().
1086  */
1087 static HWND32 WIN_FindWindow( HWND32 parent, HWND32 child, ATOM className,
1088                               LPCSTR title )
1089 {
1090     WND *pWnd;
1091     CLASS *pClass = NULL;
1092
1093     if (child)
1094     {
1095         if (!(pWnd = WIN_FindWndPtr( child ))) return 0;
1096         if (parent)
1097         {
1098             if (!pWnd->parent || (pWnd->parent->hwndSelf != parent)) return 0;
1099         }
1100         else if (pWnd->parent != pWndDesktop) return 0;
1101         pWnd = pWnd->next;
1102     }
1103     else
1104     {
1105         if (!(pWnd = parent ? WIN_FindWndPtr(parent) : pWndDesktop)) return 0;
1106         pWnd = pWnd->child;
1107     }
1108     if (!pWnd) return 0;
1109
1110     /* For a child window, all siblings will have the same hInstance, */
1111     /* so we can look for the class once and for all. */
1112
1113     if (className && (pWnd->dwStyle & WS_CHILD))
1114     {
1115         if (!(pClass = CLASS_FindClassByAtom( className, pWnd->hInstance )))
1116             return 0;
1117     }
1118
1119
1120     for ( ; pWnd; pWnd = pWnd->next)
1121     {
1122         if (className && !(pWnd->dwStyle & WS_CHILD))
1123         {
1124             if (!(pClass = CLASS_FindClassByAtom( className, GetExePtr(pWnd->hInstance))))
1125                 continue;  /* Skip this window */
1126         }
1127
1128         if (pClass && (pWnd->class != pClass))
1129             continue;  /* Not the right class */
1130
1131         /* Now check the title */
1132
1133         if (!title) return pWnd->hwndSelf;
1134         if (pWnd->text && !strcmp( pWnd->text, title )) return pWnd->hwndSelf;
1135     }
1136     return 0;
1137 }
1138
1139
1140
1141 /***********************************************************************
1142  *           FindWindow16   (USER.50)
1143  */
1144 HWND16 WINAPI FindWindow16( SEGPTR className, LPCSTR title )
1145 {
1146     return FindWindowEx16( 0, 0, className, title );
1147 }
1148
1149
1150 /***********************************************************************
1151  *           FindWindowEx16   (USER.427)
1152  */
1153 HWND16 WINAPI FindWindowEx16( HWND16 parent, HWND16 child,
1154                               SEGPTR className, LPCSTR title )
1155 {
1156     ATOM atom = 0;
1157
1158     TRACE(win, "%04x %04x '%s' '%s'\n", parent,
1159                 child, HIWORD(className)?(char *)PTR_SEG_TO_LIN(className):"",
1160                 title ? title : "");
1161
1162     if (className)
1163     {
1164         /* If the atom doesn't exist, then no class */
1165         /* with this name exists either. */
1166         if (!(atom = GlobalFindAtom16( className ))) return 0;
1167     }
1168     return WIN_FindWindow( parent, child, atom, title );
1169 }
1170
1171
1172 /***********************************************************************
1173  *           FindWindow32A   (USER32.198)
1174  */
1175 HWND32 WINAPI FindWindow32A( LPCSTR className, LPCSTR title )
1176 {
1177     HWND32 ret = FindWindowEx32A( 0, 0, className, title );
1178     if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1179     return ret;
1180 }
1181
1182
1183 /***********************************************************************
1184  *           FindWindowEx32A   (USER32.199)
1185  */
1186 HWND32 WINAPI FindWindowEx32A( HWND32 parent, HWND32 child,
1187                                LPCSTR className, LPCSTR title )
1188 {
1189     ATOM atom = 0;
1190
1191     if (className)
1192     {
1193         /* If the atom doesn't exist, then no class */
1194         /* with this name exists either. */
1195         if (!(atom = GlobalFindAtom32A( className ))) 
1196         {
1197             SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1198             return 0;
1199         }
1200     }
1201     return WIN_FindWindow( parent, child, atom, title );
1202 }
1203
1204
1205 /***********************************************************************
1206  *           FindWindowEx32W   (USER32.200)
1207  */
1208 HWND32 WINAPI FindWindowEx32W( HWND32 parent, HWND32 child,
1209                                LPCWSTR className, LPCWSTR title )
1210 {
1211     ATOM atom = 0;
1212     char *buffer;
1213     HWND32 hwnd;
1214
1215     if (className)
1216     {
1217         /* If the atom doesn't exist, then no class */
1218         /* with this name exists either. */
1219         if (!(atom = GlobalFindAtom32W( className )))
1220         {
1221             SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1222             return 0;
1223         }
1224     }
1225     buffer = HEAP_strdupWtoA( GetProcessHeap(), 0, title );
1226     hwnd = WIN_FindWindow( parent, child, atom, buffer );
1227     HeapFree( GetProcessHeap(), 0, buffer );
1228     return hwnd;
1229 }
1230
1231
1232 /***********************************************************************
1233  *           FindWindow32W   (USER32.201)
1234  */
1235 HWND32 WINAPI FindWindow32W( LPCWSTR className, LPCWSTR title )
1236 {
1237     return FindWindowEx32W( 0, 0, className, title );
1238 }
1239
1240
1241 /**********************************************************************
1242  *           WIN_GetDesktop
1243  */
1244 WND *WIN_GetDesktop(void)
1245 {
1246     return pWndDesktop;
1247 }
1248
1249
1250 /**********************************************************************
1251  *           GetDesktopWindow16   (USER.286)
1252  */
1253 HWND16 WINAPI GetDesktopWindow16(void)
1254 {
1255     return (HWND16)pWndDesktop->hwndSelf;
1256 }
1257
1258
1259 /**********************************************************************
1260  *           GetDesktopWindow32   (USER32.232)
1261  */
1262 HWND32 WINAPI GetDesktopWindow32(void)
1263 {
1264     return pWndDesktop->hwndSelf;
1265 }
1266
1267
1268 /**********************************************************************
1269  *           GetDesktopHwnd   (USER.278)
1270  *
1271  * Exactly the same thing as GetDesktopWindow(), but not documented.
1272  * Don't ask me why...
1273  */
1274 HWND16 WINAPI GetDesktopHwnd(void)
1275 {
1276     return (HWND16)pWndDesktop->hwndSelf;
1277 }
1278
1279
1280 /*******************************************************************
1281  *           EnableWindow16   (USER.34)
1282  */
1283 BOOL16 WINAPI EnableWindow16( HWND16 hwnd, BOOL16 enable )
1284 {
1285     return EnableWindow32( hwnd, enable );
1286 }
1287
1288
1289 /*******************************************************************
1290  *           EnableWindow32   (USER32.172)
1291  */
1292 BOOL32 WINAPI EnableWindow32( HWND32 hwnd, BOOL32 enable )
1293 {
1294     WND *wndPtr;
1295
1296     if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
1297     if (enable && (wndPtr->dwStyle & WS_DISABLED))
1298     {
1299           /* Enable window */
1300         wndPtr->dwStyle &= ~WS_DISABLED;
1301         SendMessage32A( hwnd, WM_ENABLE, TRUE, 0 );
1302         return TRUE;
1303     }
1304     else if (!enable && !(wndPtr->dwStyle & WS_DISABLED))
1305     {
1306           /* Disable window */
1307         wndPtr->dwStyle |= WS_DISABLED;
1308         if ((hwnd == GetFocus32()) || IsChild32( hwnd, GetFocus32() ))
1309             SetFocus32( 0 );  /* A disabled window can't have the focus */
1310         if ((hwnd == GetCapture32()) || IsChild32( hwnd, GetCapture32() ))
1311             ReleaseCapture();  /* A disabled window can't capture the mouse */
1312         SendMessage32A( hwnd, WM_ENABLE, FALSE, 0 );
1313         return FALSE;
1314     }
1315     return ((wndPtr->dwStyle & WS_DISABLED) != 0);
1316 }
1317
1318
1319 /***********************************************************************
1320  *           IsWindowEnabled16   (USER.35)
1321  */ 
1322 BOOL16 WINAPI IsWindowEnabled16(HWND16 hWnd)
1323 {
1324     return IsWindowEnabled32(hWnd);
1325 }
1326
1327
1328 /***********************************************************************
1329  *           IsWindowEnabled32   (USER32.349)
1330  */ 
1331 BOOL32 WINAPI IsWindowEnabled32(HWND32 hWnd)
1332 {
1333     WND * wndPtr; 
1334
1335     if (!(wndPtr = WIN_FindWndPtr(hWnd))) return FALSE;
1336     return !(wndPtr->dwStyle & WS_DISABLED);
1337 }
1338
1339
1340 /***********************************************************************
1341  *           IsWindowUnicode   (USER32.350)
1342  */
1343 BOOL32 WINAPI IsWindowUnicode( HWND32 hwnd )
1344 {
1345     WND * wndPtr; 
1346
1347     if (!(wndPtr = WIN_FindWndPtr(hwnd))) return FALSE;
1348     return (WINPROC_GetProcType( wndPtr->winproc ) == WIN_PROC_32W);
1349 }
1350
1351
1352 /**********************************************************************
1353  *           GetWindowWord16    (USER.133)
1354  */
1355 WORD WINAPI GetWindowWord16( HWND16 hwnd, INT16 offset )
1356 {
1357     return GetWindowWord32( hwnd, offset );
1358 }
1359
1360
1361 /**********************************************************************
1362  *           GetWindowWord32    (USER32.314)
1363  */
1364 WORD WINAPI GetWindowWord32( HWND32 hwnd, INT32 offset )
1365 {
1366     WND * wndPtr = WIN_FindWndPtr( hwnd );
1367     if (!wndPtr) return 0;
1368     if (offset >= 0)
1369     {
1370         if (offset + sizeof(WORD) > wndPtr->class->cbWndExtra)
1371         {
1372             WARN( win, "Invalid offset %d\n", offset );
1373             return 0;
1374         }
1375         return *(WORD *)(((char *)wndPtr->wExtra) + offset);
1376     }
1377     switch(offset)
1378     {
1379     case GWW_ID:         
1380         if (HIWORD(wndPtr->wIDmenu))
1381                 WARN( win,"GWW_ID: discards high bits of 0x%08x!\n",
1382                     wndPtr->wIDmenu);
1383         return (WORD)wndPtr->wIDmenu;
1384     case GWW_HWNDPARENT: 
1385         return wndPtr->parent ?
1386                 wndPtr->parent->hwndSelf : (
1387                         wndPtr->owner ?
1388                          wndPtr->owner->hwndSelf : 
1389                          0);
1390     case GWW_HINSTANCE:  
1391         if (HIWORD(wndPtr->hInstance))
1392                 WARN(win,"GWW_HINSTANCE: discards high bits of 0x%08x!\n",
1393                     wndPtr->hInstance);
1394         return (WORD)wndPtr->hInstance;
1395     default:
1396         WARN( win, "Invalid offset %d\n", offset );
1397         return 0;
1398     }
1399 }
1400
1401
1402 /**********************************************************************
1403  *           WIN_GetWindowInstance
1404  */
1405 HINSTANCE32 WIN_GetWindowInstance( HWND32 hwnd )
1406 {
1407     WND * wndPtr = WIN_FindWndPtr( hwnd );
1408     if (!wndPtr) return (HINSTANCE32)0;
1409     return wndPtr->hInstance;
1410 }
1411
1412
1413 /**********************************************************************
1414  *           SetWindowWord16    (USER.134)
1415  */
1416 WORD WINAPI SetWindowWord16( HWND16 hwnd, INT16 offset, WORD newval )
1417 {
1418     return SetWindowWord32( hwnd, offset, newval );
1419 }
1420
1421
1422 /**********************************************************************
1423  *           SetWindowWord32    (USER32.524)
1424  */
1425 WORD WINAPI SetWindowWord32( HWND32 hwnd, INT32 offset, WORD newval )
1426 {
1427     WORD *ptr, retval;
1428     WND * wndPtr = WIN_FindWndPtr( hwnd );
1429     if (!wndPtr) return 0;
1430     if (offset >= 0)
1431     {
1432         if (offset + sizeof(WORD) > wndPtr->class->cbWndExtra)
1433         {
1434             WARN( win, "Invalid offset %d\n", offset );
1435             return 0;
1436         }
1437         ptr = (WORD *)(((char *)wndPtr->wExtra) + offset);
1438     }
1439     else switch(offset)
1440     {
1441         case GWW_ID:        ptr = (WORD *)&wndPtr->wIDmenu; break;
1442         case GWW_HINSTANCE: ptr = (WORD *)&wndPtr->hInstance; break;
1443         case GWW_HWNDPARENT: return SetParent32( hwnd, newval );
1444         default:
1445             WARN( win, "Invalid offset %d\n", offset );
1446             return 0;
1447     }
1448     retval = *ptr;
1449     *ptr = newval;
1450     return retval;
1451 }
1452
1453
1454 /**********************************************************************
1455  *           WIN_GetWindowLong
1456  *
1457  * Helper function for GetWindowLong().
1458  */
1459 static LONG WIN_GetWindowLong( HWND32 hwnd, INT32 offset, WINDOWPROCTYPE type )
1460 {
1461     LONG retval;
1462     WND * wndPtr = WIN_FindWndPtr( hwnd );
1463     if (!wndPtr) return 0;
1464     if (offset >= 0)
1465     {
1466         if (offset + sizeof(LONG) > wndPtr->class->cbWndExtra)
1467         {
1468             WARN( win, "Invalid offset %d\n", offset );
1469             return 0;
1470         }
1471         retval = *(LONG *)(((char *)wndPtr->wExtra) + offset);
1472         /* Special case for dialog window procedure */
1473         if ((offset == DWL_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
1474             return (LONG)WINPROC_GetProc( (HWINDOWPROC)retval, type );
1475         return retval;
1476     }
1477     switch(offset)
1478     {
1479         case GWL_USERDATA:   return wndPtr->userdata;
1480         case GWL_STYLE:      return wndPtr->dwStyle;
1481         case GWL_EXSTYLE:    return wndPtr->dwExStyle;
1482         case GWL_ID:         return (LONG)wndPtr->wIDmenu;
1483         case GWL_WNDPROC:    return (LONG)WINPROC_GetProc( wndPtr->winproc,
1484                                                            type );
1485         case GWL_HWNDPARENT: return wndPtr->parent ?
1486                                         (HWND32)wndPtr->parent->hwndSelf : 0;
1487         case GWL_HINSTANCE:  return wndPtr->hInstance;
1488         default:
1489             WARN( win, "Unknown offset %d\n", offset );
1490     }
1491     return 0;
1492 }
1493
1494
1495 /**********************************************************************
1496  *           WIN_SetWindowLong
1497  *
1498  * Helper function for SetWindowLong().
1499  *
1500  * 0 is the failure code. However, in the case of failure SetLastError
1501  * must be set to distinguish between a 0 return value and a failure.
1502  *
1503  * FIXME: The error values for SetLastError may not be right. Can
1504  *        someone check with the real thing?
1505  */
1506 static LONG WIN_SetWindowLong( HWND32 hwnd, INT32 offset, LONG newval,
1507                                WINDOWPROCTYPE type )
1508 {
1509     LONG *ptr, retval;
1510     WND * wndPtr = WIN_FindWndPtr( hwnd );
1511     STYLESTRUCT style;
1512     
1513     TRACE(win,"%x=%p %x %lx %x\n",hwnd, wndPtr, offset, newval, type);
1514
1515     if (!wndPtr)
1516     {
1517        /* Is this the right error? */
1518        SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1519        return 0;
1520     }
1521
1522     if (offset >= 0)
1523     {
1524         if (offset + sizeof(LONG) > wndPtr->class->cbWndExtra)
1525         {
1526             WARN( win, "Invalid offset %d\n", offset );
1527
1528             /* Is this the right error? */
1529             SetLastError( ERROR_OUTOFMEMORY );
1530
1531             return 0;
1532         }
1533         ptr = (LONG *)(((char *)wndPtr->wExtra) + offset);
1534         /* Special case for dialog window procedure */
1535         if ((offset == DWL_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
1536         {
1537             retval = (LONG)WINPROC_GetProc( (HWINDOWPROC)*ptr, type );
1538             WINPROC_SetProc( (HWINDOWPROC *)ptr, (WNDPROC16)newval, 
1539                              type, WIN_PROC_WINDOW );
1540             return retval;
1541         }
1542     }
1543     else switch(offset)
1544     {
1545         case GWL_ID:
1546                 ptr = (DWORD*)&wndPtr->wIDmenu;
1547                 break;
1548         case GWL_HINSTANCE:
1549                 return SetWindowWord32( hwnd, offset, newval );
1550         case GWL_WNDPROC:
1551                                         retval = (LONG)WINPROC_GetProc( wndPtr->winproc, type );
1552                 WINPROC_SetProc( &wndPtr->winproc, (WNDPROC16)newval, 
1553                                                 type, WIN_PROC_WINDOW );
1554                 return retval;
1555         case GWL_STYLE:
1556                 style.styleOld = wndPtr->dwStyle;
1557                 newval &= ~(WS_VISIBLE | WS_CHILD);     /* Some bits can't be changed this way */
1558                 style.styleNew = newval | (style.styleOld & (WS_VISIBLE | WS_CHILD));
1559
1560                 if (wndPtr->flags & WIN_ISWIN32)
1561                         SendMessage32A(hwnd,WM_STYLECHANGING,GWL_STYLE,(LPARAM)&style);
1562                 wndPtr->dwStyle = style.styleNew;
1563                 if (wndPtr->flags & WIN_ISWIN32)
1564                         SendMessage32A(hwnd,WM_STYLECHANGED,GWL_STYLE,(LPARAM)&style);
1565                 return style.styleOld;
1566                     
1567         case GWL_USERDATA: 
1568                 ptr = &wndPtr->userdata; 
1569                 break;
1570         case GWL_EXSTYLE:  
1571                 style.styleOld = wndPtr->dwExStyle;
1572                 style.styleNew = newval;
1573                 if (wndPtr->flags & WIN_ISWIN32)
1574                         SendMessage32A(hwnd,WM_STYLECHANGING,GWL_EXSTYLE,(LPARAM)&style);
1575                 wndPtr->dwExStyle = newval;
1576                 if (wndPtr->flags & WIN_ISWIN32)
1577                         SendMessage32A(hwnd,WM_STYLECHANGED,GWL_EXSTYLE,(LPARAM)&style);
1578                 return style.styleOld;
1579
1580         default:
1581             WARN( win, "Invalid offset %d\n", offset );
1582
1583             /* Don't think this is right error but it should do */
1584             SetLastError( ERROR_OUTOFMEMORY );
1585
1586             return 0;
1587     }
1588     retval = *ptr;
1589     *ptr = newval;
1590     return retval;
1591 }
1592
1593
1594 /**********************************************************************
1595  *           GetWindowLong16    (USER.135)
1596  */
1597 LONG WINAPI GetWindowLong16( HWND16 hwnd, INT16 offset )
1598 {
1599     return WIN_GetWindowLong( (HWND32)hwnd, offset, WIN_PROC_16 );
1600 }
1601
1602
1603 /**********************************************************************
1604  *           GetWindowLong32A    (USER32.305)
1605  */
1606 LONG WINAPI GetWindowLong32A( HWND32 hwnd, INT32 offset )
1607 {
1608     return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32A );
1609 }
1610
1611
1612 /**********************************************************************
1613  *           GetWindowLong32W    (USER32.306)
1614  */
1615 LONG WINAPI GetWindowLong32W( HWND32 hwnd, INT32 offset )
1616 {
1617     return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32W );
1618 }
1619
1620
1621 /**********************************************************************
1622  *           SetWindowLong16    (USER.136)
1623  */
1624 LONG WINAPI SetWindowLong16( HWND16 hwnd, INT16 offset, LONG newval )
1625 {
1626     return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_16 );
1627 }
1628
1629
1630 /**********************************************************************
1631  *           SetWindowLong32A    (USER32.517)
1632  */
1633 LONG WINAPI SetWindowLong32A( HWND32 hwnd, INT32 offset, LONG newval )
1634 {
1635     return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32A );
1636 }
1637
1638
1639 /**********************************************************************
1640  *           SetWindowLong32W    (USER32.518) Set window attribute
1641  *
1642  * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
1643  * value in a window's extra memory. 
1644  *
1645  * The _hwnd_ parameter specifies the window.  is the handle to a
1646  * window that has extra memory. The _newval_ parameter contains the
1647  * new attribute or extra memory value.  If positive, the _offset_
1648  * parameter is the byte-addressed location in the window's extra
1649  * memory to set.  If negative, _offset_ specifies the window
1650  * attribute to set, and should be one of the following values:
1651  *
1652  * GWL_EXSTYLE      The window's extended window style
1653  *
1654  * GWL_STYLE        The window's window style. 
1655  *
1656  * GWL_WNDPROC      Pointer to the window's window procedure. 
1657  *
1658  * GWL_HINSTANCE    The window's pplication instance handle.
1659  *
1660  * GWL_ID           The window's identifier.
1661  *
1662  * GWL_USERDATA     The window's user-specified data. 
1663  *
1664  * If the window is a dialog box, the _offset_ parameter can be one of 
1665  * the following values:
1666  *
1667  * DWL_DLGPROC      The address of the window's dialog box procedure.
1668  *
1669  * DWL_MSGRESULT    The return value of a message 
1670  *                  that the dialog box procedure processed.
1671  *
1672  * DWL_USER         Application specific information.
1673  *
1674  * RETURNS
1675  *
1676  * If successful, returns the previous value located at _offset_. Otherwise,
1677  * returns 0.
1678  *
1679  * NOTES
1680  *
1681  * Extra memory for a window class is specified by a nonzero cbWndExtra 
1682  * parameter of the WNDCLASS structure passed to RegisterClass() at the
1683  * time of class creation.
1684  *  
1685  * Using GWL_WNDPROC to set a new window procedure effectively creates
1686  * a window subclass. Use CallWindowProc() in the new windows procedure
1687  * to pass messages to the superclass's window procedure.
1688  *
1689  * The user data is reserved for use by the application which created
1690  * the window.
1691  *
1692  * Do not use GWL_STYLE to change the window's WS_DISABLE style;
1693  * instead, call the EnableWindow() function to change the window's
1694  * disabled state.
1695  *
1696  * Do not use GWL_HWNDPARENT to reset the window's parent, use
1697  * SetParent() instead.
1698  *
1699  * BUGS
1700  *
1701  * GWL_STYLE does not dispatch WM_STYLE_... messages.
1702  *
1703  * CONFORMANCE
1704  *
1705  * ECMA-234, Win32 
1706  *
1707  */
1708 LONG WINAPI SetWindowLong32W( 
1709     HWND32 hwnd, /* window to alter */
1710     INT32 offset, /* offset, in bytes, of location to alter */
1711     LONG newval  /* new value of location */
1712 ) {
1713     return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32W );
1714 }
1715
1716
1717 /*******************************************************************
1718  *           GetWindowText16    (USER.36)
1719  */
1720 INT16 WINAPI GetWindowText16( HWND16 hwnd, SEGPTR lpString, INT16 nMaxCount )
1721 {
1722     return (INT16)SendMessage16(hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString);
1723 }
1724
1725
1726 /*******************************************************************
1727  *           GetWindowText32A    (USER32.309)
1728  */
1729 INT32 WINAPI GetWindowText32A( HWND32 hwnd, LPSTR lpString, INT32 nMaxCount )
1730 {
1731     return (INT32)SendMessage32A( hwnd, WM_GETTEXT, nMaxCount,
1732                                   (LPARAM)lpString );
1733 }
1734
1735 /*******************************************************************
1736  *           InternalGetWindowText    (USER32.326)
1737  */
1738 INT32 WINAPI InternalGetWindowText(HWND32 hwnd,LPWSTR lpString,INT32 nMaxCount )
1739 {
1740     FIXME(win,"(0x%08x,%p,0x%x),stub!\n",hwnd,lpString,nMaxCount);
1741     return GetWindowText32W(hwnd,lpString,nMaxCount);
1742 }
1743
1744
1745 /*******************************************************************
1746  *           GetWindowText32W    (USER32.312)
1747  */
1748 INT32 WINAPI GetWindowText32W( HWND32 hwnd, LPWSTR lpString, INT32 nMaxCount )
1749 {
1750     return (INT32)SendMessage32W( hwnd, WM_GETTEXT, nMaxCount,
1751                                   (LPARAM)lpString );
1752 }
1753
1754
1755 /*******************************************************************
1756  *           SetWindowText16    (USER.37)
1757  */
1758 void WINAPI SetWindowText16( HWND16 hwnd, SEGPTR lpString )
1759 {
1760     SendMessage16( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
1761 }
1762
1763
1764 /*******************************************************************
1765  *           SetWindowText32A    (USER32.521)
1766  */
1767 void WINAPI SetWindowText32A( HWND32 hwnd, LPCSTR lpString )
1768 {
1769     SendMessage32A( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
1770 }
1771
1772
1773 /*******************************************************************
1774  *           SetWindowText32W    (USER32.523)
1775  */
1776 void WINAPI SetWindowText32W( HWND32 hwnd, LPCWSTR lpString )
1777 {
1778     SendMessage32W( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
1779 }
1780
1781
1782 /*******************************************************************
1783  *         GetWindowTextLength16    (USER.38)
1784  */
1785 INT16 WINAPI GetWindowTextLength16( HWND16 hwnd )
1786 {
1787     return (INT16)SendMessage16( hwnd, WM_GETTEXTLENGTH, 0, 0 );
1788 }
1789
1790
1791 /*******************************************************************
1792  *         GetWindowTextLength32A   (USER32.310)
1793  */
1794 INT32 WINAPI GetWindowTextLength32A( HWND32 hwnd )
1795 {
1796     return SendMessage32A( hwnd, WM_GETTEXTLENGTH, 0, 0 );
1797 }
1798
1799 /*******************************************************************
1800  *         GetWindowTextLength32W   (USER32.311)
1801  */
1802 INT32 WINAPI GetWindowTextLength32W( HWND32 hwnd )
1803 {
1804     return SendMessage32W( hwnd, WM_GETTEXTLENGTH, 0, 0 );
1805 }
1806
1807
1808 /*******************************************************************
1809  *         IsWindow16   (USER.47)
1810  */
1811 BOOL16 WINAPI IsWindow16( HWND16 hwnd )
1812 {
1813     return IsWindow32( hwnd );
1814 }
1815
1816 void WINAPI WIN16_IsWindow16( CONTEXT *context )
1817 {
1818     WORD *stack = PTR_SEG_OFF_TO_LIN(SS_reg(context), SP_reg(context));
1819     HWND16 hwnd = (HWND16)stack[2];
1820
1821     AX_reg(context) = IsWindow32( hwnd );
1822     ES_reg(context) = USER_HeapSel;
1823 }
1824
1825
1826 /*******************************************************************
1827  *         IsWindow32   (USER32.348)
1828  */
1829 BOOL32 WINAPI IsWindow32( HWND32 hwnd )
1830 {
1831     WND * wndPtr = WIN_FindWndPtr( hwnd );
1832     return ((wndPtr != NULL) && (wndPtr->dwMagic == WND_MAGIC));
1833 }
1834
1835
1836 /*****************************************************************
1837  *         GetParent16   (USER.46)
1838  */
1839 HWND16 WINAPI GetParent16( HWND16 hwnd )
1840 {
1841     return (HWND16)GetParent32( hwnd );
1842 }
1843
1844
1845 /*****************************************************************
1846  *         GetParent32   (USER32.278)
1847  */
1848 HWND32 WINAPI GetParent32( HWND32 hwnd )
1849 {
1850     WND *wndPtr = WIN_FindWndPtr(hwnd);
1851     if ((!wndPtr) || (!(wndPtr->dwStyle & (WS_POPUP|WS_CHILD)))) return 0;
1852     wndPtr = (wndPtr->dwStyle & WS_CHILD) ? wndPtr->parent : wndPtr->owner;
1853     return wndPtr ? wndPtr->hwndSelf : 0;
1854 }
1855
1856 /*****************************************************************
1857  *         WIN_GetTopParent
1858  *
1859  * Get the top-level parent for a child window.
1860  */
1861 WND* WIN_GetTopParentPtr( WND* pWnd )
1862 {
1863     while( pWnd && (pWnd->dwStyle & WS_CHILD)) pWnd = pWnd->parent;
1864     return pWnd;
1865 }
1866
1867 /*****************************************************************
1868  *         WIN_GetTopParent
1869  *
1870  * Get the top-level parent for a child window.
1871  */
1872 HWND32 WIN_GetTopParent( HWND32 hwnd )
1873 {
1874     WND *wndPtr = WIN_GetTopParentPtr ( WIN_FindWndPtr( hwnd ) );
1875     return wndPtr ? wndPtr->hwndSelf : 0;
1876 }
1877
1878
1879 /*****************************************************************
1880  *         SetParent16   (USER.233)
1881  */
1882 HWND16 WINAPI SetParent16( HWND16 hwndChild, HWND16 hwndNewParent )
1883 {
1884     return SetParent32( hwndChild, hwndNewParent );
1885 }
1886
1887
1888 /*****************************************************************
1889  *         SetParent32   (USER32.495)
1890  */
1891 HWND32 WINAPI SetParent32( HWND32 hwndChild, HWND32 hwndNewParent )
1892 {
1893   WND *wndPtr = WIN_FindWndPtr( hwndChild );
1894   WND *pWndNewParent = 
1895     (hwndNewParent) ? WIN_FindWndPtr( hwndNewParent ) : pWndDesktop;
1896   WND *pWndOldParent =
1897     (wndPtr)?(*wndPtr->pDriver->pSetParent)(wndPtr, pWndNewParent):NULL;
1898
1899   return pWndOldParent?pWndOldParent->hwndSelf:0;
1900 }
1901
1902 /*******************************************************************
1903  *         IsChild16    (USER.48)
1904  */
1905 BOOL16 WINAPI IsChild16( HWND16 parent, HWND16 child )
1906 {
1907     return IsChild32(parent,child);
1908 }
1909
1910
1911 /*******************************************************************
1912  *         IsChild32    (USER32.339)
1913  */
1914 BOOL32 WINAPI IsChild32( HWND32 parent, HWND32 child )
1915 {
1916     WND * wndPtr = WIN_FindWndPtr( child );
1917     while (wndPtr && (wndPtr->dwStyle & WS_CHILD))
1918     {
1919         wndPtr = wndPtr->parent;
1920         if (wndPtr->hwndSelf == parent) return TRUE;
1921     }
1922     return FALSE;
1923 }
1924
1925
1926 /***********************************************************************
1927  *           IsWindowVisible16   (USER.49)
1928  */
1929 BOOL16 WINAPI IsWindowVisible16( HWND16 hwnd )
1930 {
1931     return IsWindowVisible32(hwnd);
1932 }
1933
1934
1935 /***********************************************************************
1936  *           IsWindowVisible32   (USER32.351)
1937  */
1938 BOOL32 WINAPI IsWindowVisible32( HWND32 hwnd )
1939 {
1940     WND *wndPtr = WIN_FindWndPtr( hwnd );
1941     while (wndPtr && (wndPtr->dwStyle & WS_CHILD))
1942     {
1943         if (!(wndPtr->dwStyle & WS_VISIBLE)) return FALSE;
1944         wndPtr = wndPtr->parent;
1945     }
1946     return (wndPtr && (wndPtr->dwStyle & WS_VISIBLE));
1947 }
1948
1949
1950 /***********************************************************************
1951  *           WIN_IsWindowDrawable
1952  *
1953  * hwnd is drawable when it is visible, all parents are not
1954  * minimized, and it is itself not minimized unless we are
1955  * trying to draw its default class icon.
1956  */
1957 BOOL32 WIN_IsWindowDrawable( WND* wnd, BOOL32 icon )
1958 {
1959   if( (wnd->dwStyle & WS_MINIMIZE &&
1960        icon && wnd->class->hIcon) ||
1961      !(wnd->dwStyle & WS_VISIBLE) ) return FALSE;
1962   for(wnd = wnd->parent; wnd; wnd = wnd->parent)
1963     if( wnd->dwStyle & WS_MINIMIZE ||
1964       !(wnd->dwStyle & WS_VISIBLE) ) break;
1965   return (wnd == NULL);
1966 }
1967
1968
1969 /*******************************************************************
1970  *         GetTopWindow16    (USER.229)
1971  */
1972 HWND16 WINAPI GetTopWindow16( HWND16 hwnd )
1973 {
1974     return GetTopWindow32(hwnd);
1975 }
1976
1977
1978 /*******************************************************************
1979  *         GetTopWindow32    (USER.229)
1980  */
1981 HWND32 WINAPI GetTopWindow32( HWND32 hwnd )
1982 {
1983     WND * wndPtr = WIN_FindWndPtr( hwnd );
1984     if (wndPtr && wndPtr->child) return wndPtr->child->hwndSelf;
1985     else return 0;
1986 }
1987
1988
1989 /*******************************************************************
1990  *         GetWindow16    (USER.262)
1991  */
1992 HWND16 WINAPI GetWindow16( HWND16 hwnd, WORD rel )
1993 {
1994     return GetWindow32( hwnd,rel );
1995 }
1996
1997
1998 /*******************************************************************
1999  *         GetWindow32    (USER32.302)
2000  */
2001 HWND32 WINAPI GetWindow32( HWND32 hwnd, WORD rel )
2002 {
2003     WND * wndPtr = WIN_FindWndPtr( hwnd );
2004     if (!wndPtr) return 0;
2005     switch(rel)
2006     {
2007     case GW_HWNDFIRST:
2008         if (wndPtr->parent) return wndPtr->parent->child->hwndSelf;
2009         else return 0;
2010         
2011     case GW_HWNDLAST:
2012         if (!wndPtr->parent) return 0;  /* Desktop window */
2013         while (wndPtr->next) wndPtr = wndPtr->next;
2014         return wndPtr->hwndSelf;
2015         
2016     case GW_HWNDNEXT:
2017         if (!wndPtr->next) return 0;
2018         return wndPtr->next->hwndSelf;
2019         
2020     case GW_HWNDPREV:
2021         if (!wndPtr->parent) return 0;  /* Desktop window */
2022         wndPtr = wndPtr->parent->child;  /* First sibling */
2023         if (wndPtr->hwndSelf == hwnd) return 0;  /* First in list */
2024         while (wndPtr->next)
2025         {
2026             if (wndPtr->next->hwndSelf == hwnd) return wndPtr->hwndSelf;
2027             wndPtr = wndPtr->next;
2028         }
2029         return 0;
2030         
2031     case GW_OWNER:
2032         return wndPtr->owner ? wndPtr->owner->hwndSelf : 0;
2033
2034     case GW_CHILD:
2035         return wndPtr->child ? wndPtr->child->hwndSelf : 0;
2036     }
2037     return 0;
2038 }
2039
2040
2041 /*******************************************************************
2042  *         GetNextWindow16    (USER.230)
2043  */
2044 HWND16 WINAPI GetNextWindow16( HWND16 hwnd, WORD flag )
2045 {
2046     if ((flag != GW_HWNDNEXT) && (flag != GW_HWNDPREV)) return 0;
2047     return GetWindow16( hwnd, flag );
2048 }
2049
2050 /*******************************************************************
2051  *         ShowOwnedPopups16  (USER.265)
2052  */
2053 void WINAPI ShowOwnedPopups16( HWND16 owner, BOOL16 fShow )
2054 {
2055     ShowOwnedPopups32( owner, fShow );
2056 }
2057
2058
2059 /*******************************************************************
2060  *         ShowOwnedPopups32  (USER32.531)
2061  */
2062 BOOL32 WINAPI ShowOwnedPopups32( HWND32 owner, BOOL32 fShow )
2063 {
2064     WND *pWnd = pWndDesktop->child;
2065     while (pWnd)
2066     {
2067         if (pWnd->owner && (pWnd->owner->hwndSelf == owner) &&
2068             (pWnd->dwStyle & WS_POPUP))
2069             ShowWindow32( pWnd->hwndSelf, fShow ? SW_SHOW : SW_HIDE );
2070         pWnd = pWnd->next;
2071     }
2072     return TRUE;
2073 }
2074
2075
2076 /*******************************************************************
2077  *         GetLastActivePopup16   (USER.287)
2078  */
2079 HWND16 WINAPI GetLastActivePopup16( HWND16 hwnd )
2080 {
2081     return GetLastActivePopup32( hwnd );
2082 }
2083
2084 /*******************************************************************
2085  *         GetLastActivePopup32   (USER32.256)
2086  */
2087 HWND32 WINAPI GetLastActivePopup32( HWND32 hwnd )
2088 {
2089     WND *wndPtr;
2090     wndPtr = WIN_FindWndPtr(hwnd);
2091     if (wndPtr == NULL) return hwnd;
2092     return wndPtr->hwndLastActive;
2093 }
2094
2095
2096 /*******************************************************************
2097  *           WIN_BuildWinArray
2098  *
2099  * Build an array of pointers to the children of a given window.
2100  * The array must be freed with HeapFree(SystemHeap). Return NULL
2101  * when no windows are found.
2102  */
2103 WND **WIN_BuildWinArray( WND *wndPtr, UINT32 bwaFlags, UINT32* pTotal )
2104 {
2105     WND **list, **ppWnd;
2106     WND *pWnd;
2107     UINT32 count, skipOwned, skipHidden;
2108     DWORD skipFlags;
2109
2110     skipHidden = bwaFlags & BWA_SKIPHIDDEN;
2111     skipOwned = bwaFlags & BWA_SKIPOWNED;
2112     skipFlags = (bwaFlags & BWA_SKIPDISABLED) ? WS_DISABLED : 0;
2113     if( bwaFlags & BWA_SKIPICONIC ) skipFlags |= WS_MINIMIZE;
2114
2115     /* First count the windows */
2116
2117     if (!wndPtr) wndPtr = pWndDesktop;
2118     for (pWnd = wndPtr->child, count = 0; pWnd; pWnd = pWnd->next) 
2119     {
2120         if( (pWnd->dwStyle & skipFlags) || (skipOwned && pWnd->owner) ) continue;
2121         if( !skipHidden || pWnd->dwStyle & WS_VISIBLE ) count++;
2122     }
2123
2124     if( count )
2125     {
2126         /* Now build the list of all windows */
2127
2128         if ((list = (WND **)HeapAlloc( SystemHeap, 0, sizeof(WND *) * (count + 1))))
2129         {
2130             for (pWnd = wndPtr->child, ppWnd = list, count = 0; pWnd; pWnd = pWnd->next)
2131             {
2132                 if( (pWnd->dwStyle & skipFlags) || (skipOwned && pWnd->owner) ) continue;
2133                 if( !skipHidden || pWnd->dwStyle & WS_VISIBLE )
2134                 {
2135                    *ppWnd++ = pWnd;
2136                     count++;
2137                 }
2138             }
2139            *ppWnd = NULL;
2140         }
2141         else count = 0;
2142     } else list = NULL;
2143
2144     if( pTotal ) *pTotal = count;
2145     return list;
2146 }
2147
2148
2149 /*******************************************************************
2150  *           EnumWindows16   (USER.54)
2151  */
2152 BOOL16 WINAPI EnumWindows16( WNDENUMPROC16 lpEnumFunc, LPARAM lParam )
2153 {
2154     WND **list, **ppWnd;
2155
2156     /* We have to build a list of all windows first, to avoid */
2157     /* unpleasant side-effects, for instance if the callback  */
2158     /* function changes the Z-order of the windows.           */
2159
2160     if (!(list = WIN_BuildWinArray( pWndDesktop, 0, NULL ))) return FALSE;
2161
2162     /* Now call the callback function for every window */
2163
2164     for (ppWnd = list; *ppWnd; ppWnd++)
2165     {
2166         /* Make sure that the window still exists */
2167         if (!IsWindow32((*ppWnd)->hwndSelf)) continue;
2168         if (!lpEnumFunc( (*ppWnd)->hwndSelf, lParam )) break;
2169     }
2170     HeapFree( SystemHeap, 0, list );
2171     return TRUE;
2172 }
2173
2174
2175 /*******************************************************************
2176  *           EnumWindows32   (USER32.193)
2177  */
2178 BOOL32 WINAPI EnumWindows32( WNDENUMPROC32 lpEnumFunc, LPARAM lParam )
2179 {
2180     return (BOOL32)EnumWindows16( (WNDENUMPROC16)lpEnumFunc, lParam );
2181 }
2182
2183
2184 /**********************************************************************
2185  *           EnumTaskWindows16   (USER.225)
2186  */
2187 BOOL16 WINAPI EnumTaskWindows16( HTASK16 hTask, WNDENUMPROC16 func,
2188                                  LPARAM lParam )
2189 {
2190     WND **list, **ppWnd;
2191
2192     /* This function is the same as EnumWindows(),    */
2193     /* except for an added check on the window's task. */
2194
2195     if (!(list = WIN_BuildWinArray( pWndDesktop, 0, NULL ))) return FALSE;
2196
2197     /* Now call the callback function for every window */
2198
2199     for (ppWnd = list; *ppWnd; ppWnd++)
2200     {
2201         /* Make sure that the window still exists */
2202         if (!IsWindow32((*ppWnd)->hwndSelf)) continue;
2203         if (QUEUE_GetQueueTask((*ppWnd)->hmemTaskQ) != hTask) continue;
2204         if (!func( (*ppWnd)->hwndSelf, lParam )) break;
2205     }
2206     HeapFree( SystemHeap, 0, list );
2207     return TRUE;
2208 }
2209
2210
2211 /**********************************************************************
2212  *           EnumThreadWindows   (USER32.190)
2213  */
2214 BOOL32 WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC32 func, LPARAM lParam )
2215 {
2216     THDB        *tdb = THREAD_ID_TO_THDB(id);
2217
2218     return (BOOL16)EnumTaskWindows16(tdb->teb.htask16, (WNDENUMPROC16)func, lParam);
2219 }
2220
2221
2222 /**********************************************************************
2223  *           WIN_EnumChildWindows
2224  *
2225  * Helper function for EnumChildWindows().
2226  */
2227 static BOOL16 WIN_EnumChildWindows( WND **ppWnd, WNDENUMPROC16 func,
2228                                     LPARAM lParam )
2229 {
2230     WND **childList;
2231     BOOL16 ret = FALSE;
2232
2233     for ( ; *ppWnd; ppWnd++)
2234     {
2235         /* Make sure that the window still exists */
2236         if (!IsWindow32((*ppWnd)->hwndSelf)) continue;
2237         /* Build children list first */
2238         childList = WIN_BuildWinArray( *ppWnd, BWA_SKIPOWNED, NULL );
2239         ret = func( (*ppWnd)->hwndSelf, lParam );
2240         if (childList)
2241         {
2242             if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
2243             HeapFree( SystemHeap, 0, childList );
2244         }
2245         if (!ret) return FALSE;
2246     }
2247     return TRUE;
2248 }
2249
2250
2251 /**********************************************************************
2252  *           EnumChildWindows16   (USER.55)
2253  */
2254 BOOL16 WINAPI EnumChildWindows16( HWND16 parent, WNDENUMPROC16 func,
2255                                   LPARAM lParam )
2256 {
2257     WND **list, *pParent;
2258
2259     if (!(pParent = WIN_FindWndPtr( parent ))) return FALSE;
2260     if (!(list = WIN_BuildWinArray( pParent, BWA_SKIPOWNED, NULL ))) return FALSE;
2261     WIN_EnumChildWindows( list, func, lParam );
2262     HeapFree( SystemHeap, 0, list );
2263     return TRUE;
2264 }
2265
2266
2267 /**********************************************************************
2268  *           EnumChildWindows32   (USER32.178)
2269  */
2270 BOOL32 WINAPI EnumChildWindows32( HWND32 parent, WNDENUMPROC32 func,
2271                                   LPARAM lParam )
2272 {
2273     return (BOOL32)EnumChildWindows16( (HWND16)parent, (WNDENUMPROC16)func,
2274                                        lParam );
2275 }
2276
2277
2278 /*******************************************************************
2279  *           AnyPopup16   (USER.52)
2280  */
2281 BOOL16 WINAPI AnyPopup16(void)
2282 {
2283     return AnyPopup32();
2284 }
2285
2286
2287 /*******************************************************************
2288  *           AnyPopup32   (USER32.4)
2289  */
2290 BOOL32 WINAPI AnyPopup32(void)
2291 {
2292     WND *wndPtr;
2293     for (wndPtr = pWndDesktop->child; wndPtr; wndPtr = wndPtr->next)
2294         if (wndPtr->owner && (wndPtr->dwStyle & WS_VISIBLE)) return TRUE;
2295     return FALSE;
2296 }
2297
2298
2299 /*******************************************************************
2300  *            FlashWindow16   (USER.105)
2301  */
2302 BOOL16 WINAPI FlashWindow16( HWND16 hWnd, BOOL16 bInvert )
2303 {
2304     return FlashWindow32( hWnd, bInvert );
2305 }
2306
2307
2308 /*******************************************************************
2309  *            FlashWindow32   (USER32.202)
2310  */
2311 BOOL32 WINAPI FlashWindow32( HWND32 hWnd, BOOL32 bInvert )
2312 {
2313     WND *wndPtr = WIN_FindWndPtr(hWnd);
2314
2315     TRACE(win,"%04x\n", hWnd);
2316
2317     if (!wndPtr) return FALSE;
2318
2319     if (wndPtr->dwStyle & WS_MINIMIZE)
2320     {
2321         if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
2322         {
2323             HDC32 hDC = GetDC32(hWnd);
2324             
2325             if (!SendMessage16( hWnd, WM_ERASEBKGND, (WPARAM16)hDC, 0 ))
2326                 wndPtr->flags |= WIN_NEEDS_ERASEBKGND;
2327             
2328             ReleaseDC32( hWnd, hDC );
2329             wndPtr->flags |= WIN_NCACTIVATED;
2330         }
2331         else
2332         {
2333             PAINT_RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE |
2334                                           RDW_UPDATENOW | RDW_FRAME, 0 );
2335             wndPtr->flags &= ~WIN_NCACTIVATED;
2336         }
2337         return TRUE;
2338     }
2339     else
2340     {
2341         WPARAM16 wparam;
2342         if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
2343         else wparam = (hWnd == GetActiveWindow32());
2344
2345         SendMessage16( hWnd, WM_NCACTIVATE, wparam, (LPARAM)0 );
2346         return wparam;
2347     }
2348 }
2349
2350
2351 /*******************************************************************
2352  *           SetSysModalWindow16   (USER.188)
2353  */
2354 HWND16 WINAPI SetSysModalWindow16( HWND16 hWnd )
2355 {
2356     HWND32 hWndOldModal = hwndSysModal;
2357     hwndSysModal = hWnd;
2358     FIXME(win, "EMPTY STUB !! SetSysModalWindow(%04x) !\n", hWnd);
2359     return hWndOldModal;
2360 }
2361
2362
2363 /*******************************************************************
2364  *           GetSysModalWindow16   (USER.52)
2365  */
2366 HWND16 WINAPI GetSysModalWindow16(void)
2367 {
2368     return hwndSysModal;
2369 }
2370
2371
2372 /*******************************************************************
2373  *           GetWindowContextHelpId   (USER32.303)
2374  */
2375 DWORD WINAPI GetWindowContextHelpId( HWND32 hwnd )
2376 {
2377     WND *wnd = WIN_FindWndPtr( hwnd );
2378     if (!wnd) return 0;
2379     return wnd->helpContext;
2380 }
2381
2382
2383 /*******************************************************************
2384  *           SetWindowContextHelpId   (USER32.515)
2385  */
2386 BOOL32 WINAPI SetWindowContextHelpId( HWND32 hwnd, DWORD id )
2387 {
2388     WND *wnd = WIN_FindWndPtr( hwnd );
2389     if (!wnd) return FALSE;
2390     wnd->helpContext = id;
2391     return TRUE;
2392 }
2393
2394
2395 /*******************************************************************
2396  *                      DRAG_QueryUpdate
2397  *
2398  * recursively find a child that contains spDragInfo->pt point 
2399  * and send WM_QUERYDROPOBJECT
2400  */
2401 BOOL16 DRAG_QueryUpdate( HWND32 hQueryWnd, SEGPTR spDragInfo, BOOL32 bNoSend )
2402 {
2403  BOOL16         wParam,bResult = 0;
2404  POINT32        pt;
2405  LPDRAGINFO     ptrDragInfo = (LPDRAGINFO) PTR_SEG_TO_LIN(spDragInfo);
2406  WND           *ptrQueryWnd = WIN_FindWndPtr(hQueryWnd),*ptrWnd;
2407  RECT32         tempRect;
2408
2409  if( !ptrQueryWnd || !ptrDragInfo ) return 0;
2410
2411  CONV_POINT16TO32( &ptrDragInfo->pt, &pt );
2412
2413  GetWindowRect32(hQueryWnd,&tempRect); 
2414
2415  if( !PtInRect32(&tempRect,pt) ||
2416      (ptrQueryWnd->dwStyle & WS_DISABLED) )
2417         return 0;
2418
2419  if( !(ptrQueryWnd->dwStyle & WS_MINIMIZE) ) 
2420    {
2421      tempRect = ptrQueryWnd->rectClient;
2422      if(ptrQueryWnd->dwStyle & WS_CHILD)
2423         MapWindowPoints32( ptrQueryWnd->parent->hwndSelf, 0,
2424                            (LPPOINT32)&tempRect, 2 );
2425
2426      if (PtInRect32( &tempRect, pt))
2427         {
2428          wParam = 0;
2429          
2430          for (ptrWnd = ptrQueryWnd->child; ptrWnd ;ptrWnd = ptrWnd->next)
2431              if( ptrWnd->dwStyle & WS_VISIBLE )
2432              {
2433                  GetWindowRect32( ptrWnd->hwndSelf, &tempRect );
2434                  if (PtInRect32( &tempRect, pt )) break;
2435              }
2436
2437          if(ptrWnd)
2438          {
2439             TRACE(msg,"hwnd = %04x, %d %d - %d %d\n",
2440                         ptrWnd->hwndSelf, ptrWnd->rectWindow.left, ptrWnd->rectWindow.top,
2441                         ptrWnd->rectWindow.right, ptrWnd->rectWindow.bottom );
2442             if( !(ptrWnd->dwStyle & WS_DISABLED) )
2443                 bResult = DRAG_QueryUpdate(ptrWnd->hwndSelf, spDragInfo, bNoSend);
2444          }
2445
2446          if(bResult) return bResult;
2447         }
2448      else wParam = 1;
2449    }
2450  else wParam = 1;
2451
2452  ScreenToClient16(hQueryWnd,&ptrDragInfo->pt);
2453
2454  ptrDragInfo->hScope = hQueryWnd;
2455
2456  bResult = ( bNoSend ) 
2457            ? ptrQueryWnd->dwExStyle & WS_EX_ACCEPTFILES
2458            : SendMessage16( hQueryWnd ,WM_QUERYDROPOBJECT ,
2459                           (WPARAM16)wParam ,(LPARAM) spDragInfo );
2460  if( !bResult ) 
2461      CONV_POINT32TO16( &pt, &ptrDragInfo->pt );
2462
2463  return bResult;
2464 }
2465
2466
2467 /*******************************************************************
2468  *             DragDetect   (USER.465)
2469  */
2470 BOOL16 WINAPI DragDetect16( HWND16 hWnd, POINT16 pt )
2471 {
2472     POINT32 pt32;
2473     CONV_POINT16TO32( &pt, &pt32 );
2474     return DragDetect32( hWnd, pt32 );
2475 }
2476
2477 /*******************************************************************
2478  *             DragDetect32   (USER32.151)
2479  */
2480 BOOL32 WINAPI DragDetect32( HWND32 hWnd, POINT32 pt )
2481 {
2482     MSG16 msg;
2483     RECT16  rect;
2484
2485     rect.left = pt.x - wDragWidth;
2486     rect.right = pt.x + wDragWidth;
2487
2488     rect.top = pt.y - wDragHeight;
2489     rect.bottom = pt.y + wDragHeight;
2490
2491     SetCapture32(hWnd);
2492
2493     while(1)
2494     {
2495         while(PeekMessage16(&msg ,0 ,WM_MOUSEFIRST ,WM_MOUSELAST ,PM_REMOVE))
2496         {
2497             if( msg.message == WM_LBUTTONUP )
2498             {
2499                 ReleaseCapture();
2500                 return 0;
2501             }
2502             if( msg.message == WM_MOUSEMOVE )
2503             {
2504                 if( !PtInRect16( &rect, MAKEPOINT16(msg.lParam) ) )
2505                 {
2506                     ReleaseCapture();
2507                     return 1;
2508                 }
2509             }
2510         }
2511         WaitMessage();
2512     }
2513     return 0;
2514 }
2515
2516 /******************************************************************************
2517  *             DragObject16   (USER.464)
2518  */
2519 DWORD WINAPI DragObject16( HWND16 hwndScope, HWND16 hWnd, UINT16 wObj,
2520                            HANDLE16 hOfStruct, WORD szList, HCURSOR16 hCursor )
2521 {
2522     MSG16       msg;
2523     LPDRAGINFO  lpDragInfo;
2524     SEGPTR      spDragInfo;
2525     HCURSOR16   hDragCursor=0, hOldCursor=0, hBummer=0;
2526     HGLOBAL16   hDragInfo  = GlobalAlloc16( GMEM_SHARE | GMEM_ZEROINIT, 2*sizeof(DRAGINFO));
2527     WND        *wndPtr = WIN_FindWndPtr(hWnd);
2528     HCURSOR16   hCurrentCursor = 0;
2529     HWND16      hCurrentWnd = 0;
2530
2531     lpDragInfo = (LPDRAGINFO) GlobalLock16(hDragInfo);
2532     spDragInfo = (SEGPTR) WIN16_GlobalLock16(hDragInfo);
2533
2534     if( !lpDragInfo || !spDragInfo ) return 0L;
2535
2536     hBummer = LoadCursor16(0, IDC_BUMMER16);
2537
2538     if( !hBummer || !wndPtr )
2539     {
2540         GlobalFree16(hDragInfo);
2541         return 0L;
2542     }
2543
2544     if(hCursor)
2545     {
2546         if( !(hDragCursor = CURSORICON_IconToCursor(hCursor, FALSE)) )
2547         {
2548             GlobalFree16(hDragInfo);
2549             return 0L;
2550         }
2551
2552         if( hDragCursor == hCursor ) hDragCursor = 0;
2553         else hCursor = hDragCursor;
2554
2555         hOldCursor = SetCursor32(hDragCursor);
2556     }
2557
2558     lpDragInfo->hWnd   = hWnd;
2559     lpDragInfo->hScope = 0;
2560     lpDragInfo->wFlags = wObj;
2561     lpDragInfo->hList  = szList; /* near pointer! */
2562     lpDragInfo->hOfStruct = hOfStruct;
2563     lpDragInfo->l = 0L; 
2564
2565     SetCapture32(hWnd);
2566     ShowCursor32( TRUE );
2567
2568     do
2569     {
2570         do{  WaitMessage(); }
2571         while( !PeekMessage16(&msg,0,WM_MOUSEFIRST,WM_MOUSELAST,PM_REMOVE) );
2572
2573        *(lpDragInfo+1) = *lpDragInfo;
2574
2575         lpDragInfo->pt = msg.pt;
2576
2577         /* update DRAGINFO struct */
2578         TRACE(msg,"lpDI->hScope = %04x\n",lpDragInfo->hScope);
2579
2580         if( DRAG_QueryUpdate(hwndScope, spDragInfo, FALSE) > 0 )
2581             hCurrentCursor = hCursor;
2582         else
2583         {
2584             hCurrentCursor = hBummer;
2585             lpDragInfo->hScope = 0;
2586         }
2587         if( hCurrentCursor )
2588             SetCursor32(hCurrentCursor);
2589
2590         /* send WM_DRAGLOOP */
2591         SendMessage16( hWnd, WM_DRAGLOOP, (WPARAM16)(hCurrentCursor != hBummer), 
2592                                           (LPARAM) spDragInfo );
2593         /* send WM_DRAGSELECT or WM_DRAGMOVE */
2594         if( hCurrentWnd != lpDragInfo->hScope )
2595         {
2596             if( hCurrentWnd )
2597                 SendMessage16( hCurrentWnd, WM_DRAGSELECT, 0, 
2598                        (LPARAM)MAKELONG(LOWORD(spDragInfo)+sizeof(DRAGINFO),
2599                                         HIWORD(spDragInfo)) );
2600             hCurrentWnd = lpDragInfo->hScope;
2601             if( hCurrentWnd )
2602                 SendMessage16( hCurrentWnd, WM_DRAGSELECT, 1, (LPARAM)spDragInfo); 
2603         }
2604         else
2605             if( hCurrentWnd )
2606                 SendMessage16( hCurrentWnd, WM_DRAGMOVE, 0, (LPARAM)spDragInfo);
2607
2608     } while( msg.message != WM_LBUTTONUP && msg.message != WM_NCLBUTTONUP );
2609
2610     ReleaseCapture();
2611     ShowCursor32( FALSE );
2612
2613     if( hCursor )
2614     {
2615         SetCursor32( hOldCursor );
2616         if (hDragCursor) DestroyCursor32( hDragCursor );
2617     }
2618
2619     if( hCurrentCursor != hBummer ) 
2620         msg.lParam = SendMessage16( lpDragInfo->hScope, WM_DROPOBJECT, 
2621                                    (WPARAM16)hWnd, (LPARAM)spDragInfo );
2622     else
2623         msg.lParam = 0;
2624     GlobalFree16(hDragInfo);
2625
2626     return (DWORD)(msg.lParam);
2627 }