comctl32: Convert the German resources to UTF-8.
[wine] / dlls / user32 / win.c
1 /*
2  * Window related functions
3  *
4  * Copyright 1993, 1994 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 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 = wine_server_client_ptr( 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       = wine_server_get_ptr( 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 /***********************************************************************
717  *              destroy_thread_window
718  *
719  * Destroy a window upon exit of its thread.
720  */
721 static void destroy_thread_window( HWND hwnd )
722 {
723     WND *wndPtr;
724     HWND *list;
725     HMENU menu = 0, sys_menu = 0;
726     WORD index;
727
728     /* free child windows */
729
730     if ((list = WIN_ListChildren( hwnd )))
731     {
732         int i;
733         for (i = 0; list[i]; i++)
734         {
735             if (WIN_IsCurrentThread( list[i] )) destroy_thread_window( list[i] );
736             else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
737         }
738         HeapFree( GetProcessHeap(), 0, list );
739     }
740
741     /* destroy the client-side storage */
742
743     index = USER_HANDLE_TO_INDEX(hwnd);
744     if (index >= NB_USER_HANDLES) return;
745     USER_Lock();
746     if ((wndPtr = user_handles[index]))
747     {
748         if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD) menu = (HMENU)wndPtr->wIDmenu;
749         sys_menu = wndPtr->hSysMenu;
750         free_dce( wndPtr->dce, hwnd );
751         user_handles[index] = NULL;
752         wndPtr->dwMagic = 0;
753     }
754     USER_Unlock();
755
756     HeapFree( GetProcessHeap(), 0, wndPtr );
757     if (menu) DestroyMenu( menu );
758     if (sys_menu) DestroyMenu( sys_menu );
759 }
760
761
762 /***********************************************************************
763  *              destroy_thread_child_windows
764  *
765  * Destroy child windows upon exit of its thread.
766  */
767 static void destroy_thread_child_windows( HWND hwnd )
768 {
769     HWND *list;
770     int i;
771
772     if (WIN_IsCurrentThread( hwnd ))
773     {
774         destroy_thread_window( hwnd );
775     }
776     else if ((list = WIN_ListChildren( hwnd )))
777     {
778         for (i = 0; list[i]; i++) destroy_thread_child_windows( list[i] );
779         HeapFree( GetProcessHeap(), 0, list );
780     }
781 }
782
783
784 /***********************************************************************
785  *           WIN_DestroyThreadWindows
786  *
787  * Destroy all children of 'wnd' owned by the current thread.
788  */
789 void WIN_DestroyThreadWindows( HWND hwnd )
790 {
791     HWND *list;
792     int i;
793
794     if (!(list = WIN_ListChildren( hwnd ))) return;
795
796     /* reset owners of top-level windows */
797     for (i = 0; list[i]; i++)
798     {
799         if (!WIN_IsCurrentThread( list[i] ))
800         {
801             HWND owner = GetWindow( list[i], GW_OWNER );
802             if (owner && WIN_IsCurrentThread( owner )) WIN_SetOwner( list[i], 0 );
803         }
804     }
805
806     for (i = 0; list[i]; i++) destroy_thread_child_windows( list[i] );
807     HeapFree( GetProcessHeap(), 0, list );
808 }
809
810
811 /***********************************************************************
812  *           WIN_FixCoordinates
813  *
814  * Fix the coordinates - Helper for WIN_CreateWindowEx.
815  * returns default show mode in sw.
816  */
817 static void WIN_FixCoordinates( CREATESTRUCTA *cs, INT *sw)
818 {
819 #define IS_DEFAULT(x)  ((x) == CW_USEDEFAULT || (x) == CW_USEDEFAULT16)
820     POINT pos[2];
821
822     if (cs->dwExStyle & WS_EX_MDICHILD)
823     {
824         UINT id = 0;
825
826         MDI_CalcDefaultChildPos(cs->hwndParent, -1, pos, 0, &id);
827         if (!(cs->style & WS_POPUP)) cs->hMenu = ULongToHandle(id);
828
829         TRACE("MDI child id %04x\n", id);
830     }
831
832     if (cs->style & (WS_CHILD | WS_POPUP))
833     {
834         if (cs->dwExStyle & WS_EX_MDICHILD)
835         {
836             if (IS_DEFAULT(cs->x))
837             {
838                 cs->x = pos[0].x;
839                 cs->y = pos[0].y;
840             }
841             if (IS_DEFAULT(cs->cx) || !cs->cx) cs->cx = pos[1].x;
842             if (IS_DEFAULT(cs->cy) || !cs->cy) cs->cy = pos[1].y;
843         }
844         else
845         {
846             if (IS_DEFAULT(cs->x)) cs->x = cs->y = 0;
847             if (IS_DEFAULT(cs->cx)) cs->cx = cs->cy = 0;
848         }
849     }
850     else  /* overlapped window */
851     {
852         HMONITOR monitor;
853         MONITORINFO mon_info;
854         STARTUPINFOW info;
855
856         if (!IS_DEFAULT(cs->x) && !IS_DEFAULT(cs->cx) && !IS_DEFAULT(cs->cy)) return;
857
858         monitor = MonitorFromWindow( cs->hwndParent, MONITOR_DEFAULTTOPRIMARY );
859         mon_info.cbSize = sizeof(mon_info);
860         GetMonitorInfoW( monitor, &mon_info );
861         GetStartupInfoW( &info );
862
863         if (IS_DEFAULT(cs->x))
864         {
865             if (!IS_DEFAULT(cs->y)) *sw = cs->y;
866             cs->x = (info.dwFlags & STARTF_USEPOSITION) ? info.dwX : mon_info.rcWork.left;
867             cs->y = (info.dwFlags & STARTF_USEPOSITION) ? info.dwY : mon_info.rcWork.top;
868         }
869
870         if (IS_DEFAULT(cs->cx))
871         {
872             if (info.dwFlags & STARTF_USESIZE)
873             {
874                 cs->cx = info.dwXSize;
875                 cs->cy = info.dwYSize;
876             }
877             else
878             {
879                 cs->cx = (mon_info.rcWork.right - mon_info.rcWork.left) * 3 / 4 - cs->x;
880                 cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
881             }
882         }
883         /* neither x nor cx are default. Check the y values .
884          * In the trace we see Outlook and Outlook Express using
885          * cy set to CW_USEDEFAULT when opening the address book.
886          */
887         else if (IS_DEFAULT(cs->cy))
888         {
889             FIXME("Strange use of CW_USEDEFAULT in nHeight\n");
890             cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
891         }
892     }
893 #undef IS_DEFAULT
894 }
895
896 /***********************************************************************
897  *           dump_window_styles
898  */
899 static void dump_window_styles( DWORD style, DWORD exstyle )
900 {
901     TRACE( "style:" );
902     if(style & WS_POPUP) TRACE(" WS_POPUP");
903     if(style & WS_CHILD) TRACE(" WS_CHILD");
904     if(style & WS_MINIMIZE) TRACE(" WS_MINIMIZE");
905     if(style & WS_VISIBLE) TRACE(" WS_VISIBLE");
906     if(style & WS_DISABLED) TRACE(" WS_DISABLED");
907     if(style & WS_CLIPSIBLINGS) TRACE(" WS_CLIPSIBLINGS");
908     if(style & WS_CLIPCHILDREN) TRACE(" WS_CLIPCHILDREN");
909     if(style & WS_MAXIMIZE) TRACE(" WS_MAXIMIZE");
910     if((style & WS_CAPTION) == WS_CAPTION) TRACE(" WS_CAPTION");
911     else
912     {
913         if(style & WS_BORDER) TRACE(" WS_BORDER");
914         if(style & WS_DLGFRAME) TRACE(" WS_DLGFRAME");
915     }
916     if(style & WS_VSCROLL) TRACE(" WS_VSCROLL");
917     if(style & WS_HSCROLL) TRACE(" WS_HSCROLL");
918     if(style & WS_SYSMENU) TRACE(" WS_SYSMENU");
919     if(style & WS_THICKFRAME) TRACE(" WS_THICKFRAME");
920     if (style & WS_CHILD)
921     {
922         if(style & WS_GROUP) TRACE(" WS_GROUP");
923         if(style & WS_TABSTOP) TRACE(" WS_TABSTOP");
924     }
925     else
926     {
927         if(style & WS_MINIMIZEBOX) TRACE(" WS_MINIMIZEBOX");
928         if(style & WS_MAXIMIZEBOX) TRACE(" WS_MAXIMIZEBOX");
929     }
930
931     /* FIXME: Add dumping of BS_/ES_/SBS_/LBS_/CBS_/DS_/etc. styles */
932 #define DUMPED_STYLES \
933     (WS_POPUP | \
934      WS_CHILD | \
935      WS_MINIMIZE | \
936      WS_VISIBLE | \
937      WS_DISABLED | \
938      WS_CLIPSIBLINGS | \
939      WS_CLIPCHILDREN | \
940      WS_MAXIMIZE | \
941      WS_BORDER | \
942      WS_DLGFRAME | \
943      WS_VSCROLL | \
944      WS_HSCROLL | \
945      WS_SYSMENU | \
946      WS_THICKFRAME | \
947      WS_GROUP | \
948      WS_TABSTOP | \
949      WS_MINIMIZEBOX | \
950      WS_MAXIMIZEBOX)
951
952     if(style & ~DUMPED_STYLES) TRACE(" %08lx", style & ~DUMPED_STYLES);
953     TRACE("\n");
954 #undef DUMPED_STYLES
955
956     TRACE( "exstyle:" );
957     if(exstyle & WS_EX_DLGMODALFRAME) TRACE(" WS_EX_DLGMODALFRAME");
958     if(exstyle & WS_EX_DRAGDETECT) TRACE(" WS_EX_DRAGDETECT");
959     if(exstyle & WS_EX_NOPARENTNOTIFY) TRACE(" WS_EX_NOPARENTNOTIFY");
960     if(exstyle & WS_EX_TOPMOST) TRACE(" WS_EX_TOPMOST");
961     if(exstyle & WS_EX_ACCEPTFILES) TRACE(" WS_EX_ACCEPTFILES");
962     if(exstyle & WS_EX_TRANSPARENT) TRACE(" WS_EX_TRANSPARENT");
963     if(exstyle & WS_EX_MDICHILD) TRACE(" WS_EX_MDICHILD");
964     if(exstyle & WS_EX_TOOLWINDOW) TRACE(" WS_EX_TOOLWINDOW");
965     if(exstyle & WS_EX_WINDOWEDGE) TRACE(" WS_EX_WINDOWEDGE");
966     if(exstyle & WS_EX_CLIENTEDGE) TRACE(" WS_EX_CLIENTEDGE");
967     if(exstyle & WS_EX_CONTEXTHELP) TRACE(" WS_EX_CONTEXTHELP");
968     if(exstyle & WS_EX_RIGHT) TRACE(" WS_EX_RIGHT");
969     if(exstyle & WS_EX_RTLREADING) TRACE(" WS_EX_RTLREADING");
970     if(exstyle & WS_EX_LEFTSCROLLBAR) TRACE(" WS_EX_LEFTSCROLLBAR");
971     if(exstyle & WS_EX_CONTROLPARENT) TRACE(" WS_EX_CONTROLPARENT");
972     if(exstyle & WS_EX_STATICEDGE) TRACE(" WS_EX_STATICEDGE");
973     if(exstyle & WS_EX_APPWINDOW) TRACE(" WS_EX_APPWINDOW");
974     if(exstyle & WS_EX_LAYERED) TRACE(" WS_EX_LAYERED");
975
976 #define DUMPED_EX_STYLES \
977     (WS_EX_DLGMODALFRAME | \
978      WS_EX_DRAGDETECT | \
979      WS_EX_NOPARENTNOTIFY | \
980      WS_EX_TOPMOST | \
981      WS_EX_ACCEPTFILES | \
982      WS_EX_TRANSPARENT | \
983      WS_EX_MDICHILD | \
984      WS_EX_TOOLWINDOW | \
985      WS_EX_WINDOWEDGE | \
986      WS_EX_CLIENTEDGE | \
987      WS_EX_CONTEXTHELP | \
988      WS_EX_RIGHT | \
989      WS_EX_RTLREADING | \
990      WS_EX_LEFTSCROLLBAR | \
991      WS_EX_CONTROLPARENT | \
992      WS_EX_STATICEDGE | \
993      WS_EX_APPWINDOW | \
994      WS_EX_LAYERED)
995
996     if(exstyle & ~DUMPED_EX_STYLES) TRACE(" %08lx", exstyle & ~DUMPED_EX_STYLES);
997     TRACE("\n");
998 #undef DUMPED_EX_STYLES
999 }
1000
1001
1002 /***********************************************************************
1003  *           WIN_CreateWindowEx
1004  *
1005  * Implementation of CreateWindowEx().
1006  */
1007 static HWND WIN_CreateWindowEx( CREATESTRUCTA *cs, LPCWSTR className, UINT flags )
1008 {
1009     INT cx, cy, style, sw = SW_SHOW;
1010     LRESULT result;
1011     RECT rect;
1012     WND *wndPtr;
1013     HWND hwnd, parent, owner, top_child = 0;
1014     BOOL unicode = (flags & WIN_ISUNICODE) != 0;
1015     MDICREATESTRUCTA mdi_cs;
1016     CBT_CREATEWNDA cbtc;
1017     CREATESTRUCTA cbcs;
1018
1019     TRACE("%s %s ex=%08x style=%08x %d,%d %dx%d parent=%p menu=%p inst=%p params=%p\n",
1020           unicode ? debugstr_w((LPCWSTR)cs->lpszName) : debugstr_a(cs->lpszName),
1021           debugstr_w(className),
1022           cs->dwExStyle, cs->style, cs->x, cs->y, cs->cx, cs->cy,
1023           cs->hwndParent, cs->hMenu, cs->hInstance, cs->lpCreateParams );
1024     if(TRACE_ON(win)) dump_window_styles( cs->style, cs->dwExStyle );
1025
1026     /* Fix the styles for MDI children */
1027     if (cs->dwExStyle & WS_EX_MDICHILD)
1028     {
1029         UINT flags = 0;
1030
1031         wndPtr = WIN_GetPtr(cs->hwndParent);
1032         if (wndPtr && wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
1033         {
1034             flags = wndPtr->flags;
1035             WIN_ReleasePtr(wndPtr);
1036         }
1037
1038         if (!(flags & WIN_ISMDICLIENT))
1039         {
1040             WARN("WS_EX_MDICHILD, but parent %p is not MDIClient\n", cs->hwndParent);
1041             return 0;
1042         }
1043
1044         /* cs->lpCreateParams of WM_[NC]CREATE is different for MDI children.
1045          * MDICREATESTRUCT members have the originally passed values.
1046          *
1047          * Note: we rely on the fact that MDICREATESTRUCTA and MDICREATESTRUCTW
1048          * have the same layout.
1049          */
1050         mdi_cs.szClass = cs->lpszClass;
1051         mdi_cs.szTitle = cs->lpszName;
1052         mdi_cs.hOwner = cs->hInstance;
1053         mdi_cs.x = cs->x;
1054         mdi_cs.y = cs->y;
1055         mdi_cs.cx = cs->cx;
1056         mdi_cs.cy = cs->cy;
1057         mdi_cs.style = cs->style;
1058         mdi_cs.lParam = (LPARAM)cs->lpCreateParams;
1059
1060         cs->lpCreateParams = &mdi_cs;
1061
1062         if (GetWindowLongW(cs->hwndParent, GWL_STYLE) & MDIS_ALLCHILDSTYLES)
1063         {
1064             if (cs->style & WS_POPUP)
1065             {
1066                 TRACE("WS_POPUP with MDIS_ALLCHILDSTYLES is not allowed\n");
1067                 return 0;
1068             }
1069             cs->style |= WS_CHILD | WS_CLIPSIBLINGS;
1070         }
1071         else
1072         {
1073             cs->style &= ~WS_POPUP;
1074             cs->style |= WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION |
1075                 WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
1076         }
1077
1078         top_child = GetWindow(cs->hwndParent, GW_CHILD);
1079
1080         if (top_child)
1081         {
1082             /* Restore current maximized child */
1083             if((cs->style & WS_VISIBLE) && IsZoomed(top_child))
1084             {
1085                 TRACE("Restoring current maximized child %p\n", top_child);
1086                 SendMessageW( top_child, WM_SETREDRAW, FALSE, 0 );
1087                 ShowWindow( top_child, SW_SHOWNORMAL );
1088                 SendMessageW( top_child, WM_SETREDRAW, TRUE, 0 );
1089             }
1090         }
1091     }
1092
1093     /* Find the parent window */
1094
1095     parent = cs->hwndParent;
1096     owner = 0;
1097
1098     if (cs->hwndParent == HWND_MESSAGE)
1099     {
1100         cs->hwndParent = parent = get_hwnd_message_parent();
1101     }
1102     else if (cs->hwndParent)
1103     {
1104         if ((cs->style & (WS_CHILD|WS_POPUP)) != WS_CHILD)
1105         {
1106             parent = GetDesktopWindow();
1107             owner = cs->hwndParent;
1108         }
1109     }
1110     else
1111     {
1112         static const WCHAR messageW[] = {'M','e','s','s','a','g','e',0};
1113
1114         if ((cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
1115         {
1116             WARN("No parent for child window\n" );
1117             SetLastError(ERROR_TLW_WITH_WSCHILD);
1118             return 0;  /* WS_CHILD needs a parent, but WS_POPUP doesn't */
1119         }
1120         /* are we creating the desktop or HWND_MESSAGE parent itself? */
1121         if (className != (LPCWSTR)DESKTOP_CLASS_ATOM &&
1122             (IS_INTRESOURCE(className) || strcmpiW( className, messageW )))
1123             parent = GetDesktopWindow();
1124     }
1125
1126     WIN_FixCoordinates(cs, &sw); /* fix default coordinates */
1127
1128     if ((cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
1129         ((!(cs->dwExStyle & WS_EX_STATICEDGE)) &&
1130           (cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
1131         cs->dwExStyle |= WS_EX_WINDOWEDGE;
1132     else
1133         cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
1134
1135     /* Create the window structure */
1136
1137     if (!(wndPtr = create_window_handle( parent, owner, className, cs->hInstance, unicode )))
1138         return 0;
1139     hwnd = wndPtr->hwndSelf;
1140
1141     /* Fill the window structure */
1142
1143     wndPtr->tid            = GetCurrentThreadId();
1144     wndPtr->hInstance      = cs->hInstance;
1145     wndPtr->text           = NULL;
1146     wndPtr->dwStyle        = cs->style & ~WS_VISIBLE;
1147     wndPtr->dwExStyle      = cs->dwExStyle;
1148     wndPtr->wIDmenu        = 0;
1149     wndPtr->helpContext    = 0;
1150     wndPtr->pScroll        = NULL;
1151     wndPtr->userdata       = 0;
1152     wndPtr->hIcon          = 0;
1153     wndPtr->hIconSmall     = 0;
1154     wndPtr->hSysMenu       = 0;
1155     wndPtr->flags         |= (flags & WIN_ISWIN32);
1156
1157     wndPtr->min_pos.x = wndPtr->min_pos.y = -1;
1158     wndPtr->max_pos.x = wndPtr->max_pos.y = -1;
1159
1160     if (wndPtr->dwStyle & WS_SYSMENU) SetSystemMenu( hwnd, 0 );
1161
1162     /*
1163      * Correct the window styles.
1164      *
1165      * It affects only the style loaded into the WIN structure.
1166      */
1167
1168     if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1169     {
1170         wndPtr->dwStyle |= WS_CLIPSIBLINGS;
1171         if (!(wndPtr->dwStyle & WS_POPUP))
1172             wndPtr->dwStyle |= WS_CAPTION;
1173     }
1174
1175     /*
1176      * WS_EX_WINDOWEDGE appears to be enforced based on the other styles, so
1177      * why does the user get to set it?
1178      */
1179
1180     if ((wndPtr->dwExStyle & WS_EX_DLGMODALFRAME) ||
1181           (wndPtr->dwStyle & (WS_DLGFRAME | WS_THICKFRAME)))
1182         wndPtr->dwExStyle |= WS_EX_WINDOWEDGE;
1183     else
1184         wndPtr->dwExStyle &= ~WS_EX_WINDOWEDGE;
1185
1186     if (!(wndPtr->dwStyle & (WS_CHILD | WS_POPUP)))
1187         wndPtr->flags |= WIN_NEED_SIZE;
1188
1189     SERVER_START_REQ( set_window_info )
1190     {
1191         req->handle    = wine_server_user_handle( hwnd );
1192         req->flags     = SET_WIN_STYLE | SET_WIN_EXSTYLE | SET_WIN_INSTANCE | SET_WIN_UNICODE;
1193         req->style     = wndPtr->dwStyle;
1194         req->ex_style  = wndPtr->dwExStyle;
1195         req->instance  = wine_server_client_ptr( wndPtr->hInstance );
1196         req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
1197         req->extra_offset = -1;
1198         wine_server_call( req );
1199     }
1200     SERVER_END_REQ;
1201
1202     /* Set the window menu */
1203
1204     if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1205     {
1206         if (cs->hMenu)
1207         {
1208             if (!MENU_SetMenu(hwnd, cs->hMenu))
1209             {
1210                 WIN_ReleasePtr( wndPtr );
1211                 free_window_handle( hwnd );
1212                 return 0;
1213             }
1214         }
1215         else
1216         {
1217             LPCSTR menuName = (LPCSTR)GetClassLongPtrA( hwnd, GCLP_MENUNAME );
1218             if (menuName)
1219             {
1220                 if (!cs->hInstance || HIWORD(cs->hInstance))
1221                     cs->hMenu = LoadMenuA(cs->hInstance,menuName);
1222                 else
1223                     cs->hMenu = HMENU_32(LoadMenu16(HINSTANCE_16(cs->hInstance),menuName));
1224
1225                 if (cs->hMenu) MENU_SetMenu( hwnd, cs->hMenu );
1226             }
1227         }
1228     }
1229     else SetWindowLongPtrW( hwnd, GWLP_ID, (ULONG_PTR)cs->hMenu );
1230
1231     /* call the WH_CBT hook */
1232
1233     /* the window style passed to the hook must be the real window style,
1234      * rather than just the window style that the caller to CreateWindowEx
1235      * passed in, so we have to copy the original CREATESTRUCT and get the
1236      * the real style. */
1237     cbcs = *cs;
1238     cbcs.style = wndPtr->dwStyle;
1239     cbtc.lpcs = &cbcs;
1240     cbtc.hwndInsertAfter = HWND_TOP;
1241     WIN_ReleasePtr( wndPtr );
1242     if (HOOK_CallHooks( WH_CBT, HCBT_CREATEWND, (WPARAM)hwnd, (LPARAM)&cbtc, unicode )) goto failed;
1243
1244     /* send the WM_GETMINMAXINFO message and fix the size if needed */
1245
1246     cx = cs->cx;
1247     cy = cs->cy;
1248     if ((cs->style & WS_THICKFRAME) || !(cs->style & (WS_POPUP | WS_CHILD)))
1249     {
1250         POINT maxSize, maxPos, minTrack, maxTrack;
1251         WINPOS_GetMinMaxInfo( hwnd, &maxSize, &maxPos, &minTrack, &maxTrack);
1252         if (maxTrack.x < cx) cx = maxTrack.x;
1253         if (maxTrack.y < cy) cy = maxTrack.y;
1254         if (minTrack.x > cx) cx = minTrack.x;
1255         if (minTrack.y > cy) cy = minTrack.y;
1256     }
1257
1258     if (cx < 0) cx = 0;
1259     if (cy < 0) cy = 0;
1260     SetRect( &rect, cs->x, cs->y, cs->x + cx, cs->y + cy );
1261     /* check for wraparound */
1262     if (cs->x + cx < cs->x) rect.right = 0x7fffffff;
1263     if (cs->y + cy < cs->y) rect.bottom = 0x7fffffff;
1264     if (!set_window_pos( hwnd, 0, SWP_NOZORDER | SWP_NOACTIVATE, &rect, &rect, NULL )) goto failed;
1265
1266     /* send WM_NCCREATE */
1267
1268     TRACE( "hwnd %p cs %d,%d %dx%d\n", hwnd, cs->x, cs->y, cx, cy );
1269     if (unicode)
1270         result = SendMessageW( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1271     else
1272         result = SendMessageA( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1273     if (!result)
1274     {
1275         WARN( "%p: aborted by WM_NCCREATE\n", hwnd );
1276         goto failed;
1277     }
1278
1279     /* send WM_NCCALCSIZE */
1280
1281     if ((wndPtr = WIN_GetPtr(hwnd)))
1282     {
1283         /* yes, even if the CBT hook was called with HWND_TOP */
1284         POINT pt;
1285         HWND insert_after = (wndPtr->dwStyle & WS_CHILD) ? HWND_BOTTOM : HWND_TOP;
1286         RECT window_rect = wndPtr->rectWindow;
1287         RECT client_rect = window_rect;
1288         WIN_ReleasePtr( wndPtr );
1289
1290         /* the rectangle is in screen coords for WM_NCCALCSIZE when wparam is FALSE */
1291         pt.x = pt.y = 0;
1292         MapWindowPoints( parent, 0, &pt, 1 );
1293         OffsetRect( &client_rect, pt.x, pt.y );
1294         SendMessageW( hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&client_rect );
1295         OffsetRect( &client_rect, -pt.x, -pt.y );
1296         set_window_pos( hwnd, insert_after, SWP_NOACTIVATE, &window_rect, &client_rect, NULL );
1297     }
1298     else return 0;
1299
1300     /* send WM_CREATE */
1301
1302     if (unicode)
1303         result = SendMessageW( hwnd, WM_CREATE, 0, (LPARAM)cs );
1304     else
1305         result = SendMessageA( hwnd, WM_CREATE, 0, (LPARAM)cs );
1306     if (result == -1) goto failed;
1307
1308     /* call the driver */
1309
1310     if (!USER_Driver->pCreateWindow( hwnd )) goto failed;
1311
1312     NotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_WINDOW, 0);
1313
1314     /* send the size messages */
1315
1316     if (!(wndPtr = WIN_GetPtr( hwnd )) ||
1317           wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
1318     if (!(wndPtr->flags & WIN_NEED_SIZE))
1319     {
1320         rect = wndPtr->rectClient;
1321         WIN_ReleasePtr( wndPtr );
1322         SendMessageW( hwnd, WM_SIZE, SIZE_RESTORED,
1323                       MAKELONG(rect.right-rect.left, rect.bottom-rect.top));
1324         SendMessageW( hwnd, WM_MOVE, 0, MAKELONG( rect.left, rect.top ) );
1325     }
1326     else WIN_ReleasePtr( wndPtr );
1327
1328     /* Show the window, maximizing or minimizing if needed */
1329
1330     style = WIN_SetStyle( hwnd, 0, WS_MAXIMIZE | WS_MINIMIZE );
1331     if (style & (WS_MINIMIZE | WS_MAXIMIZE))
1332     {
1333         RECT newPos;
1334         UINT swFlag = (style & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;
1335
1336         swFlag = WINPOS_MinMaximize( hwnd, swFlag, &newPos );
1337         swFlag |= SWP_FRAMECHANGED; /* Frame always gets changed */
1338         if (!(style & WS_VISIBLE) || (style & WS_CHILD) || GetActiveWindow()) swFlag |= SWP_NOACTIVATE;
1339         SetWindowPos( hwnd, 0, newPos.left, newPos.top, newPos.right - newPos.left,
1340                       newPos.bottom - newPos.top, swFlag );
1341     }
1342
1343     /* Notify the parent window only */
1344
1345     send_parent_notify( hwnd, WM_CREATE );
1346     if (!IsWindow( hwnd )) return 0;
1347
1348     if (cs->style & WS_VISIBLE)
1349     {
1350         if (cs->style & WS_MAXIMIZE)
1351             sw = SW_SHOW;
1352         else if (cs->style & WS_MINIMIZE)
1353             sw = SW_SHOWMINIMIZED;
1354
1355         ShowWindow( hwnd, sw );
1356         if (cs->dwExStyle & WS_EX_MDICHILD)
1357         {
1358             SendMessageW(cs->hwndParent, WM_MDIREFRESHMENU, 0, 0);
1359             /* ShowWindow won't activate child windows */
1360             SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE );
1361         }
1362     }
1363
1364     /* Call WH_SHELL hook */
1365
1366     if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1367         HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0, TRUE );
1368
1369     TRACE("created window %p\n", hwnd);
1370     return hwnd;
1371
1372 failed:
1373     WIN_DestroyWindow( hwnd );
1374     return 0;
1375 }
1376
1377
1378 /***********************************************************************
1379  *              CreateWindow (USER.41)
1380  */
1381 HWND16 WINAPI CreateWindow16( LPCSTR className, LPCSTR windowName,
1382                               DWORD style, INT16 x, INT16 y, INT16 width,
1383                               INT16 height, HWND16 parent, HMENU16 menu,
1384                               HINSTANCE16 instance, LPVOID data )
1385 {
1386     return CreateWindowEx16( 0, className, windowName, style,
1387                              x, y, width, height, parent, menu, instance, data );
1388 }
1389
1390
1391 /***********************************************************************
1392  *              CreateWindowEx (USER.452)
1393  */
1394 HWND16 WINAPI CreateWindowEx16( DWORD exStyle, LPCSTR className,
1395                                 LPCSTR windowName, DWORD style, INT16 x,
1396                                 INT16 y, INT16 width, INT16 height,
1397                                 HWND16 parent, HMENU16 menu,
1398                                 HINSTANCE16 instance, LPVOID data )
1399 {
1400     CREATESTRUCTA cs;
1401     char buffer[256];
1402
1403     /* Fix the coordinates */
1404
1405     cs.x  = (x == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)x;
1406     cs.y  = (y == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)y;
1407     cs.cx = (width == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)width;
1408     cs.cy = (height == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)height;
1409
1410     /* Create the window */
1411
1412     cs.lpCreateParams = data;
1413     cs.hInstance      = HINSTANCE_32(instance);
1414     cs.hMenu          = HMENU_32(menu);
1415     cs.hwndParent     = WIN_Handle32( parent );
1416     cs.style          = style;
1417     cs.lpszName       = windowName;
1418     cs.lpszClass      = className;
1419     cs.dwExStyle      = exStyle;
1420
1421     if (!IS_INTRESOURCE(className))
1422     {
1423         WCHAR bufferW[256];
1424
1425         if (!MultiByteToWideChar( CP_ACP, 0, className, -1, bufferW, sizeof(bufferW)/sizeof(WCHAR) ))
1426             return 0;
1427         return HWND_16( WIN_CreateWindowEx( &cs, bufferW, 0 ));
1428     }
1429     else
1430     {
1431         if (!GlobalGetAtomNameA( LOWORD(className), buffer, sizeof(buffer) ))
1432         {
1433             ERR( "bad atom %x\n", LOWORD(className));
1434             return 0;
1435         }
1436         cs.lpszClass = buffer;
1437         return HWND_16( WIN_CreateWindowEx( &cs, (LPCWSTR)className, 0 ));
1438     }
1439 }
1440
1441
1442 /***********************************************************************
1443  *              CreateWindowExA (USER32.@)
1444  */
1445 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1446                                  LPCSTR windowName, DWORD style, INT x,
1447                                  INT y, INT width, INT height,
1448                                  HWND parent, HMENU menu,
1449                                  HINSTANCE instance, LPVOID data )
1450 {
1451     CREATESTRUCTA cs;
1452
1453     cs.lpCreateParams = data;
1454     cs.hInstance      = instance;
1455     cs.hMenu          = menu;
1456     cs.hwndParent     = parent;
1457     cs.x              = x;
1458     cs.y              = y;
1459     cs.cx             = width;
1460     cs.cy             = height;
1461     cs.style          = style;
1462     cs.lpszName       = windowName;
1463     cs.lpszClass      = className;
1464     cs.dwExStyle      = exStyle;
1465
1466     if (!IS_INTRESOURCE(className))
1467     {
1468         WCHAR bufferW[256];
1469         if (!MultiByteToWideChar( CP_ACP, 0, className, -1, bufferW, sizeof(bufferW)/sizeof(WCHAR) ))
1470             return 0;
1471         return WIN_CreateWindowEx( &cs, bufferW, WIN_ISWIN32 );
1472     }
1473     return WIN_CreateWindowEx( &cs, (LPCWSTR)className, WIN_ISWIN32 );
1474 }
1475
1476
1477 /***********************************************************************
1478  *              CreateWindowExW (USER32.@)
1479  */
1480 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1481                                  LPCWSTR windowName, DWORD style, INT x,
1482                                  INT y, INT width, INT height,
1483                                  HWND parent, HMENU menu,
1484                                  HINSTANCE instance, LPVOID data )
1485 {
1486     CREATESTRUCTW cs;
1487
1488     cs.lpCreateParams = data;
1489     cs.hInstance      = instance;
1490     cs.hMenu          = menu;
1491     cs.hwndParent     = parent;
1492     cs.x              = x;
1493     cs.y              = y;
1494     cs.cx             = width;
1495     cs.cy             = height;
1496     cs.style          = style;
1497     cs.lpszName       = windowName;
1498     cs.lpszClass      = className;
1499     cs.dwExStyle      = exStyle;
1500
1501     /* Note: we rely on the fact that CREATESTRUCTA and */
1502     /* CREATESTRUCTW have the same layout. */
1503     return WIN_CreateWindowEx( (CREATESTRUCTA *)&cs, className, WIN_ISWIN32 | WIN_ISUNICODE );
1504 }
1505
1506
1507 /***********************************************************************
1508  *           WIN_SendDestroyMsg
1509  */
1510 static void WIN_SendDestroyMsg( HWND hwnd )
1511 {
1512     GUITHREADINFO info;
1513
1514     if (GetGUIThreadInfo( GetCurrentThreadId(), &info ))
1515     {
1516         if (hwnd == info.hwndCaret) DestroyCaret();
1517         if (hwnd == info.hwndActive) WINPOS_ActivateOtherWindow( hwnd );
1518     }
1519
1520     /*
1521      * Send the WM_DESTROY to the window.
1522      */
1523     SendMessageW( hwnd, WM_DESTROY, 0, 0);
1524
1525     /*
1526      * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1527      * make sure that the window still exists when we come back.
1528      */
1529     if (IsWindow(hwnd))
1530     {
1531         HWND* pWndArray;
1532         int i;
1533
1534         if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1535
1536         for (i = 0; pWndArray[i]; i++)
1537         {
1538             if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1539         }
1540         HeapFree( GetProcessHeap(), 0, pWndArray );
1541     }
1542     else
1543       WARN("\tdestroyed itself while in WM_DESTROY!\n");
1544 }
1545
1546
1547 /***********************************************************************
1548  *              DestroyWindow (USER32.@)
1549  */
1550 BOOL WINAPI DestroyWindow( HWND hwnd )
1551 {
1552     BOOL is_child;
1553
1554     if (!(hwnd = WIN_IsCurrentThread( hwnd )) || is_desktop_window( hwnd ))
1555     {
1556         SetLastError( ERROR_ACCESS_DENIED );
1557         return FALSE;
1558     }
1559
1560     TRACE("(%p)\n", hwnd);
1561
1562       /* Call hooks */
1563
1564     if (HOOK_CallHooks( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0, TRUE )) return FALSE;
1565
1566     if (MENU_IsMenuActive() == hwnd)
1567         EndMenu();
1568
1569     is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;
1570
1571     if (is_child)
1572     {
1573         if (!USER_IsExitingThread( GetCurrentThreadId() ))
1574             send_parent_notify( hwnd, WM_DESTROY );
1575     }
1576     else if (!GetWindow( hwnd, GW_OWNER ))
1577     {
1578         HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
1579         /* FIXME: clean up palette - see "Internals" p.352 */
1580     }
1581
1582     if (!IsWindow(hwnd)) return TRUE;
1583
1584       /* Hide the window */
1585     if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)
1586     {
1587         /* Only child windows receive WM_SHOWWINDOW in DestroyWindow() */
1588         if (is_child)
1589             ShowWindow( hwnd, SW_HIDE );
1590         else
1591             SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE |
1592                           SWP_NOZORDER | SWP_NOACTIVATE | SWP_HIDEWINDOW );
1593     }
1594
1595     if (!IsWindow(hwnd)) return TRUE;
1596
1597       /* Recursively destroy owned windows */
1598
1599     if (!is_child)
1600     {
1601         for (;;)
1602         {
1603             int i, got_one = 0;
1604             HWND *list = WIN_ListChildren( GetDesktopWindow() );
1605             if (list)
1606             {
1607                 for (i = 0; list[i]; i++)
1608                 {
1609                     if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1610                     if (WIN_IsCurrentThread( list[i] ))
1611                     {
1612                         DestroyWindow( list[i] );
1613                         got_one = 1;
1614                         continue;
1615                     }
1616                     WIN_SetOwner( list[i], 0 );
1617                 }
1618                 HeapFree( GetProcessHeap(), 0, list );
1619             }
1620             if (!got_one) break;
1621         }
1622     }
1623
1624       /* Send destroy messages */
1625
1626     WIN_SendDestroyMsg( hwnd );
1627     if (!IsWindow( hwnd )) return TRUE;
1628
1629     if (GetClipboardOwner() == hwnd)
1630         CLIPBOARD_ReleaseOwner();
1631
1632       /* Destroy the window storage */
1633
1634     WIN_DestroyWindow( hwnd );
1635     return TRUE;
1636 }
1637
1638
1639 /***********************************************************************
1640  *              CloseWindow (USER32.@)
1641  */
1642 BOOL WINAPI CloseWindow( HWND hwnd )
1643 {
1644     if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1645     ShowWindow( hwnd, SW_MINIMIZE );
1646     return TRUE;
1647 }
1648
1649
1650 /***********************************************************************
1651  *              OpenIcon (USER32.@)
1652  */
1653 BOOL WINAPI OpenIcon( HWND hwnd )
1654 {
1655     if (!IsIconic( hwnd )) return FALSE;
1656     ShowWindow( hwnd, SW_SHOWNORMAL );
1657     return TRUE;
1658 }
1659
1660
1661 /***********************************************************************
1662  *              FindWindowExW (USER32.@)
1663  */
1664 HWND WINAPI FindWindowExW( HWND parent, HWND child, LPCWSTR className, LPCWSTR title )
1665 {
1666     HWND *list = NULL;
1667     HWND retvalue = 0;
1668     int i = 0, len = 0;
1669     WCHAR *buffer = NULL;
1670
1671     if (!parent && child) parent = GetDesktopWindow();
1672     else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
1673
1674     if (title)
1675     {
1676         len = strlenW(title) + 1;  /* one extra char to check for chars beyond the end */
1677         if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1678     }
1679
1680     if (!(list = list_window_children( 0, parent, className, 0 ))) goto done;
1681
1682     if (child)
1683     {
1684         child = WIN_GetFullHandle( child );
1685         while (list[i] && list[i] != child) i++;
1686         if (!list[i]) goto done;
1687         i++;  /* start from next window */
1688     }
1689
1690     if (title)
1691     {
1692         while (list[i])
1693         {
1694             if (GetWindowTextW( list[i], buffer, len + 1 ) && !strcmpiW( buffer, title )) break;
1695             i++;
1696         }
1697     }
1698     retvalue = list[i];
1699
1700  done:
1701     HeapFree( GetProcessHeap(), 0, list );
1702     HeapFree( GetProcessHeap(), 0, buffer );
1703     return retvalue;
1704 }
1705
1706
1707
1708 /***********************************************************************
1709  *              FindWindowA (USER32.@)
1710  */
1711 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1712 {
1713     HWND ret = FindWindowExA( 0, 0, className, title );
1714     if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1715     return ret;
1716 }
1717
1718
1719 /***********************************************************************
1720  *              FindWindowExA (USER32.@)
1721  */
1722 HWND WINAPI FindWindowExA( HWND parent, HWND child, LPCSTR className, LPCSTR title )
1723 {
1724     LPWSTR titleW = NULL;
1725     HWND hwnd = 0;
1726
1727     if (title)
1728     {
1729         DWORD len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
1730         if (!(titleW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
1731         MultiByteToWideChar( CP_ACP, 0, title, -1, titleW, len );
1732     }
1733
1734     if (!IS_INTRESOURCE(className))
1735     {
1736         WCHAR classW[256];
1737         if (MultiByteToWideChar( CP_ACP, 0, className, -1, classW, sizeof(classW)/sizeof(WCHAR) ))
1738             hwnd = FindWindowExW( parent, child, classW, titleW );
1739     }
1740     else
1741     {
1742         hwnd = FindWindowExW( parent, child, (LPCWSTR)className, titleW );
1743     }
1744
1745     HeapFree( GetProcessHeap(), 0, titleW );
1746     return hwnd;
1747 }
1748
1749
1750 /***********************************************************************
1751  *              FindWindowW (USER32.@)
1752  */
1753 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
1754 {
1755     return FindWindowExW( 0, 0, className, title );
1756 }
1757
1758
1759 /**********************************************************************
1760  *              GetDesktopWindow (USER32.@)
1761  */
1762 HWND WINAPI GetDesktopWindow(void)
1763 {
1764     struct user_thread_info *thread_info = get_user_thread_info();
1765
1766     if (thread_info->top_window) return thread_info->top_window;
1767
1768     SERVER_START_REQ( get_desktop_window )
1769     {
1770         req->force = 0;
1771         if (!wine_server_call( req ))
1772         {
1773             thread_info->top_window = wine_server_ptr_handle( reply->top_window );
1774             thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
1775         }
1776     }
1777     SERVER_END_REQ;
1778
1779     if (!thread_info->top_window)
1780     {
1781         USEROBJECTFLAGS flags;
1782         if (!GetUserObjectInformationW( GetProcessWindowStation(), UOI_FLAGS, &flags,
1783                                         sizeof(flags), NULL ) || (flags.dwFlags & WSF_VISIBLE))
1784         {
1785             static const WCHAR command_line[] = {'\\','e','x','p','l','o','r','e','r','.','e','x','e',' ','/','d','e','s','k','t','o','p',0};
1786             STARTUPINFOW si;
1787             PROCESS_INFORMATION pi;
1788             WCHAR cmdline[MAX_PATH + sizeof(command_line)/sizeof(WCHAR)];
1789
1790             memset( &si, 0, sizeof(si) );
1791             si.cb = sizeof(si);
1792             si.dwFlags = STARTF_USESTDHANDLES;
1793             si.hStdInput  = 0;
1794             si.hStdOutput = 0;
1795             si.hStdError  = GetStdHandle( STD_ERROR_HANDLE );
1796
1797             GetSystemDirectoryW( cmdline, MAX_PATH );
1798             lstrcatW( cmdline, command_line );
1799             if (CreateProcessW( NULL, cmdline, NULL, NULL, FALSE, DETACHED_PROCESS,
1800                                 NULL, NULL, &si, &pi ))
1801             {
1802                 TRACE( "started explorer pid %04x tid %04x\n", pi.dwProcessId, pi.dwThreadId );
1803                 WaitForInputIdle( pi.hProcess, 10000 );
1804                 CloseHandle( pi.hThread );
1805                 CloseHandle( pi.hProcess );
1806             }
1807             else WARN( "failed to start explorer, err %d\n", GetLastError() );
1808         }
1809         else TRACE( "not starting explorer since winstation is not visible\n" );
1810
1811         SERVER_START_REQ( get_desktop_window )
1812         {
1813             req->force = 1;
1814             if (!wine_server_call( req ))
1815             {
1816                 thread_info->top_window = wine_server_ptr_handle( reply->top_window );
1817                 thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
1818             }
1819         }
1820         SERVER_END_REQ;
1821     }
1822
1823     if (!thread_info->top_window || !USER_Driver->pCreateDesktopWindow( thread_info->top_window ))
1824         ERR( "failed to create desktop window\n" );
1825
1826     return thread_info->top_window;
1827 }
1828
1829
1830 /*******************************************************************
1831  *              EnableWindow (USER32.@)
1832  */
1833 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
1834 {
1835     BOOL retvalue;
1836     HWND full_handle;
1837
1838     if (is_broadcast(hwnd))
1839     {
1840         SetLastError( ERROR_INVALID_PARAMETER );
1841         return FALSE;
1842     }
1843
1844     if (!(full_handle = WIN_IsCurrentThread( hwnd )))
1845         return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
1846
1847     hwnd = full_handle;
1848
1849     TRACE("( %p, %d )\n", hwnd, enable);
1850
1851     retvalue = !IsWindowEnabled( hwnd );
1852
1853     if (enable && retvalue)
1854     {
1855         WIN_SetStyle( hwnd, 0, WS_DISABLED );
1856         SendMessageW( hwnd, WM_ENABLE, TRUE, 0 );
1857     }
1858     else if (!enable && !retvalue)
1859     {
1860         HWND capture_wnd;
1861
1862         SendMessageW( hwnd, WM_CANCELMODE, 0, 0);
1863
1864         WIN_SetStyle( hwnd, WS_DISABLED, 0 );
1865
1866         if (hwnd == GetFocus())
1867             SetFocus( 0 );  /* A disabled window can't have the focus */
1868
1869         capture_wnd = GetCapture();
1870         if (hwnd == capture_wnd || IsChild(hwnd, capture_wnd))
1871             ReleaseCapture();  /* A disabled window can't capture the mouse */
1872
1873         SendMessageW( hwnd, WM_ENABLE, FALSE, 0 );
1874     }
1875     return retvalue;
1876 }
1877
1878
1879 /***********************************************************************
1880  *              IsWindowEnabled (USER32.@)
1881  */
1882 BOOL WINAPI IsWindowEnabled(HWND hWnd)
1883 {
1884     return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
1885 }
1886
1887
1888 /***********************************************************************
1889  *              IsWindowUnicode (USER32.@)
1890  */
1891 BOOL WINAPI IsWindowUnicode( HWND hwnd )
1892 {
1893     WND * wndPtr;
1894     BOOL retvalue = FALSE;
1895
1896     if (!(wndPtr = WIN_GetPtr(hwnd))) return FALSE;
1897
1898     if (wndPtr == WND_DESKTOP) return TRUE;
1899
1900     if (wndPtr != WND_OTHER_PROCESS)
1901     {
1902         retvalue = (wndPtr->flags & WIN_ISUNICODE) != 0;
1903         WIN_ReleasePtr( wndPtr );
1904     }
1905     else
1906     {
1907         SERVER_START_REQ( get_window_info )
1908         {
1909             req->handle = wine_server_user_handle( hwnd );
1910             if (!wine_server_call_err( req )) retvalue = reply->is_unicode;
1911         }
1912         SERVER_END_REQ;
1913     }
1914     return retvalue;
1915 }
1916
1917
1918 /**********************************************************************
1919  *           WIN_GetWindowLong
1920  *
1921  * Helper function for GetWindowLong().
1922  */
1923 static LONG_PTR WIN_GetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicode )
1924 {
1925     LONG_PTR retvalue = 0;
1926     WND *wndPtr;
1927
1928     if (offset == GWLP_HWNDPARENT)
1929     {
1930         HWND parent = GetAncestor( hwnd, GA_PARENT );
1931         if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
1932         return (ULONG_PTR)parent;
1933     }
1934
1935     if (!(wndPtr = WIN_GetPtr( hwnd )))
1936     {
1937         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1938         return 0;
1939     }
1940
1941     if (wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP)
1942     {
1943         if (offset == GWLP_WNDPROC)
1944         {
1945             SetLastError( ERROR_ACCESS_DENIED );
1946             return 0;
1947         }
1948         SERVER_START_REQ( set_window_info )
1949         {
1950             req->handle = wine_server_user_handle( hwnd );
1951             req->flags  = 0;  /* don't set anything, just retrieve */
1952             req->extra_offset = (offset >= 0) ? offset : -1;
1953             req->extra_size = (offset >= 0) ? size : 0;
1954             if (!wine_server_call_err( req ))
1955             {
1956                 switch(offset)
1957                 {
1958                 case GWL_STYLE:      retvalue = reply->old_style; break;
1959                 case GWL_EXSTYLE:    retvalue = reply->old_ex_style; break;
1960                 case GWLP_ID:        retvalue = reply->old_id; break;
1961                 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wine_server_get_ptr( reply->old_instance ); break;
1962                 case GWLP_USERDATA:  retvalue = reply->old_user_data; break;
1963                 default:
1964                     if (offset >= 0) retvalue = get_win_data( &reply->old_extra_value, size );
1965                     else SetLastError( ERROR_INVALID_INDEX );
1966                     break;
1967                 }
1968             }
1969         }
1970         SERVER_END_REQ;
1971         return retvalue;
1972     }
1973
1974     /* now we have a valid wndPtr */
1975
1976     if (offset >= 0)
1977     {
1978         if (offset > (int)(wndPtr->cbWndExtra - size))
1979         {
1980             WARN("Invalid offset %d\n", offset );
1981             WIN_ReleasePtr( wndPtr );
1982             SetLastError( ERROR_INVALID_INDEX );
1983             return 0;
1984         }
1985         retvalue = get_win_data( (char *)wndPtr->wExtra + offset, size );
1986
1987         /* Special case for dialog window procedure */
1988         if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && (wndPtr->flags & WIN_ISDIALOG))
1989             retvalue = (LONG_PTR)WINPROC_GetProc( (WNDPROC)retvalue, unicode );
1990         WIN_ReleasePtr( wndPtr );
1991         return retvalue;
1992     }
1993
1994     switch(offset)
1995     {
1996     case GWLP_USERDATA:  retvalue = wndPtr->userdata; break;
1997     case GWL_STYLE:      retvalue = wndPtr->dwStyle; break;
1998     case GWL_EXSTYLE:    retvalue = wndPtr->dwExStyle; break;
1999     case GWLP_ID:        retvalue = wndPtr->wIDmenu; break;
2000     case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hInstance; break;
2001     case GWLP_WNDPROC:
2002         /* This looks like a hack only for the edit control (see tests). This makes these controls
2003          * more tolerant to A/W mismatches. The lack of W->A->W conversion for such a mismatch suggests
2004          * that the hack is in GetWindowLongPtr[AW], not in winprocs.
2005          */
2006         if (wndPtr->winproc == EDIT_winproc_handle && (!unicode != !(wndPtr->flags & WIN_ISUNICODE)))
2007             retvalue = (ULONG_PTR)wndPtr->winproc;
2008         else
2009             retvalue = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, unicode );
2010         break;
2011     default:
2012         WARN("Unknown offset %d\n", offset );
2013         SetLastError( ERROR_INVALID_INDEX );
2014         break;
2015     }
2016     WIN_ReleasePtr(wndPtr);
2017     return retvalue;
2018 }
2019
2020
2021 /**********************************************************************
2022  *           WIN_SetWindowLong
2023  *
2024  * Helper function for SetWindowLong().
2025  *
2026  * 0 is the failure code. However, in the case of failure SetLastError
2027  * must be set to distinguish between a 0 return value and a failure.
2028  */
2029 LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, UINT size, LONG_PTR newval, BOOL unicode )
2030 {
2031     STYLESTRUCT style;
2032     BOOL ok;
2033     LONG_PTR retval = 0;
2034     WND *wndPtr;
2035
2036     TRACE( "%p %d %lx %c\n", hwnd, offset, newval, unicode ? 'W' : 'A' );
2037
2038     if (is_broadcast(hwnd))
2039     {
2040         SetLastError( ERROR_INVALID_PARAMETER );
2041         return FALSE;
2042     }
2043
2044     if (!(wndPtr = WIN_GetPtr( hwnd )))
2045     {
2046         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2047         return 0;
2048     }
2049     if (wndPtr == WND_DESKTOP)
2050     {
2051         /* can't change anything on the desktop window */
2052         SetLastError( ERROR_ACCESS_DENIED );
2053         return 0;
2054     }
2055     if (wndPtr == WND_OTHER_PROCESS)
2056     {
2057         if (offset == GWLP_WNDPROC)
2058         {
2059             SetLastError( ERROR_ACCESS_DENIED );
2060             return 0;
2061         }
2062         if (offset > 32767 || offset < -32767)
2063         {
2064             SetLastError( ERROR_INVALID_INDEX );
2065             return 0;
2066         }
2067         return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, MAKEWPARAM( offset, size ), newval );
2068     }
2069
2070     /* first some special cases */
2071     switch( offset )
2072     {
2073     case GWL_STYLE:
2074     case GWL_EXSTYLE:
2075         style.styleOld =
2076             offset == GWL_STYLE ? wndPtr->dwStyle : wndPtr->dwExStyle;
2077         style.styleNew = newval;
2078         WIN_ReleasePtr( wndPtr );
2079         SendMessageW( hwnd, WM_STYLECHANGING, offset, (LPARAM)&style );
2080         if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2081         newval = style.styleNew;
2082         break;
2083     case GWLP_HWNDPARENT:
2084         if (wndPtr->parent == GetDesktopWindow())
2085         {
2086             WIN_ReleasePtr( wndPtr );
2087             return (ULONG_PTR)WIN_SetOwner( hwnd, (HWND)newval );
2088         }
2089         else
2090         {
2091             WIN_ReleasePtr( wndPtr );
2092             return (ULONG_PTR)SetParent( hwnd, (HWND)newval );
2093         }
2094     case GWLP_WNDPROC:
2095     {
2096         WNDPROC proc;
2097         UINT old_flags = wndPtr->flags;
2098         retval = WIN_GetWindowLong( hwnd, offset, size, unicode );
2099         if (unicode) proc = WINPROC_AllocProc( NULL, (WNDPROC)newval );
2100         else proc = WINPROC_AllocProc( (WNDPROC)newval, NULL );
2101         if (proc) wndPtr->winproc = proc;
2102         if (WINPROC_IsUnicode( proc, unicode )) wndPtr->flags |= WIN_ISUNICODE;
2103         else wndPtr->flags &= ~WIN_ISUNICODE;
2104         if (!((old_flags ^ wndPtr->flags) & WIN_ISUNICODE))
2105         {
2106             WIN_ReleasePtr( wndPtr );
2107             return retval;
2108         }
2109         /* update is_unicode flag on the server side */
2110         break;
2111     }
2112     case GWLP_ID:
2113     case GWLP_HINSTANCE:
2114     case GWLP_USERDATA:
2115         break;
2116     case DWLP_DLGPROC:
2117         if ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
2118             (size == sizeof(LONG_PTR)) && (wndPtr->flags & WIN_ISDIALOG))
2119         {
2120             WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWLP_DLGPROC);
2121             retval = (ULONG_PTR)WINPROC_GetProc( *ptr, unicode );
2122             if (unicode) *ptr = WINPROC_AllocProc( NULL, (WNDPROC)newval );
2123             else *ptr = WINPROC_AllocProc( (WNDPROC)newval, NULL );
2124             WIN_ReleasePtr( wndPtr );
2125             return retval;
2126         }
2127         /* fall through */
2128     default:
2129         if (offset < 0 || offset > (int)(wndPtr->cbWndExtra - size))
2130         {
2131             WARN("Invalid offset %d\n", offset );
2132             WIN_ReleasePtr( wndPtr );
2133             SetLastError( ERROR_INVALID_INDEX );
2134             return 0;
2135         }
2136         else if (get_win_data( (char *)wndPtr->wExtra + offset, size ) == newval)
2137         {
2138             /* already set to the same value */
2139             WIN_ReleasePtr( wndPtr );
2140             return newval;
2141         }
2142         break;
2143     }
2144
2145     SERVER_START_REQ( set_window_info )
2146     {
2147         req->handle = wine_server_user_handle( hwnd );
2148         req->extra_offset = -1;
2149         switch(offset)
2150         {
2151         case GWL_STYLE:
2152             req->flags = SET_WIN_STYLE;
2153             req->style = newval;
2154             break;
2155         case GWL_EXSTYLE:
2156             req->flags = SET_WIN_EXSTYLE;
2157             /* WS_EX_TOPMOST can only be changed through SetWindowPos */
2158             newval = (newval & ~WS_EX_TOPMOST) | (wndPtr->dwExStyle & WS_EX_TOPMOST);
2159             req->ex_style = newval;
2160             break;
2161         case GWLP_ID:
2162             req->flags = SET_WIN_ID;
2163             req->id = newval;
2164             break;
2165         case GWLP_HINSTANCE:
2166             req->flags = SET_WIN_INSTANCE;
2167             req->instance = wine_server_client_ptr( (void *)newval );
2168             break;
2169         case GWLP_WNDPROC:
2170             req->flags = SET_WIN_UNICODE;
2171             req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
2172             break;
2173         case GWLP_USERDATA:
2174             req->flags = SET_WIN_USERDATA;
2175             req->user_data = newval;
2176             break;
2177         default:
2178             req->flags = SET_WIN_EXTRA;
2179             req->extra_offset = offset;
2180             req->extra_size = size;
2181             set_win_data( &req->extra_value, newval, size );
2182         }
2183         if ((ok = !wine_server_call_err( req )))
2184         {
2185             switch(offset)
2186             {
2187             case GWL_STYLE:
2188                 wndPtr->dwStyle = newval;
2189                 retval = reply->old_style;
2190                 break;
2191             case GWL_EXSTYLE:
2192                 wndPtr->dwExStyle = newval;
2193                 retval = reply->old_ex_style;
2194                 break;
2195             case GWLP_ID:
2196                 wndPtr->wIDmenu = newval;
2197                 retval = reply->old_id;
2198                 break;
2199             case GWLP_HINSTANCE:
2200                 wndPtr->hInstance = (HINSTANCE)newval;
2201                 retval = (ULONG_PTR)wine_server_get_ptr( reply->old_instance );
2202                 break;
2203             case GWLP_WNDPROC:
2204                 break;
2205             case GWLP_USERDATA:
2206                 wndPtr->userdata = newval;
2207                 retval = reply->old_user_data;
2208                 break;
2209             default:
2210                 retval = get_win_data( (char *)wndPtr->wExtra + offset, size );
2211                 set_win_data( (char *)wndPtr->wExtra + offset, newval, size );
2212                 break;
2213             }
2214         }
2215     }
2216     SERVER_END_REQ;
2217     WIN_ReleasePtr( wndPtr );
2218
2219     if (!ok) return 0;
2220
2221     if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2222     {
2223         USER_Driver->pSetWindowStyle( hwnd, offset, &style );
2224         SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2225     }
2226
2227     return retval;
2228 }
2229
2230
2231 /**********************************************************************
2232  *              GetWindowLong (USER.135)
2233  */
2234 LONG WINAPI GetWindowLong16( HWND16 hwnd, INT16 offset )
2235 {
2236     WND *wndPtr;
2237     LONG_PTR retvalue;
2238     BOOL is_winproc = (offset == GWLP_WNDPROC);
2239
2240     if (offset >= 0)
2241     {
2242         if (!(wndPtr = WIN_GetPtr( WIN_Handle32(hwnd) )))
2243         {
2244             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2245             return 0;
2246         }
2247         if (wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
2248         {
2249             if (offset > (int)(wndPtr->cbWndExtra - sizeof(LONG)))
2250             {
2251                 /*
2252                  * Some programs try to access last element from 16 bit
2253                  * code using illegal offset value. Hopefully this is
2254                  * what those programs really expect.
2255                  */
2256                 if (wndPtr->cbWndExtra >= 4 && offset == wndPtr->cbWndExtra - sizeof(WORD))
2257                 {
2258                     INT offset2 = wndPtr->cbWndExtra - sizeof(LONG);
2259                     ERR( "- replaced invalid offset %d with %d\n", offset, offset2 );
2260                     offset = offset2;
2261                 }
2262                 else
2263                 {
2264                     WARN("Invalid offset %d\n", offset );
2265                     WIN_ReleasePtr( wndPtr );
2266                     SetLastError( ERROR_INVALID_INDEX );
2267                     return 0;
2268                 }
2269             }
2270             is_winproc = ((offset == DWLP_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG));
2271             WIN_ReleasePtr( wndPtr );
2272         }
2273     }
2274     retvalue = GetWindowLongA( WIN_Handle32(hwnd), offset );
2275     if (is_winproc) retvalue = (LONG_PTR)WINPROC_GetProc16( (WNDPROC)retvalue, FALSE );
2276     return retvalue;
2277 }
2278
2279
2280 /**********************************************************************
2281  *              GetWindowWord (USER32.@)
2282  */
2283 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
2284 {
2285     switch(offset)
2286     {
2287     case GWLP_ID:
2288     case GWLP_HINSTANCE:
2289     case GWLP_HWNDPARENT:
2290         break;
2291     default:
2292         if (offset < 0)
2293         {
2294             WARN("Invalid offset %d\n", offset );
2295             SetLastError( ERROR_INVALID_INDEX );
2296             return 0;
2297         }
2298         break;
2299     }
2300     return WIN_GetWindowLong( hwnd, offset, sizeof(WORD), FALSE );
2301 }
2302
2303
2304 /**********************************************************************
2305  *              GetWindowLongA (USER32.@)
2306  */
2307 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2308 {
2309     return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), FALSE );
2310 }
2311
2312
2313 /**********************************************************************
2314  *              GetWindowLongW (USER32.@)
2315  */
2316 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2317 {
2318     return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), TRUE );
2319 }
2320
2321
2322 /**********************************************************************
2323  *              SetWindowLong (USER.136)
2324  */
2325 LONG WINAPI SetWindowLong16( HWND16 hwnd, INT16 offset, LONG newval )
2326 {
2327     WND *wndPtr;
2328     BOOL is_winproc = (offset == GWLP_WNDPROC);
2329
2330     if (offset == DWLP_DLGPROC)
2331     {
2332         if (!(wndPtr = WIN_GetPtr( WIN_Handle32(hwnd) )))
2333         {
2334             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2335             return 0;
2336         }
2337         if (wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
2338         {
2339             is_winproc = ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
2340                           (wndPtr->flags & WIN_ISDIALOG));
2341             WIN_ReleasePtr( wndPtr );
2342         }
2343     }
2344
2345     if (is_winproc)
2346     {
2347         WNDPROC new_proc = WINPROC_AllocProc16( (WNDPROC16)newval );
2348         WNDPROC old_proc = (WNDPROC)SetWindowLongPtrA( WIN_Handle32(hwnd), offset, (LONG_PTR)new_proc );
2349         return (LONG)WINPROC_GetProc16( old_proc, FALSE );
2350     }
2351     else return SetWindowLongA( WIN_Handle32(hwnd), offset, newval );
2352 }
2353
2354
2355 /**********************************************************************
2356  *              SetWindowWord (USER32.@)
2357  */
2358 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
2359 {
2360     switch(offset)
2361     {
2362     case GWLP_ID:
2363     case GWLP_HINSTANCE:
2364     case GWLP_HWNDPARENT:
2365         break;
2366     default:
2367         if (offset < 0)
2368         {
2369             WARN("Invalid offset %d\n", offset );
2370             SetLastError( ERROR_INVALID_INDEX );
2371             return 0;
2372         }
2373         break;
2374     }
2375     return WIN_SetWindowLong( hwnd, offset, sizeof(WORD), newval, FALSE );
2376 }
2377
2378
2379 /**********************************************************************
2380  *              SetWindowLongA (USER32.@)
2381  *
2382  * See SetWindowLongW.
2383  */
2384 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2385 {
2386     return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, FALSE );
2387 }
2388
2389
2390 /**********************************************************************
2391  *              SetWindowLongW (USER32.@) Set window attribute
2392  *
2393  * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2394  * value in a window's extra memory.
2395  *
2396  * The _hwnd_ parameter specifies the window.  is the handle to a
2397  * window that has extra memory. The _newval_ parameter contains the
2398  * new attribute or extra memory value.  If positive, the _offset_
2399  * parameter is the byte-addressed location in the window's extra
2400  * memory to set.  If negative, _offset_ specifies the window
2401  * attribute to set, and should be one of the following values:
2402  *
2403  * GWL_EXSTYLE      The window's extended window style
2404  *
2405  * GWL_STYLE        The window's window style.
2406  *
2407  * GWLP_WNDPROC     Pointer to the window's window procedure.
2408  *
2409  * GWLP_HINSTANCE   The window's pplication instance handle.
2410  *
2411  * GWLP_ID          The window's identifier.
2412  *
2413  * GWLP_USERDATA    The window's user-specified data.
2414  *
2415  * If the window is a dialog box, the _offset_ parameter can be one of
2416  * the following values:
2417  *
2418  * DWLP_DLGPROC     The address of the window's dialog box procedure.
2419  *
2420  * DWLP_MSGRESULT   The return value of a message
2421  *                  that the dialog box procedure processed.
2422  *
2423  * DWLP_USER        Application specific information.
2424  *
2425  * RETURNS
2426  *
2427  * If successful, returns the previous value located at _offset_. Otherwise,
2428  * returns 0.
2429  *
2430  * NOTES
2431  *
2432  * Extra memory for a window class is specified by a nonzero cbWndExtra
2433  * parameter of the WNDCLASS structure passed to RegisterClass() at the
2434  * time of class creation.
2435  *
2436  * Using GWL_WNDPROC to set a new window procedure effectively creates
2437  * a window subclass. Use CallWindowProc() in the new windows procedure
2438  * to pass messages to the superclass's window procedure.
2439  *
2440  * The user data is reserved for use by the application which created
2441  * the window.
2442  *
2443  * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2444  * instead, call the EnableWindow() function to change the window's
2445  * disabled state.
2446  *
2447  * Do not use GWL_HWNDPARENT to reset the window's parent, use
2448  * SetParent() instead.
2449  *
2450  * Win95:
2451  * When offset is GWL_STYLE and the calling app's ver is 4.0,
2452  * it sends WM_STYLECHANGING before changing the settings
2453  * and WM_STYLECHANGED afterwards.
2454  * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2455  */
2456 LONG WINAPI SetWindowLongW(
2457     HWND hwnd,  /* [in] window to alter */
2458     INT offset, /* [in] offset, in bytes, of location to alter */
2459     LONG newval /* [in] new value of location */
2460 ) {
2461     return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, TRUE );
2462 }
2463
2464
2465 /*******************************************************************
2466  *              GetWindowTextA (USER32.@)
2467  */
2468 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2469 {
2470     WCHAR *buffer;
2471
2472     if (!lpString) return 0;
2473
2474     if (WIN_IsCurrentProcess( hwnd ))
2475         return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2476
2477     /* when window belongs to other process, don't send a message */
2478     if (nMaxCount <= 0) return 0;
2479     if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2480     get_server_window_text( hwnd, buffer, nMaxCount );
2481     if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2482         lpString[nMaxCount-1] = 0;
2483     HeapFree( GetProcessHeap(), 0, buffer );
2484     return strlen(lpString);
2485 }
2486
2487
2488 /*******************************************************************
2489  *              InternalGetWindowText (USER32.@)
2490  */
2491 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2492 {
2493     WND *win;
2494
2495     if (nMaxCount <= 0) return 0;
2496     if (!(win = WIN_GetPtr( hwnd ))) return 0;
2497     if (win == WND_DESKTOP) lpString[0] = 0;
2498     else if (win != WND_OTHER_PROCESS)
2499     {
2500         if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2501         else lpString[0] = 0;
2502         WIN_ReleasePtr( win );
2503     }
2504     else
2505     {
2506         get_server_window_text( hwnd, lpString, nMaxCount );
2507     }
2508     return strlenW(lpString);
2509 }
2510
2511
2512 /*******************************************************************
2513  *              GetWindowTextW (USER32.@)
2514  */
2515 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2516 {
2517     if (!lpString) return 0;
2518
2519     if (WIN_IsCurrentProcess( hwnd ))
2520         return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2521
2522     /* when window belongs to other process, don't send a message */
2523     if (nMaxCount <= 0) return 0;
2524     get_server_window_text( hwnd, lpString, nMaxCount );
2525     return strlenW(lpString);
2526 }
2527
2528
2529 /*******************************************************************
2530  *              SetWindowTextA (USER32.@)
2531  *              SetWindowText  (USER32.@)
2532  */
2533 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2534 {
2535     if (is_broadcast(hwnd))
2536     {
2537         SetLastError( ERROR_INVALID_PARAMETER );
2538         return FALSE;
2539     }
2540     if (!WIN_IsCurrentProcess( hwnd ))
2541         WARN( "setting text %s of other process window %p should not use SendMessage\n",
2542                debugstr_a(lpString), hwnd );
2543     return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2544 }
2545
2546
2547 /*******************************************************************
2548  *              SetWindowTextW (USER32.@)
2549  */
2550 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2551 {
2552     if (is_broadcast(hwnd))
2553     {
2554         SetLastError( ERROR_INVALID_PARAMETER );
2555         return FALSE;
2556     }
2557     if (!WIN_IsCurrentProcess( hwnd ))
2558         WARN( "setting text %s of other process window %p should not use SendMessage\n",
2559                debugstr_w(lpString), hwnd );
2560     return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2561 }
2562
2563
2564 /*******************************************************************
2565  *              GetWindowTextLengthA (USER32.@)
2566  */
2567 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2568 {
2569     return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2570 }
2571
2572 /*******************************************************************
2573  *              GetWindowTextLengthW (USER32.@)
2574  */
2575 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2576 {
2577     return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2578 }
2579
2580
2581 /*******************************************************************
2582  *              IsWindow (USER32.@)
2583  */
2584 BOOL WINAPI IsWindow( HWND hwnd )
2585 {
2586     WND *ptr;
2587     BOOL ret;
2588
2589     if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2590     if (ptr == WND_DESKTOP) return TRUE;
2591
2592     if (ptr != WND_OTHER_PROCESS)
2593     {
2594         WIN_ReleasePtr( ptr );
2595         return TRUE;
2596     }
2597
2598     /* check other processes */
2599     SERVER_START_REQ( get_window_info )
2600     {
2601         req->handle = wine_server_user_handle( hwnd );
2602         ret = !wine_server_call_err( req );
2603     }
2604     SERVER_END_REQ;
2605     return ret;
2606 }
2607
2608
2609 /***********************************************************************
2610  *              GetWindowThreadProcessId (USER32.@)
2611  */
2612 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2613 {
2614     WND *ptr;
2615     DWORD tid = 0;
2616
2617     if (!(ptr = WIN_GetPtr( hwnd )))
2618     {
2619         SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2620         return 0;
2621     }
2622
2623     if (ptr != WND_OTHER_PROCESS && ptr != WND_DESKTOP)
2624     {
2625         /* got a valid window */
2626         tid = ptr->tid;
2627         if (process) *process = GetCurrentProcessId();
2628         WIN_ReleasePtr( ptr );
2629         return tid;
2630     }
2631
2632     /* check other processes */
2633     SERVER_START_REQ( get_window_info )
2634     {
2635         req->handle = wine_server_user_handle( hwnd );
2636         if (!wine_server_call_err( req ))
2637         {
2638             tid = (DWORD)reply->tid;
2639             if (process) *process = (DWORD)reply->pid;
2640         }
2641     }
2642     SERVER_END_REQ;
2643     return tid;
2644 }
2645
2646
2647 /*****************************************************************
2648  *              GetParent (USER32.@)
2649  */
2650 HWND WINAPI GetParent( HWND hwnd )
2651 {
2652     WND *wndPtr;
2653     HWND retvalue = 0;
2654
2655     if (!(wndPtr = WIN_GetPtr( hwnd )))
2656     {
2657         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2658         return 0;
2659     }
2660     if (wndPtr == WND_DESKTOP) return 0;
2661     if (wndPtr == WND_OTHER_PROCESS)
2662     {
2663         LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2664         if (style & (WS_POPUP | WS_CHILD))
2665         {
2666             SERVER_START_REQ( get_window_tree )
2667             {
2668                 req->handle = wine_server_user_handle( hwnd );
2669                 if (!wine_server_call_err( req ))
2670                 {
2671                     if (style & WS_POPUP) retvalue = wine_server_ptr_handle( reply->owner );
2672                     else if (style & WS_CHILD) retvalue = wine_server_ptr_handle( reply->parent );
2673                 }
2674             }
2675             SERVER_END_REQ;
2676         }
2677     }
2678     else
2679     {
2680         if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2681         else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2682         WIN_ReleasePtr( wndPtr );
2683     }
2684     return retvalue;
2685 }
2686
2687
2688 /*****************************************************************
2689  *              GetAncestor (USER32.@)
2690  */
2691 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2692 {
2693     WND *win;
2694     HWND *list, ret = 0;
2695
2696     switch(type)
2697     {
2698     case GA_PARENT:
2699         if (!(win = WIN_GetPtr( hwnd )))
2700         {
2701             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2702             return 0;
2703         }
2704         if (win == WND_DESKTOP) return 0;
2705         if (win != WND_OTHER_PROCESS)
2706         {
2707             ret = win->parent;
2708             WIN_ReleasePtr( win );
2709         }
2710         else /* need to query the server */
2711         {
2712             SERVER_START_REQ( get_window_tree )
2713             {
2714                 req->handle = wine_server_user_handle( hwnd );
2715                 if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->parent );
2716             }
2717             SERVER_END_REQ;
2718         }
2719         break;
2720
2721     case GA_ROOT:
2722         if (!(list = list_window_parents( hwnd ))) return 0;
2723
2724         if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd );  /* top-level window */
2725         else
2726         {
2727             int count = 2;
2728             while (list[count]) count++;
2729             ret = list[count - 2];  /* get the one before the desktop */
2730         }
2731         HeapFree( GetProcessHeap(), 0, list );
2732         break;
2733
2734     case GA_ROOTOWNER:
2735         if (is_desktop_window( hwnd )) return 0;
2736         ret = WIN_GetFullHandle( hwnd );
2737         for (;;)
2738         {
2739             HWND parent = GetParent( ret );
2740             if (!parent) break;
2741             ret = parent;
2742         }
2743         break;
2744     }
2745     return ret;
2746 }
2747
2748
2749 /*****************************************************************
2750  *              SetParent (USER32.@)
2751  */
2752 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2753 {
2754     HWND full_handle;
2755     HWND old_parent = 0;
2756     BOOL was_visible;
2757     WND *wndPtr;
2758     BOOL ret;
2759
2760     if (is_broadcast(hwnd) || is_broadcast(parent))
2761     {
2762         SetLastError(ERROR_INVALID_PARAMETER);
2763         return 0;
2764     }
2765
2766     if (!parent) parent = GetDesktopWindow();
2767     else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
2768     else parent = WIN_GetFullHandle( parent );
2769
2770     if (!IsWindow( parent ))
2771     {
2772         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2773         return 0;
2774     }
2775
2776     /* Some applications try to set a child as a parent */
2777     if (IsChild(hwnd, parent))
2778     {
2779         SetLastError( ERROR_INVALID_PARAMETER );
2780         return 0;
2781     }
2782
2783     if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2784         return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2785
2786     /* Windows hides the window first, then shows it again
2787      * including the WM_SHOWWINDOW messages and all */
2788     was_visible = ShowWindow( hwnd, SW_HIDE );
2789
2790     wndPtr = WIN_GetPtr( hwnd );
2791     if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
2792
2793     SERVER_START_REQ( set_parent )
2794     {
2795         req->handle = wine_server_user_handle( hwnd );
2796         req->parent = wine_server_user_handle( parent );
2797         if ((ret = !wine_server_call( req )))
2798         {
2799             old_parent = wine_server_ptr_handle( reply->old_parent );
2800             wndPtr->parent = parent = wine_server_ptr_handle( reply->full_parent );
2801         }
2802
2803     }
2804     SERVER_END_REQ;
2805     WIN_ReleasePtr( wndPtr );
2806     if (!ret) return 0;
2807
2808     USER_Driver->pSetParent( full_handle, parent, old_parent );
2809
2810     /* SetParent additionally needs to make hwnd the topmost window
2811        in the x-order and send the expected WM_WINDOWPOSCHANGING and
2812        WM_WINDOWPOSCHANGED notification messages.
2813     */
2814     SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0,
2815                   SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | (was_visible ? SWP_SHOWWINDOW : 0) );
2816     /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
2817      * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
2818
2819     return old_parent;
2820 }
2821
2822
2823 /*******************************************************************
2824  *              IsChild (USER32.@)
2825  */
2826 BOOL WINAPI IsChild( HWND parent, HWND child )
2827 {
2828     HWND *list = list_window_parents( child );
2829     int i;
2830     BOOL ret;
2831
2832     if (!list) return FALSE;
2833     parent = WIN_GetFullHandle( parent );
2834     for (i = 0; list[i]; i++) if (list[i] == parent) break;
2835     ret = list[i] && list[i+1];
2836     HeapFree( GetProcessHeap(), 0, list );
2837     return ret;
2838 }
2839
2840
2841 /***********************************************************************
2842  *              IsWindowVisible (USER32.@)
2843  */
2844 BOOL WINAPI IsWindowVisible( HWND hwnd )
2845 {
2846     HWND *list;
2847     BOOL retval = TRUE;
2848     int i;
2849
2850     if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2851     if (!(list = list_window_parents( hwnd ))) return TRUE;
2852     if (list[0])
2853     {
2854         for (i = 0; list[i+1]; i++)
2855             if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2856         retval = !list[i+1] && (list[i] == GetDesktopWindow());  /* top message window isn't visible */
2857     }
2858     HeapFree( GetProcessHeap(), 0, list );
2859     return retval;
2860 }
2861
2862
2863 /***********************************************************************
2864  *           WIN_IsWindowDrawable
2865  *
2866  * hwnd is drawable when it is visible, all parents are not
2867  * minimized, and it is itself not minimized unless we are
2868  * trying to draw its default class icon.
2869  */
2870 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2871 {
2872     HWND *list;
2873     BOOL retval = TRUE;
2874     int i;
2875     LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2876
2877     if (!(style & WS_VISIBLE)) return FALSE;
2878     if ((style & WS_MINIMIZE) && icon && GetClassLongPtrW( hwnd, GCLP_HICON ))  return FALSE;
2879
2880     if (!(list = list_window_parents( hwnd ))) return TRUE;
2881     if (list[0])
2882     {
2883         for (i = 0; list[i+1]; i++)
2884             if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2885                 break;
2886         retval = !list[i+1] && (list[i] == GetDesktopWindow());  /* top message window isn't visible */
2887     }
2888     HeapFree( GetProcessHeap(), 0, list );
2889     return retval;
2890 }
2891
2892
2893 /*******************************************************************
2894  *              GetTopWindow (USER32.@)
2895  */
2896 HWND WINAPI GetTopWindow( HWND hwnd )
2897 {
2898     if (!hwnd) hwnd = GetDesktopWindow();
2899     return GetWindow( hwnd, GW_CHILD );
2900 }
2901
2902
2903 /*******************************************************************
2904  *              GetWindow (USER32.@)
2905  */
2906 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2907 {
2908     HWND retval = 0;
2909
2910     if (rel == GW_OWNER)  /* this one may be available locally */
2911     {
2912         WND *wndPtr = WIN_GetPtr( hwnd );
2913         if (!wndPtr)
2914         {
2915             SetLastError( ERROR_INVALID_HANDLE );
2916             return 0;
2917         }
2918         if (wndPtr == WND_DESKTOP) return 0;
2919         if (wndPtr != WND_OTHER_PROCESS)
2920         {
2921             retval = wndPtr->owner;
2922             WIN_ReleasePtr( wndPtr );
2923             return retval;
2924         }
2925         /* else fall through to server call */
2926     }
2927
2928     SERVER_START_REQ( get_window_tree )
2929     {
2930         req->handle = wine_server_user_handle( hwnd );
2931         if (!wine_server_call_err( req ))
2932         {
2933             switch(rel)
2934             {
2935             case GW_HWNDFIRST:
2936                 retval = wine_server_ptr_handle( reply->first_sibling );
2937                 break;
2938             case GW_HWNDLAST:
2939                 retval = wine_server_ptr_handle( reply->last_sibling );
2940                 break;
2941             case GW_HWNDNEXT:
2942                 retval = wine_server_ptr_handle( reply->next_sibling );
2943                 break;
2944             case GW_HWNDPREV:
2945                 retval = wine_server_ptr_handle( reply->prev_sibling );
2946                 break;
2947             case GW_OWNER:
2948                 retval = wine_server_ptr_handle( reply->owner );
2949                 break;
2950             case GW_CHILD:
2951                 retval = wine_server_ptr_handle( reply->first_child );
2952                 break;
2953             }
2954         }
2955     }
2956     SERVER_END_REQ;
2957     return retval;
2958 }
2959
2960
2961 /*******************************************************************
2962  *              ShowOwnedPopups (USER32.@)
2963  */
2964 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2965 {
2966     int count = 0;
2967     WND *pWnd;
2968     HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2969
2970     if (!win_array) return TRUE;
2971
2972     while (win_array[count]) count++;
2973     while (--count >= 0)
2974     {
2975         if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2976         if (!(pWnd = WIN_GetPtr( win_array[count] ))) continue;
2977         if (pWnd == WND_OTHER_PROCESS) continue;
2978         if (fShow)
2979         {
2980             if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2981             {
2982                 WIN_ReleasePtr( pWnd );
2983                 /* In Windows, ShowOwnedPopups(TRUE) generates
2984                  * WM_SHOWWINDOW messages with SW_PARENTOPENING,
2985                  * regardless of the state of the owner
2986                  */
2987                 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
2988                 continue;
2989             }
2990         }
2991         else
2992         {
2993             if (pWnd->dwStyle & WS_VISIBLE)
2994             {
2995                 WIN_ReleasePtr( pWnd );
2996                 /* In Windows, ShowOwnedPopups(FALSE) generates
2997                  * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
2998                  * regardless of the state of the owner
2999                  */
3000                 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
3001                 continue;
3002             }
3003         }
3004         WIN_ReleasePtr( pWnd );
3005     }
3006     HeapFree( GetProcessHeap(), 0, win_array );
3007     return TRUE;
3008 }
3009
3010
3011 /*******************************************************************
3012  *              GetLastActivePopup (USER32.@)
3013  */
3014 HWND WINAPI GetLastActivePopup( HWND hwnd )
3015 {
3016     HWND retval = hwnd;
3017
3018     SERVER_START_REQ( get_window_info )
3019     {
3020         req->handle = wine_server_user_handle( hwnd );
3021         if (!wine_server_call_err( req )) retval = wine_server_ptr_handle( reply->last_active );
3022     }
3023     SERVER_END_REQ;
3024     return retval;
3025 }
3026
3027
3028 /*******************************************************************
3029  *           WIN_ListChildren
3030  *
3031  * Build an array of the children of a given window. The array must be
3032  * freed with HeapFree. Returns NULL when no windows are found.
3033  */
3034 HWND *WIN_ListChildren( HWND hwnd )
3035 {
3036     if (!hwnd)
3037     {
3038         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3039         return NULL;
3040     }
3041     return list_window_children( 0, hwnd, NULL, 0 );
3042 }
3043
3044
3045 /*******************************************************************
3046  *              EnumWindows (USER32.@)
3047  */
3048 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
3049 {
3050     HWND *list;
3051     BOOL ret = TRUE;
3052     int i;
3053
3054     USER_CheckNotLock();
3055
3056     /* We have to build a list of all windows first, to avoid */
3057     /* unpleasant side-effects, for instance if the callback */
3058     /* function changes the Z-order of the windows.          */
3059
3060     if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
3061
3062     /* Now call the callback function for every window */
3063
3064     for (i = 0; list[i]; i++)
3065     {
3066         /* Make sure that the window still exists */
3067         if (!IsWindow( list[i] )) continue;
3068         if (!(ret = lpEnumFunc( list[i], lParam ))) break;
3069     }
3070     HeapFree( GetProcessHeap(), 0, list );
3071     return ret;
3072 }
3073
3074
3075 /**********************************************************************
3076  *              EnumThreadWindows (USER32.@)
3077  */
3078 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
3079 {
3080     HWND *list;
3081     int i;
3082
3083     USER_CheckNotLock();
3084
3085     if (!(list = list_window_children( 0, GetDesktopWindow(), NULL, id ))) return TRUE;
3086
3087     /* Now call the callback function for every window */
3088
3089     for (i = 0; list[i]; i++)
3090         if (!func( list[i], lParam )) break;
3091     HeapFree( GetProcessHeap(), 0, list );
3092     return TRUE;
3093 }
3094
3095
3096 /***********************************************************************
3097  *              EnumDesktopWindows   (USER32.@)
3098  */
3099 BOOL WINAPI EnumDesktopWindows( HDESK desktop, WNDENUMPROC func, LPARAM lparam )
3100 {
3101     HWND *list;
3102     int i;
3103
3104     USER_CheckNotLock();
3105
3106     if (!(list = list_window_children( desktop, 0, NULL, 0 ))) return TRUE;
3107
3108     for (i = 0; list[i]; i++)
3109         if (!func( list[i], lparam )) break;
3110     HeapFree( GetProcessHeap(), 0, list );
3111     return TRUE;
3112 }
3113
3114
3115 /**********************************************************************
3116  *           WIN_EnumChildWindows
3117  *
3118  * Helper function for EnumChildWindows().
3119  */
3120 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
3121 {
3122     HWND *childList;
3123     BOOL ret = FALSE;
3124
3125     for ( ; *list; list++)
3126     {
3127         /* Make sure that the window still exists */
3128         if (!IsWindow( *list )) continue;
3129         /* Build children list first */
3130         childList = WIN_ListChildren( *list );
3131
3132         ret = func( *list, lParam );
3133
3134         if (childList)
3135         {
3136             if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
3137             HeapFree( GetProcessHeap(), 0, childList );
3138         }
3139         if (!ret) return FALSE;
3140     }
3141     return TRUE;
3142 }
3143
3144
3145 /**********************************************************************
3146  *              EnumChildWindows (USER32.@)
3147  */
3148 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
3149 {
3150     HWND *list;
3151     BOOL ret;
3152
3153     USER_CheckNotLock();
3154
3155     if (!(list = WIN_ListChildren( parent ))) return FALSE;
3156     ret = WIN_EnumChildWindows( list, func, lParam );
3157     HeapFree( GetProcessHeap(), 0, list );
3158     return ret;
3159 }
3160
3161
3162 /*******************************************************************
3163  *              AnyPopup (USER.52)
3164  */
3165 BOOL16 WINAPI AnyPopup16(void)
3166 {
3167     return AnyPopup();
3168 }
3169
3170
3171 /*******************************************************************
3172  *              AnyPopup (USER32.@)
3173  */
3174 BOOL WINAPI AnyPopup(void)
3175 {
3176     int i;
3177     BOOL retvalue;
3178     HWND *list = WIN_ListChildren( GetDesktopWindow() );
3179
3180     if (!list) return FALSE;
3181     for (i = 0; list[i]; i++)
3182     {
3183         if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
3184     }
3185     retvalue = (list[i] != 0);
3186     HeapFree( GetProcessHeap(), 0, list );
3187     return retvalue;
3188 }
3189
3190
3191 /*******************************************************************
3192  *              FlashWindow (USER32.@)
3193  */
3194 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3195 {
3196     WND *wndPtr;
3197
3198     TRACE("%p\n", hWnd);
3199
3200     if (IsIconic( hWnd ))
3201     {
3202         RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
3203
3204         wndPtr = WIN_GetPtr(hWnd);
3205         if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3206         if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
3207         {
3208             wndPtr->flags |= WIN_NCACTIVATED;
3209         }
3210         else
3211         {
3212             wndPtr->flags &= ~WIN_NCACTIVATED;
3213         }
3214         WIN_ReleasePtr( wndPtr );
3215         return TRUE;
3216     }
3217     else
3218     {
3219         WPARAM wparam;
3220
3221         wndPtr = WIN_GetPtr(hWnd);
3222         if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3223         hWnd = wndPtr->hwndSelf;  /* make it a full handle */
3224
3225         if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3226         else wparam = (hWnd == GetForegroundWindow());
3227
3228         WIN_ReleasePtr( wndPtr );
3229         SendMessageW( hWnd, WM_NCACTIVATE, wparam, 0 );
3230         return wparam;
3231     }
3232 }
3233
3234 /*******************************************************************
3235  *              FlashWindowEx (USER32.@)
3236  */
3237 BOOL WINAPI FlashWindowEx( PFLASHWINFO pfwi )
3238 {
3239     FIXME("%p\n", pfwi);
3240     return TRUE;
3241 }
3242
3243 /*******************************************************************
3244  *              GetWindowContextHelpId (USER32.@)
3245  */
3246 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3247 {
3248     DWORD retval;
3249     WND *wnd = WIN_GetPtr( hwnd );
3250     if (!wnd || wnd == WND_DESKTOP) return 0;
3251     if (wnd == WND_OTHER_PROCESS)
3252     {
3253         if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3254         return 0;
3255     }
3256     retval = wnd->helpContext;
3257     WIN_ReleasePtr( wnd );
3258     return retval;
3259 }
3260
3261
3262 /*******************************************************************
3263  *              SetWindowContextHelpId (USER32.@)
3264  */
3265 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3266 {
3267     WND *wnd = WIN_GetPtr( hwnd );
3268     if (!wnd || wnd == WND_DESKTOP) return FALSE;
3269     if (wnd == WND_OTHER_PROCESS)
3270     {
3271         if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3272         return 0;
3273     }
3274     wnd->helpContext = id;
3275     WIN_ReleasePtr( wnd );
3276     return TRUE;
3277 }
3278
3279
3280 /*******************************************************************
3281  *              DragDetect (USER32.@)
3282  */
3283 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3284 {
3285     MSG msg;
3286     RECT rect;
3287     WORD wDragWidth = GetSystemMetrics(SM_CXDRAG);
3288     WORD wDragHeight= GetSystemMetrics(SM_CYDRAG);
3289
3290     rect.left = pt.x - wDragWidth;
3291     rect.right = pt.x + wDragWidth;
3292
3293     rect.top = pt.y - wDragHeight;
3294     rect.bottom = pt.y + wDragHeight;
3295
3296     SetCapture(hWnd);
3297
3298     while(1)
3299     {
3300         while (PeekMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ))
3301         {
3302             if( msg.message == WM_LBUTTONUP )
3303             {
3304                 ReleaseCapture();
3305                 return 0;
3306             }
3307             if( msg.message == WM_MOUSEMOVE )
3308             {
3309                 POINT tmp;
3310                 tmp.x = (short)LOWORD(msg.lParam);
3311                 tmp.y = (short)HIWORD(msg.lParam);
3312                 if( !PtInRect( &rect, tmp ))
3313                 {
3314                     ReleaseCapture();
3315                     return 1;
3316                 }
3317             }
3318         }
3319         WaitMessage();
3320     }
3321     return 0;
3322 }
3323
3324 /******************************************************************************
3325  *              GetWindowModuleFileNameA (USER32.@)
3326  */
3327 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR module, UINT size )
3328 {
3329     WND *win;
3330     HINSTANCE hinst;
3331
3332     TRACE( "%p, %p, %u\n", hwnd, module, size );
3333
3334     win = WIN_GetPtr( hwnd );
3335     if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3336     {
3337         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3338         return 0;
3339     }
3340     hinst = win->hInstance;
3341     WIN_ReleasePtr( win );
3342
3343     return GetModuleFileNameA( hinst, module, size );
3344 }
3345
3346 /******************************************************************************
3347  *              GetWindowModuleFileNameW (USER32.@)
3348  */
3349 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR module, UINT size )
3350 {
3351     WND *win;
3352     HINSTANCE hinst;
3353
3354     TRACE( "%p, %p, %u\n", hwnd, module, size );
3355
3356     win = WIN_GetPtr( hwnd );
3357     if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3358     {
3359         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3360         return 0;
3361     }
3362     hinst = win->hInstance;
3363     WIN_ReleasePtr( win );
3364
3365     return GetModuleFileNameW( hinst, module, size );
3366 }
3367
3368 /******************************************************************************
3369  *              GetWindowInfo (USER32.@)
3370  *
3371  * Note: tests show that Windows doesn't check cbSize of the structure.
3372  */
3373 BOOL WINAPI GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3374 {
3375     if (!pwi) return FALSE;
3376     if (!IsWindow(hwnd)) return FALSE;
3377
3378     GetWindowRect(hwnd, &pwi->rcWindow);
3379     GetClientRect(hwnd, &pwi->rcClient);
3380     /* translate to screen coordinates */
3381     MapWindowPoints(hwnd, 0, (LPPOINT)&pwi->rcClient, 2);
3382
3383     pwi->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
3384     pwi->dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3385     pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3386
3387     pwi->cxWindowBorders = pwi->rcClient.left - pwi->rcWindow.left;
3388     pwi->cyWindowBorders = pwi->rcWindow.bottom - pwi->rcClient.bottom;
3389
3390     pwi->atomWindowType = GetClassLongW( hwnd, GCW_ATOM );
3391     pwi->wCreatorVersion = 0x0400;
3392
3393     return TRUE;
3394 }
3395
3396 /******************************************************************************
3397  *              SwitchDesktop (USER32.@)
3398  *
3399  * NOTES: Sets the current input or interactive desktop.
3400  */
3401 BOOL WINAPI SwitchDesktop( HDESK hDesktop)
3402 {
3403     FIXME("SwitchDesktop(hwnd %p) stub!\n", hDesktop);
3404     return TRUE;
3405 }
3406
3407 /*****************************************************************************
3408  *              SetLayeredWindowAttributes (USER32.@)
3409  */
3410 BOOL WINAPI SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, DWORD flags )
3411 {
3412     BOOL ret;
3413
3414     TRACE("(%p,%08x,%d,%x): stub!\n", hwnd, key, alpha, flags);
3415
3416     SERVER_START_REQ( set_window_layered_info )
3417     {
3418         req->handle = wine_server_user_handle( hwnd );
3419         req->color_key = key;
3420         req->alpha = alpha;
3421         req->flags = flags;
3422         ret = !wine_server_call_err( req );
3423     }
3424     SERVER_END_REQ;
3425
3426     if (ret) USER_Driver->pSetLayeredWindowAttributes( hwnd, key, alpha, flags );
3427
3428     return ret;
3429 }
3430
3431
3432 /*****************************************************************************
3433  *              GetLayeredWindowAttributes (USER32.@)
3434  */
3435 BOOL WINAPI GetLayeredWindowAttributes( HWND hwnd, COLORREF *key, BYTE *alpha, DWORD *flags )
3436 {
3437     BOOL ret;
3438
3439     SERVER_START_REQ( get_window_layered_info )
3440     {
3441         req->handle = wine_server_user_handle( hwnd );
3442         if ((ret = !wine_server_call_err( req )))
3443         {
3444             if (key) *key = reply->color_key;
3445             if (alpha) *alpha = reply->alpha;
3446             if (flags) *flags = reply->flags;
3447         }
3448     }
3449     SERVER_END_REQ;
3450
3451     return ret;
3452 }
3453
3454
3455 /*****************************************************************************
3456  *              UpdateLayeredWindowIndirect  (USER32.@)
3457  */
3458 BOOL WINAPI UpdateLayeredWindowIndirect( HWND hwnd, const UPDATELAYEREDWINDOWINFO *info )
3459 {
3460     BYTE alpha = 0xff;
3461
3462     if (!(info->dwFlags & ULW_EX_NORESIZE) && (info->pptDst || info->psize))
3463     {
3464         int x = 0, y = 0, cx = 0, cy = 0;
3465         DWORD flags = SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOSENDCHANGING;
3466
3467         if (info->pptDst)
3468         {
3469             x = info->pptDst->x;
3470             y = info->pptDst->y;
3471             flags &= ~SWP_NOMOVE;
3472         }
3473         if (info->psize)
3474         {
3475             cx = info->psize->cx;
3476             cy = info->psize->cy;
3477             flags &= ~SWP_NOSIZE;
3478         }
3479         TRACE( "moving window %p pos %d,%d %dx%x\n", hwnd, x, y, cx, cy );
3480         SetWindowPos( hwnd, 0, x, y, cx, cy, flags );
3481     }
3482
3483     if (info->hdcSrc)
3484     {
3485         RECT rect;
3486         HDC hdc = GetDCEx( hwnd, 0, DCX_CACHE );
3487
3488         if (hdc)
3489         {
3490             int x = 0, y = 0;
3491
3492             GetClientRect( hwnd, &rect );
3493             if (info->pptSrc)
3494             {
3495                 x = info->pptSrc->x;
3496                 y = info->pptSrc->y;
3497             }
3498             /* FIXME: intersect rect with info->prcDirty */
3499             TRACE( "copying window %p pos %d,%d\n", hwnd, x, y );
3500             BitBlt( hdc, rect.left, rect.top, rect.right, rect.bottom,
3501                     info->hdcSrc, rect.left + x, rect.top + y, SRCCOPY );
3502             ReleaseDC( hwnd, hdc );
3503         }
3504     }
3505
3506     if (info->pblend && !(info->dwFlags & ULW_OPAQUE)) alpha = info->pblend->SourceConstantAlpha;
3507     TRACE( "setting window %p alpha %u\n", hwnd, alpha );
3508     USER_Driver->pSetLayeredWindowAttributes( hwnd, info->crKey, alpha,
3509                                               info->dwFlags & (LWA_ALPHA | LWA_COLORKEY) );
3510     return TRUE;
3511 }
3512
3513
3514 /*****************************************************************************
3515  *              UpdateLayeredWindow (USER32.@)
3516  */
3517 BOOL WINAPI UpdateLayeredWindow( HWND hwnd, HDC hdcDst, POINT *pptDst, SIZE *psize,
3518                                  HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend,
3519                                  DWORD dwFlags)
3520 {
3521     UPDATELAYEREDWINDOWINFO info;
3522
3523     info.cbSize   = sizeof(info);
3524     info.hdcDst   = hdcDst;
3525     info.pptDst   = pptDst;
3526     info.psize    = psize;
3527     info.hdcSrc   = hdcSrc;
3528     info.pptSrc   = pptSrc;
3529     info.crKey    = crKey;
3530     info.pblend   = pblend;
3531     info.dwFlags  = dwFlags;
3532     info.prcDirty = NULL;
3533     return UpdateLayeredWindowIndirect( hwnd, &info );
3534 }
3535
3536 /* 64bit versions */
3537
3538 #ifdef GetWindowLongPtrW
3539 #undef GetWindowLongPtrW
3540 #endif
3541
3542 #ifdef GetWindowLongPtrA
3543 #undef GetWindowLongPtrA
3544 #endif
3545
3546 #ifdef SetWindowLongPtrW
3547 #undef SetWindowLongPtrW
3548 #endif
3549
3550 #ifdef SetWindowLongPtrA
3551 #undef SetWindowLongPtrA
3552 #endif
3553
3554 /*****************************************************************************
3555  *              GetWindowLongPtrW (USER32.@)
3556  */
3557 LONG_PTR WINAPI GetWindowLongPtrW( HWND hwnd, INT offset )
3558 {
3559     return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), TRUE );
3560 }
3561
3562 /*****************************************************************************
3563  *              GetWindowLongPtrA (USER32.@)
3564  */
3565 LONG_PTR WINAPI GetWindowLongPtrA( HWND hwnd, INT offset )
3566 {
3567     return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), FALSE );
3568 }
3569
3570 /*****************************************************************************
3571  *              SetWindowLongPtrW (USER32.@)
3572  */
3573 LONG_PTR WINAPI SetWindowLongPtrW( HWND hwnd, INT offset, LONG_PTR newval )
3574 {
3575     return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, TRUE );
3576 }
3577
3578 /*****************************************************************************
3579  *              SetWindowLongPtrA (USER32.@)
3580  */
3581 LONG_PTR WINAPI SetWindowLongPtrA( HWND hwnd, INT offset, LONG_PTR newval )
3582 {
3583     return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, FALSE );
3584 }