~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/user32/win.c

Version: ~ [ wine-1.1.33 ] ~ [ wine-1.1.32 ] ~ [ wine-1.1.31 ] ~ [ wine-1.1.30 ] ~ [ wine-1.1.29 ] ~ [ wine-1.1.28 ] ~ [ wine-1.1.27 ] ~ [ wine-1.1.26 ] ~ [ wine-1.1.25 ] ~ [ wine-1.1.24 ] ~ [ wine-1.1.23 ] ~ [ wine-1.1.22 ] ~ [ wine-1.1.21 ] ~ [ wine-1.1.20 ] ~ [ wine-1.1.19 ] ~ [ wine-1.1.18 ] ~ [ wine-1.1.17 ] ~ [ wine-1.1.16 ] ~ [ wine-1.1.15 ] ~ [ wine-1.1.14 ] ~ [ wine-1.1.13 ] ~ [ wine-1.1.12 ] ~ [ wine-1.1.11 ] ~ [ wine-1.1.10 ] ~ [ wine-1.1.9 ] ~ [ wine-1.1.8 ] ~ [ wine-1.1.7 ] ~ [ wine-1.0.1 ] ~ [ wine-1.1.6 ] ~ [ wine-1.1.5 ] ~ [ wine-1.1.4 ] ~ [ wine-1.1.3 ] ~ [ wine-1.1.2 ] ~ [ wine-1.1.1 ] ~ [ wine-1.1.0 ] ~ [ wine-1.0 ] ~

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