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