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