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