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