comctl32/monthcal: Cache window GWL_STYLE.
[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 systemdir[MAX_PATH];
1789             WCHAR cmdline[MAX_PATH + sizeof(command_line)/sizeof(WCHAR)];
1790
1791             memset( &si, 0, sizeof(si) );
1792             si.cb = sizeof(si);
1793             si.dwFlags = STARTF_USESTDHANDLES;
1794             si.hStdInput  = 0;
1795             si.hStdOutput = 0;
1796             si.hStdError  = GetStdHandle( STD_ERROR_HANDLE );
1797
1798             GetSystemDirectoryW( systemdir, MAX_PATH );
1799             lstrcpyW( cmdline, systemdir );
1800             lstrcatW( cmdline, command_line );
1801             if (CreateProcessW( NULL, cmdline, NULL, NULL, FALSE, DETACHED_PROCESS,
1802                                 NULL, systemdir, &si, &pi ))
1803             {
1804                 TRACE( "started explorer pid %04x tid %04x\n", pi.dwProcessId, pi.dwThreadId );
1805                 WaitForInputIdle( pi.hProcess, 10000 );
1806                 CloseHandle( pi.hThread );
1807                 CloseHandle( pi.hProcess );
1808             }
1809             else WARN( "failed to start explorer, err %d\n", GetLastError() );
1810         }
1811         else TRACE( "not starting explorer since winstation is not visible\n" );
1812
1813         SERVER_START_REQ( get_desktop_window )
1814         {
1815             req->force = 1;
1816             if (!wine_server_call( req ))
1817             {
1818                 thread_info->top_window = wine_server_ptr_handle( reply->top_window );
1819                 thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
1820             }
1821         }
1822         SERVER_END_REQ;
1823     }
1824
1825     if (!thread_info->top_window || !USER_Driver->pCreateDesktopWindow( thread_info->top_window ))
1826         ERR( "failed to create desktop window\n" );
1827
1828     return thread_info->top_window;
1829 }
1830
1831
1832 /*******************************************************************
1833  *              EnableWindow (USER32.@)
1834  */
1835 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
1836 {
1837     BOOL retvalue;
1838     HWND full_handle;
1839
1840     if (is_broadcast(hwnd))
1841     {
1842         SetLastError( ERROR_INVALID_PARAMETER );
1843         return FALSE;
1844     }
1845
1846     if (!(full_handle = WIN_IsCurrentThread( hwnd )))
1847         return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
1848
1849     hwnd = full_handle;
1850
1851     TRACE("( %p, %d )\n", hwnd, enable);
1852
1853     retvalue = !IsWindowEnabled( hwnd );
1854
1855     if (enable && retvalue)
1856     {
1857         WIN_SetStyle( hwnd, 0, WS_DISABLED );
1858         SendMessageW( hwnd, WM_ENABLE, TRUE, 0 );
1859     }
1860     else if (!enable && !retvalue)
1861     {
1862         HWND capture_wnd;
1863
1864         SendMessageW( hwnd, WM_CANCELMODE, 0, 0);
1865
1866         WIN_SetStyle( hwnd, WS_DISABLED, 0 );
1867
1868         if (hwnd == GetFocus())
1869             SetFocus( 0 );  /* A disabled window can't have the focus */
1870
1871         capture_wnd = GetCapture();
1872         if (hwnd == capture_wnd || IsChild(hwnd, capture_wnd))
1873             ReleaseCapture();  /* A disabled window can't capture the mouse */
1874
1875         SendMessageW( hwnd, WM_ENABLE, FALSE, 0 );
1876     }
1877     return retvalue;
1878 }
1879
1880
1881 /***********************************************************************
1882  *              IsWindowEnabled (USER32.@)
1883  */
1884 BOOL WINAPI IsWindowEnabled(HWND hWnd)
1885 {
1886     return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
1887 }
1888
1889
1890 /***********************************************************************
1891  *              IsWindowUnicode (USER32.@)
1892  */
1893 BOOL WINAPI IsWindowUnicode( HWND hwnd )
1894 {
1895     WND * wndPtr;
1896     BOOL retvalue = FALSE;
1897
1898     if (!(wndPtr = WIN_GetPtr(hwnd))) return FALSE;
1899
1900     if (wndPtr == WND_DESKTOP) return TRUE;
1901
1902     if (wndPtr != WND_OTHER_PROCESS)
1903     {
1904         retvalue = (wndPtr->flags & WIN_ISUNICODE) != 0;
1905         WIN_ReleasePtr( wndPtr );
1906     }
1907     else
1908     {
1909         SERVER_START_REQ( get_window_info )
1910         {
1911             req->handle = wine_server_user_handle( hwnd );
1912             if (!wine_server_call_err( req )) retvalue = reply->is_unicode;
1913         }
1914         SERVER_END_REQ;
1915     }
1916     return retvalue;
1917 }
1918
1919
1920 /**********************************************************************
1921  *           WIN_GetWindowLong
1922  *
1923  * Helper function for GetWindowLong().
1924  */
1925 static LONG_PTR WIN_GetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicode )
1926 {
1927     LONG_PTR retvalue = 0;
1928     WND *wndPtr;
1929
1930     if (offset == GWLP_HWNDPARENT)
1931     {
1932         HWND parent = GetAncestor( hwnd, GA_PARENT );
1933         if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
1934         return (ULONG_PTR)parent;
1935     }
1936
1937     if (!(wndPtr = WIN_GetPtr( hwnd )))
1938     {
1939         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1940         return 0;
1941     }
1942
1943     if (wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP)
1944     {
1945         if (offset == GWLP_WNDPROC)
1946         {
1947             SetLastError( ERROR_ACCESS_DENIED );
1948             return 0;
1949         }
1950         SERVER_START_REQ( set_window_info )
1951         {
1952             req->handle = wine_server_user_handle( hwnd );
1953             req->flags  = 0;  /* don't set anything, just retrieve */
1954             req->extra_offset = (offset >= 0) ? offset : -1;
1955             req->extra_size = (offset >= 0) ? size : 0;
1956             if (!wine_server_call_err( req ))
1957             {
1958                 switch(offset)
1959                 {
1960                 case GWL_STYLE:      retvalue = reply->old_style; break;
1961                 case GWL_EXSTYLE:    retvalue = reply->old_ex_style; break;
1962                 case GWLP_ID:        retvalue = reply->old_id; break;
1963                 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wine_server_get_ptr( reply->old_instance ); break;
1964                 case GWLP_USERDATA:  retvalue = reply->old_user_data; break;
1965                 default:
1966                     if (offset >= 0) retvalue = get_win_data( &reply->old_extra_value, size );
1967                     else SetLastError( ERROR_INVALID_INDEX );
1968                     break;
1969                 }
1970             }
1971         }
1972         SERVER_END_REQ;
1973         return retvalue;
1974     }
1975
1976     /* now we have a valid wndPtr */
1977
1978     if (offset >= 0)
1979     {
1980         if (offset > (int)(wndPtr->cbWndExtra - size))
1981         {
1982             WARN("Invalid offset %d\n", offset );
1983             WIN_ReleasePtr( wndPtr );
1984             SetLastError( ERROR_INVALID_INDEX );
1985             return 0;
1986         }
1987         retvalue = get_win_data( (char *)wndPtr->wExtra + offset, size );
1988
1989         /* Special case for dialog window procedure */
1990         if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && (wndPtr->flags & WIN_ISDIALOG))
1991             retvalue = (LONG_PTR)WINPROC_GetProc( (WNDPROC)retvalue, unicode );
1992         WIN_ReleasePtr( wndPtr );
1993         return retvalue;
1994     }
1995
1996     switch(offset)
1997     {
1998     case GWLP_USERDATA:  retvalue = wndPtr->userdata; break;
1999     case GWL_STYLE:      retvalue = wndPtr->dwStyle; break;
2000     case GWL_EXSTYLE:    retvalue = wndPtr->dwExStyle; break;
2001     case GWLP_ID:        retvalue = wndPtr->wIDmenu; break;
2002     case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hInstance; break;
2003     case GWLP_WNDPROC:
2004         /* This looks like a hack only for the edit control (see tests). This makes these controls
2005          * more tolerant to A/W mismatches. The lack of W->A->W conversion for such a mismatch suggests
2006          * that the hack is in GetWindowLongPtr[AW], not in winprocs.
2007          */
2008         if (wndPtr->winproc == EDIT_winproc_handle && (!unicode != !(wndPtr->flags & WIN_ISUNICODE)))
2009             retvalue = (ULONG_PTR)wndPtr->winproc;
2010         else
2011             retvalue = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, unicode );
2012         break;
2013     default:
2014         WARN("Unknown offset %d\n", offset );
2015         SetLastError( ERROR_INVALID_INDEX );
2016         break;
2017     }
2018     WIN_ReleasePtr(wndPtr);
2019     return retvalue;
2020 }
2021
2022
2023 /**********************************************************************
2024  *           WIN_SetWindowLong
2025  *
2026  * Helper function for SetWindowLong().
2027  *
2028  * 0 is the failure code. However, in the case of failure SetLastError
2029  * must be set to distinguish between a 0 return value and a failure.
2030  */
2031 LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, UINT size, LONG_PTR newval, BOOL unicode )
2032 {
2033     STYLESTRUCT style;
2034     BOOL ok;
2035     LONG_PTR retval = 0;
2036     WND *wndPtr;
2037
2038     TRACE( "%p %d %lx %c\n", hwnd, offset, newval, unicode ? 'W' : 'A' );
2039
2040     if (is_broadcast(hwnd))
2041     {
2042         SetLastError( ERROR_INVALID_PARAMETER );
2043         return FALSE;
2044     }
2045
2046     if (!(wndPtr = WIN_GetPtr( hwnd )))
2047     {
2048         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2049         return 0;
2050     }
2051     if (wndPtr == WND_DESKTOP)
2052     {
2053         /* can't change anything on the desktop window */
2054         SetLastError( ERROR_ACCESS_DENIED );
2055         return 0;
2056     }
2057     if (wndPtr == WND_OTHER_PROCESS)
2058     {
2059         if (offset == GWLP_WNDPROC)
2060         {
2061             SetLastError( ERROR_ACCESS_DENIED );
2062             return 0;
2063         }
2064         if (offset > 32767 || offset < -32767)
2065         {
2066             SetLastError( ERROR_INVALID_INDEX );
2067             return 0;
2068         }
2069         return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, MAKEWPARAM( offset, size ), newval );
2070     }
2071
2072     /* first some special cases */
2073     switch( offset )
2074     {
2075     case GWL_STYLE:
2076     case GWL_EXSTYLE:
2077         style.styleOld =
2078             offset == GWL_STYLE ? wndPtr->dwStyle : wndPtr->dwExStyle;
2079         style.styleNew = newval;
2080         WIN_ReleasePtr( wndPtr );
2081         SendMessageW( hwnd, WM_STYLECHANGING, offset, (LPARAM)&style );
2082         if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2083         newval = style.styleNew;
2084         break;
2085     case GWLP_HWNDPARENT:
2086         if (wndPtr->parent == GetDesktopWindow())
2087         {
2088             WIN_ReleasePtr( wndPtr );
2089             return (ULONG_PTR)WIN_SetOwner( hwnd, (HWND)newval );
2090         }
2091         else
2092         {
2093             WIN_ReleasePtr( wndPtr );
2094             return (ULONG_PTR)SetParent( hwnd, (HWND)newval );
2095         }
2096     case GWLP_WNDPROC:
2097     {
2098         WNDPROC proc;
2099         UINT old_flags = wndPtr->flags;
2100         retval = WIN_GetWindowLong( hwnd, offset, size, unicode );
2101         if (unicode) proc = WINPROC_AllocProc( NULL, (WNDPROC)newval );
2102         else proc = WINPROC_AllocProc( (WNDPROC)newval, NULL );
2103         if (proc) wndPtr->winproc = proc;
2104         if (WINPROC_IsUnicode( proc, unicode )) wndPtr->flags |= WIN_ISUNICODE;
2105         else wndPtr->flags &= ~WIN_ISUNICODE;
2106         if (!((old_flags ^ wndPtr->flags) & WIN_ISUNICODE))
2107         {
2108             WIN_ReleasePtr( wndPtr );
2109             return retval;
2110         }
2111         /* update is_unicode flag on the server side */
2112         break;
2113     }
2114     case GWLP_ID:
2115     case GWLP_HINSTANCE:
2116     case GWLP_USERDATA:
2117         break;
2118     case DWLP_DLGPROC:
2119         if ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
2120             (size == sizeof(LONG_PTR)) && (wndPtr->flags & WIN_ISDIALOG))
2121         {
2122             WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWLP_DLGPROC);
2123             retval = (ULONG_PTR)WINPROC_GetProc( *ptr, unicode );
2124             if (unicode) *ptr = WINPROC_AllocProc( NULL, (WNDPROC)newval );
2125             else *ptr = WINPROC_AllocProc( (WNDPROC)newval, NULL );
2126             WIN_ReleasePtr( wndPtr );
2127             return retval;
2128         }
2129         /* fall through */
2130     default:
2131         if (offset < 0 || offset > (int)(wndPtr->cbWndExtra - size))
2132         {
2133             WARN("Invalid offset %d\n", offset );
2134             WIN_ReleasePtr( wndPtr );
2135             SetLastError( ERROR_INVALID_INDEX );
2136             return 0;
2137         }
2138         else if (get_win_data( (char *)wndPtr->wExtra + offset, size ) == newval)
2139         {
2140             /* already set to the same value */
2141             WIN_ReleasePtr( wndPtr );
2142             return newval;
2143         }
2144         break;
2145     }
2146
2147     SERVER_START_REQ( set_window_info )
2148     {
2149         req->handle = wine_server_user_handle( hwnd );
2150         req->extra_offset = -1;
2151         switch(offset)
2152         {
2153         case GWL_STYLE:
2154             req->flags = SET_WIN_STYLE;
2155             req->style = newval;
2156             break;
2157         case GWL_EXSTYLE:
2158             req->flags = SET_WIN_EXSTYLE;
2159             /* WS_EX_TOPMOST can only be changed through SetWindowPos */
2160             newval = (newval & ~WS_EX_TOPMOST) | (wndPtr->dwExStyle & WS_EX_TOPMOST);
2161             req->ex_style = newval;
2162             break;
2163         case GWLP_ID:
2164             req->flags = SET_WIN_ID;
2165             req->id = newval;
2166             break;
2167         case GWLP_HINSTANCE:
2168             req->flags = SET_WIN_INSTANCE;
2169             req->instance = wine_server_client_ptr( (void *)newval );
2170             break;
2171         case GWLP_WNDPROC:
2172             req->flags = SET_WIN_UNICODE;
2173             req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
2174             break;
2175         case GWLP_USERDATA:
2176             req->flags = SET_WIN_USERDATA;
2177             req->user_data = newval;
2178             break;
2179         default:
2180             req->flags = SET_WIN_EXTRA;
2181             req->extra_offset = offset;
2182             req->extra_size = size;
2183             set_win_data( &req->extra_value, newval, size );
2184         }
2185         if ((ok = !wine_server_call_err( req )))
2186         {
2187             switch(offset)
2188             {
2189             case GWL_STYLE:
2190                 wndPtr->dwStyle = newval;
2191                 retval = reply->old_style;
2192                 break;
2193             case GWL_EXSTYLE:
2194                 wndPtr->dwExStyle = newval;
2195                 retval = reply->old_ex_style;
2196                 break;
2197             case GWLP_ID:
2198                 wndPtr->wIDmenu = newval;
2199                 retval = reply->old_id;
2200                 break;
2201             case GWLP_HINSTANCE:
2202                 wndPtr->hInstance = (HINSTANCE)newval;
2203                 retval = (ULONG_PTR)wine_server_get_ptr( reply->old_instance );
2204                 break;
2205             case GWLP_WNDPROC:
2206                 break;
2207             case GWLP_USERDATA:
2208                 wndPtr->userdata = newval;
2209                 retval = reply->old_user_data;
2210                 break;
2211             default:
2212                 retval = get_win_data( (char *)wndPtr->wExtra + offset, size );
2213                 set_win_data( (char *)wndPtr->wExtra + offset, newval, size );
2214                 break;
2215             }
2216         }
2217     }
2218     SERVER_END_REQ;
2219     WIN_ReleasePtr( wndPtr );
2220
2221     if (!ok) return 0;
2222
2223     if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2224     {
2225         USER_Driver->pSetWindowStyle( hwnd, offset, &style );
2226         SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2227     }
2228
2229     return retval;
2230 }
2231
2232
2233 /**********************************************************************
2234  *              GetWindowLong (USER.135)
2235  */
2236 LONG WINAPI GetWindowLong16( HWND16 hwnd, INT16 offset )
2237 {
2238     WND *wndPtr;
2239     LONG_PTR retvalue;
2240     BOOL is_winproc = (offset == GWLP_WNDPROC);
2241
2242     if (offset >= 0)
2243     {
2244         if (!(wndPtr = WIN_GetPtr( WIN_Handle32(hwnd) )))
2245         {
2246             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2247             return 0;
2248         }
2249         if (wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
2250         {
2251             if (offset > (int)(wndPtr->cbWndExtra - sizeof(LONG)))
2252             {
2253                 /*
2254                  * Some programs try to access last element from 16 bit
2255                  * code using illegal offset value. Hopefully this is
2256                  * what those programs really expect.
2257                  */
2258                 if (wndPtr->cbWndExtra >= 4 && offset == wndPtr->cbWndExtra - sizeof(WORD))
2259                 {
2260                     INT offset2 = wndPtr->cbWndExtra - sizeof(LONG);
2261                     ERR( "- replaced invalid offset %d with %d\n", offset, offset2 );
2262                     offset = offset2;
2263                 }
2264                 else
2265                 {
2266                     WARN("Invalid offset %d\n", offset );
2267                     WIN_ReleasePtr( wndPtr );
2268                     SetLastError( ERROR_INVALID_INDEX );
2269                     return 0;
2270                 }
2271             }
2272             is_winproc = ((offset == DWLP_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG));
2273             WIN_ReleasePtr( wndPtr );
2274         }
2275     }
2276     retvalue = GetWindowLongA( WIN_Handle32(hwnd), offset );
2277     if (is_winproc) retvalue = (LONG_PTR)WINPROC_GetProc16( (WNDPROC)retvalue, FALSE );
2278     return retvalue;
2279 }
2280
2281
2282 /**********************************************************************
2283  *              GetWindowWord (USER32.@)
2284  */
2285 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
2286 {
2287     switch(offset)
2288     {
2289     case GWLP_ID:
2290     case GWLP_HINSTANCE:
2291     case GWLP_HWNDPARENT:
2292         break;
2293     default:
2294         if (offset < 0)
2295         {
2296             WARN("Invalid offset %d\n", offset );
2297             SetLastError( ERROR_INVALID_INDEX );
2298             return 0;
2299         }
2300         break;
2301     }
2302     return WIN_GetWindowLong( hwnd, offset, sizeof(WORD), FALSE );
2303 }
2304
2305
2306 /**********************************************************************
2307  *              GetWindowLongA (USER32.@)
2308  */
2309 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2310 {
2311     return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), FALSE );
2312 }
2313
2314
2315 /**********************************************************************
2316  *              GetWindowLongW (USER32.@)
2317  */
2318 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2319 {
2320     return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), TRUE );
2321 }
2322
2323
2324 /**********************************************************************
2325  *              SetWindowLong (USER.136)
2326  */
2327 LONG WINAPI SetWindowLong16( HWND16 hwnd, INT16 offset, LONG newval )
2328 {
2329     WND *wndPtr;
2330     BOOL is_winproc = (offset == GWLP_WNDPROC);
2331
2332     if (offset == DWLP_DLGPROC)
2333     {
2334         if (!(wndPtr = WIN_GetPtr( WIN_Handle32(hwnd) )))
2335         {
2336             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2337             return 0;
2338         }
2339         if (wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
2340         {
2341             is_winproc = ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
2342                           (wndPtr->flags & WIN_ISDIALOG));
2343             WIN_ReleasePtr( wndPtr );
2344         }
2345     }
2346
2347     if (is_winproc)
2348     {
2349         WNDPROC new_proc = WINPROC_AllocProc16( (WNDPROC16)newval );
2350         WNDPROC old_proc = (WNDPROC)SetWindowLongPtrA( WIN_Handle32(hwnd), offset, (LONG_PTR)new_proc );
2351         return (LONG)WINPROC_GetProc16( old_proc, FALSE );
2352     }
2353     else return SetWindowLongA( WIN_Handle32(hwnd), offset, newval );
2354 }
2355
2356
2357 /**********************************************************************
2358  *              SetWindowWord (USER32.@)
2359  */
2360 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
2361 {
2362     switch(offset)
2363     {
2364     case GWLP_ID:
2365     case GWLP_HINSTANCE:
2366     case GWLP_HWNDPARENT:
2367         break;
2368     default:
2369         if (offset < 0)
2370         {
2371             WARN("Invalid offset %d\n", offset );
2372             SetLastError( ERROR_INVALID_INDEX );
2373             return 0;
2374         }
2375         break;
2376     }
2377     return WIN_SetWindowLong( hwnd, offset, sizeof(WORD), newval, FALSE );
2378 }
2379
2380
2381 /**********************************************************************
2382  *              SetWindowLongA (USER32.@)
2383  *
2384  * See SetWindowLongW.
2385  */
2386 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2387 {
2388     return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, FALSE );
2389 }
2390
2391
2392 /**********************************************************************
2393  *              SetWindowLongW (USER32.@) Set window attribute
2394  *
2395  * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2396  * value in a window's extra memory.
2397  *
2398  * The _hwnd_ parameter specifies the window.  is the handle to a
2399  * window that has extra memory. The _newval_ parameter contains the
2400  * new attribute or extra memory value.  If positive, the _offset_
2401  * parameter is the byte-addressed location in the window's extra
2402  * memory to set.  If negative, _offset_ specifies the window
2403  * attribute to set, and should be one of the following values:
2404  *
2405  * GWL_EXSTYLE      The window's extended window style
2406  *
2407  * GWL_STYLE        The window's window style.
2408  *
2409  * GWLP_WNDPROC     Pointer to the window's window procedure.
2410  *
2411  * GWLP_HINSTANCE   The window's pplication instance handle.
2412  *
2413  * GWLP_ID          The window's identifier.
2414  *
2415  * GWLP_USERDATA    The window's user-specified data.
2416  *
2417  * If the window is a dialog box, the _offset_ parameter can be one of
2418  * the following values:
2419  *
2420  * DWLP_DLGPROC     The address of the window's dialog box procedure.
2421  *
2422  * DWLP_MSGRESULT   The return value of a message
2423  *                  that the dialog box procedure processed.
2424  *
2425  * DWLP_USER        Application specific information.
2426  *
2427  * RETURNS
2428  *
2429  * If successful, returns the previous value located at _offset_. Otherwise,
2430  * returns 0.
2431  *
2432  * NOTES
2433  *
2434  * Extra memory for a window class is specified by a nonzero cbWndExtra
2435  * parameter of the WNDCLASS structure passed to RegisterClass() at the
2436  * time of class creation.
2437  *
2438  * Using GWL_WNDPROC to set a new window procedure effectively creates
2439  * a window subclass. Use CallWindowProc() in the new windows procedure
2440  * to pass messages to the superclass's window procedure.
2441  *
2442  * The user data is reserved for use by the application which created
2443  * the window.
2444  *
2445  * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2446  * instead, call the EnableWindow() function to change the window's
2447  * disabled state.
2448  *
2449  * Do not use GWL_HWNDPARENT to reset the window's parent, use
2450  * SetParent() instead.
2451  *
2452  * Win95:
2453  * When offset is GWL_STYLE and the calling app's ver is 4.0,
2454  * it sends WM_STYLECHANGING before changing the settings
2455  * and WM_STYLECHANGED afterwards.
2456  * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2457  */
2458 LONG WINAPI SetWindowLongW(
2459     HWND hwnd,  /* [in] window to alter */
2460     INT offset, /* [in] offset, in bytes, of location to alter */
2461     LONG newval /* [in] new value of location */
2462 ) {
2463     return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, TRUE );
2464 }
2465
2466
2467 /*******************************************************************
2468  *              GetWindowTextA (USER32.@)
2469  */
2470 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2471 {
2472     WCHAR *buffer;
2473
2474     if (!lpString) return 0;
2475
2476     if (WIN_IsCurrentProcess( hwnd ))
2477         return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2478
2479     /* when window belongs to other process, don't send a message */
2480     if (nMaxCount <= 0) return 0;
2481     if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2482     get_server_window_text( hwnd, buffer, nMaxCount );
2483     if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2484         lpString[nMaxCount-1] = 0;
2485     HeapFree( GetProcessHeap(), 0, buffer );
2486     return strlen(lpString);
2487 }
2488
2489
2490 /*******************************************************************
2491  *              InternalGetWindowText (USER32.@)
2492  */
2493 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2494 {
2495     WND *win;
2496
2497     if (nMaxCount <= 0) return 0;
2498     if (!(win = WIN_GetPtr( hwnd ))) return 0;
2499     if (win == WND_DESKTOP) lpString[0] = 0;
2500     else if (win != WND_OTHER_PROCESS)
2501     {
2502         if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2503         else lpString[0] = 0;
2504         WIN_ReleasePtr( win );
2505     }
2506     else
2507     {
2508         get_server_window_text( hwnd, lpString, nMaxCount );
2509     }
2510     return strlenW(lpString);
2511 }
2512
2513
2514 /*******************************************************************
2515  *              GetWindowTextW (USER32.@)
2516  */
2517 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2518 {
2519     if (!lpString) return 0;
2520
2521     if (WIN_IsCurrentProcess( hwnd ))
2522         return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2523
2524     /* when window belongs to other process, don't send a message */
2525     if (nMaxCount <= 0) return 0;
2526     get_server_window_text( hwnd, lpString, nMaxCount );
2527     return strlenW(lpString);
2528 }
2529
2530
2531 /*******************************************************************
2532  *              SetWindowTextA (USER32.@)
2533  *              SetWindowText  (USER32.@)
2534  */
2535 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2536 {
2537     if (is_broadcast(hwnd))
2538     {
2539         SetLastError( ERROR_INVALID_PARAMETER );
2540         return FALSE;
2541     }
2542     if (!WIN_IsCurrentProcess( hwnd ))
2543         WARN( "setting text %s of other process window %p should not use SendMessage\n",
2544                debugstr_a(lpString), hwnd );
2545     return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2546 }
2547
2548
2549 /*******************************************************************
2550  *              SetWindowTextW (USER32.@)
2551  */
2552 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2553 {
2554     if (is_broadcast(hwnd))
2555     {
2556         SetLastError( ERROR_INVALID_PARAMETER );
2557         return FALSE;
2558     }
2559     if (!WIN_IsCurrentProcess( hwnd ))
2560         WARN( "setting text %s of other process window %p should not use SendMessage\n",
2561                debugstr_w(lpString), hwnd );
2562     return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2563 }
2564
2565
2566 /*******************************************************************
2567  *              GetWindowTextLengthA (USER32.@)
2568  */
2569 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2570 {
2571     return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2572 }
2573
2574 /*******************************************************************
2575  *              GetWindowTextLengthW (USER32.@)
2576  */
2577 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2578 {
2579     return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2580 }
2581
2582
2583 /*******************************************************************
2584  *              IsWindow (USER32.@)
2585  */
2586 BOOL WINAPI IsWindow( HWND hwnd )
2587 {
2588     WND *ptr;
2589     BOOL ret;
2590
2591     if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2592     if (ptr == WND_DESKTOP) return TRUE;
2593
2594     if (ptr != WND_OTHER_PROCESS)
2595     {
2596         WIN_ReleasePtr( ptr );
2597         return TRUE;
2598     }
2599
2600     /* check other processes */
2601     SERVER_START_REQ( get_window_info )
2602     {
2603         req->handle = wine_server_user_handle( hwnd );
2604         ret = !wine_server_call_err( req );
2605     }
2606     SERVER_END_REQ;
2607     return ret;
2608 }
2609
2610
2611 /***********************************************************************
2612  *              GetWindowThreadProcessId (USER32.@)
2613  */
2614 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2615 {
2616     WND *ptr;
2617     DWORD tid = 0;
2618
2619     if (!(ptr = WIN_GetPtr( hwnd )))
2620     {
2621         SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2622         return 0;
2623     }
2624
2625     if (ptr != WND_OTHER_PROCESS && ptr != WND_DESKTOP)
2626     {
2627         /* got a valid window */
2628         tid = ptr->tid;
2629         if (process) *process = GetCurrentProcessId();
2630         WIN_ReleasePtr( ptr );
2631         return tid;
2632     }
2633
2634     /* check other processes */
2635     SERVER_START_REQ( get_window_info )
2636     {
2637         req->handle = wine_server_user_handle( hwnd );
2638         if (!wine_server_call_err( req ))
2639         {
2640             tid = (DWORD)reply->tid;
2641             if (process) *process = (DWORD)reply->pid;
2642         }
2643     }
2644     SERVER_END_REQ;
2645     return tid;
2646 }
2647
2648
2649 /*****************************************************************
2650  *              GetParent (USER32.@)
2651  */
2652 HWND WINAPI GetParent( HWND hwnd )
2653 {
2654     WND *wndPtr;
2655     HWND retvalue = 0;
2656
2657     if (!(wndPtr = WIN_GetPtr( hwnd )))
2658     {
2659         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2660         return 0;
2661     }
2662     if (wndPtr == WND_DESKTOP) return 0;
2663     if (wndPtr == WND_OTHER_PROCESS)
2664     {
2665         LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2666         if (style & (WS_POPUP | WS_CHILD))
2667         {
2668             SERVER_START_REQ( get_window_tree )
2669             {
2670                 req->handle = wine_server_user_handle( hwnd );
2671                 if (!wine_server_call_err( req ))
2672                 {
2673                     if (style & WS_POPUP) retvalue = wine_server_ptr_handle( reply->owner );
2674                     else if (style & WS_CHILD) retvalue = wine_server_ptr_handle( reply->parent );
2675                 }
2676             }
2677             SERVER_END_REQ;
2678         }
2679     }
2680     else
2681     {
2682         if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2683         else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2684         WIN_ReleasePtr( wndPtr );
2685     }
2686     return retvalue;
2687 }
2688
2689
2690 /*****************************************************************
2691  *              GetAncestor (USER32.@)
2692  */
2693 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2694 {
2695     WND *win;
2696     HWND *list, ret = 0;
2697
2698     switch(type)
2699     {
2700     case GA_PARENT:
2701         if (!(win = WIN_GetPtr( hwnd )))
2702         {
2703             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2704             return 0;
2705         }
2706         if (win == WND_DESKTOP) return 0;
2707         if (win != WND_OTHER_PROCESS)
2708         {
2709             ret = win->parent;
2710             WIN_ReleasePtr( win );
2711         }
2712         else /* need to query the server */
2713         {
2714             SERVER_START_REQ( get_window_tree )
2715             {
2716                 req->handle = wine_server_user_handle( hwnd );
2717                 if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->parent );
2718             }
2719             SERVER_END_REQ;
2720         }
2721         break;
2722
2723     case GA_ROOT:
2724         if (!(list = list_window_parents( hwnd ))) return 0;
2725
2726         if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd );  /* top-level window */
2727         else
2728         {
2729             int count = 2;
2730             while (list[count]) count++;
2731             ret = list[count - 2];  /* get the one before the desktop */
2732         }
2733         HeapFree( GetProcessHeap(), 0, list );
2734         break;
2735
2736     case GA_ROOTOWNER:
2737         if (is_desktop_window( hwnd )) return 0;
2738         ret = WIN_GetFullHandle( hwnd );
2739         for (;;)
2740         {
2741             HWND parent = GetParent( ret );
2742             if (!parent) break;
2743             ret = parent;
2744         }
2745         break;
2746     }
2747     return ret;
2748 }
2749
2750
2751 /*****************************************************************
2752  *              SetParent (USER32.@)
2753  */
2754 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2755 {
2756     HWND full_handle;
2757     HWND old_parent = 0;
2758     BOOL was_visible;
2759     WND *wndPtr;
2760     BOOL ret;
2761
2762     if (is_broadcast(hwnd) || is_broadcast(parent))
2763     {
2764         SetLastError(ERROR_INVALID_PARAMETER);
2765         return 0;
2766     }
2767
2768     if (!parent) parent = GetDesktopWindow();
2769     else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
2770     else parent = WIN_GetFullHandle( parent );
2771
2772     if (!IsWindow( parent ))
2773     {
2774         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2775         return 0;
2776     }
2777
2778     /* Some applications try to set a child as a parent */
2779     if (IsChild(hwnd, parent))
2780     {
2781         SetLastError( ERROR_INVALID_PARAMETER );
2782         return 0;
2783     }
2784
2785     if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2786         return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2787
2788     /* Windows hides the window first, then shows it again
2789      * including the WM_SHOWWINDOW messages and all */
2790     was_visible = ShowWindow( hwnd, SW_HIDE );
2791
2792     wndPtr = WIN_GetPtr( hwnd );
2793     if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
2794
2795     SERVER_START_REQ( set_parent )
2796     {
2797         req->handle = wine_server_user_handle( hwnd );
2798         req->parent = wine_server_user_handle( parent );
2799         if ((ret = !wine_server_call( req )))
2800         {
2801             old_parent = wine_server_ptr_handle( reply->old_parent );
2802             wndPtr->parent = parent = wine_server_ptr_handle( reply->full_parent );
2803         }
2804
2805     }
2806     SERVER_END_REQ;
2807     WIN_ReleasePtr( wndPtr );
2808     if (!ret) return 0;
2809
2810     USER_Driver->pSetParent( full_handle, parent, old_parent );
2811
2812     /* SetParent additionally needs to make hwnd the topmost window
2813        in the x-order and send the expected WM_WINDOWPOSCHANGING and
2814        WM_WINDOWPOSCHANGED notification messages.
2815     */
2816     SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0,
2817                   SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | (was_visible ? SWP_SHOWWINDOW : 0) );
2818     /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
2819      * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
2820
2821     return old_parent;
2822 }
2823
2824
2825 /*******************************************************************
2826  *              IsChild (USER32.@)
2827  */
2828 BOOL WINAPI IsChild( HWND parent, HWND child )
2829 {
2830     HWND *list = list_window_parents( child );
2831     int i;
2832     BOOL ret;
2833
2834     if (!list) return FALSE;
2835     parent = WIN_GetFullHandle( parent );
2836     for (i = 0; list[i]; i++) if (list[i] == parent) break;
2837     ret = list[i] && list[i+1];
2838     HeapFree( GetProcessHeap(), 0, list );
2839     return ret;
2840 }
2841
2842
2843 /***********************************************************************
2844  *              IsWindowVisible (USER32.@)
2845  */
2846 BOOL WINAPI IsWindowVisible( HWND hwnd )
2847 {
2848     HWND *list;
2849     BOOL retval = TRUE;
2850     int i;
2851
2852     if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2853     if (!(list = list_window_parents( hwnd ))) return TRUE;
2854     if (list[0])
2855     {
2856         for (i = 0; list[i+1]; i++)
2857             if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2858         retval = !list[i+1] && (list[i] == GetDesktopWindow());  /* top message window isn't visible */
2859     }
2860     HeapFree( GetProcessHeap(), 0, list );
2861     return retval;
2862 }
2863
2864
2865 /***********************************************************************
2866  *           WIN_IsWindowDrawable
2867  *
2868  * hwnd is drawable when it is visible, all parents are not
2869  * minimized, and it is itself not minimized unless we are
2870  * trying to draw its default class icon.
2871  */
2872 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2873 {
2874     HWND *list;
2875     BOOL retval = TRUE;
2876     int i;
2877     LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2878
2879     if (!(style & WS_VISIBLE)) return FALSE;
2880     if ((style & WS_MINIMIZE) && icon && GetClassLongPtrW( hwnd, GCLP_HICON ))  return FALSE;
2881
2882     if (!(list = list_window_parents( hwnd ))) return TRUE;
2883     if (list[0])
2884     {
2885         for (i = 0; list[i+1]; i++)
2886             if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2887                 break;
2888         retval = !list[i+1] && (list[i] == GetDesktopWindow());  /* top message window isn't visible */
2889     }
2890     HeapFree( GetProcessHeap(), 0, list );
2891     return retval;
2892 }
2893
2894
2895 /*******************************************************************
2896  *              GetTopWindow (USER32.@)
2897  */
2898 HWND WINAPI GetTopWindow( HWND hwnd )
2899 {
2900     if (!hwnd) hwnd = GetDesktopWindow();
2901     return GetWindow( hwnd, GW_CHILD );
2902 }
2903
2904
2905 /*******************************************************************
2906  *              GetWindow (USER32.@)
2907  */
2908 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2909 {
2910     HWND retval = 0;
2911
2912     if (rel == GW_OWNER)  /* this one may be available locally */
2913     {
2914         WND *wndPtr = WIN_GetPtr( hwnd );
2915         if (!wndPtr)
2916         {
2917             SetLastError( ERROR_INVALID_HANDLE );
2918             return 0;
2919         }
2920         if (wndPtr == WND_DESKTOP) return 0;
2921         if (wndPtr != WND_OTHER_PROCESS)
2922         {
2923             retval = wndPtr->owner;
2924             WIN_ReleasePtr( wndPtr );
2925             return retval;
2926         }
2927         /* else fall through to server call */
2928     }
2929
2930     SERVER_START_REQ( get_window_tree )
2931     {
2932         req->handle = wine_server_user_handle( hwnd );
2933         if (!wine_server_call_err( req ))
2934         {
2935             switch(rel)
2936             {
2937             case GW_HWNDFIRST:
2938                 retval = wine_server_ptr_handle( reply->first_sibling );
2939                 break;
2940             case GW_HWNDLAST:
2941                 retval = wine_server_ptr_handle( reply->last_sibling );
2942                 break;
2943             case GW_HWNDNEXT:
2944                 retval = wine_server_ptr_handle( reply->next_sibling );
2945                 break;
2946             case GW_HWNDPREV:
2947                 retval = wine_server_ptr_handle( reply->prev_sibling );
2948                 break;
2949             case GW_OWNER:
2950                 retval = wine_server_ptr_handle( reply->owner );
2951                 break;
2952             case GW_CHILD:
2953                 retval = wine_server_ptr_handle( reply->first_child );
2954                 break;
2955             }
2956         }
2957     }
2958     SERVER_END_REQ;
2959     return retval;
2960 }
2961
2962
2963 /*******************************************************************
2964  *              ShowOwnedPopups (USER32.@)
2965  */
2966 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2967 {
2968     int count = 0;
2969     WND *pWnd;
2970     HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2971
2972     if (!win_array) return TRUE;
2973
2974     while (win_array[count]) count++;
2975     while (--count >= 0)
2976     {
2977         if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2978         if (!(pWnd = WIN_GetPtr( win_array[count] ))) continue;
2979         if (pWnd == WND_OTHER_PROCESS) continue;
2980         if (fShow)
2981         {
2982             if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2983             {
2984                 WIN_ReleasePtr( pWnd );
2985                 /* In Windows, ShowOwnedPopups(TRUE) generates
2986                  * WM_SHOWWINDOW messages with SW_PARENTOPENING,
2987                  * regardless of the state of the owner
2988                  */
2989                 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
2990                 continue;
2991             }
2992         }
2993         else
2994         {
2995             if (pWnd->dwStyle & WS_VISIBLE)
2996             {
2997                 WIN_ReleasePtr( pWnd );
2998                 /* In Windows, ShowOwnedPopups(FALSE) generates
2999                  * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
3000                  * regardless of the state of the owner
3001                  */
3002                 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
3003                 continue;
3004             }
3005         }
3006         WIN_ReleasePtr( pWnd );
3007     }
3008     HeapFree( GetProcessHeap(), 0, win_array );
3009     return TRUE;
3010 }
3011
3012
3013 /*******************************************************************
3014  *              GetLastActivePopup (USER32.@)
3015  */
3016 HWND WINAPI GetLastActivePopup( HWND hwnd )
3017 {
3018     HWND retval = hwnd;
3019
3020     SERVER_START_REQ( get_window_info )
3021     {
3022         req->handle = wine_server_user_handle( hwnd );
3023         if (!wine_server_call_err( req )) retval = wine_server_ptr_handle( reply->last_active );
3024     }
3025     SERVER_END_REQ;
3026     return retval;
3027 }
3028
3029
3030 /*******************************************************************
3031  *           WIN_ListChildren
3032  *
3033  * Build an array of the children of a given window. The array must be
3034  * freed with HeapFree. Returns NULL when no windows are found.
3035  */
3036 HWND *WIN_ListChildren( HWND hwnd )
3037 {
3038     if (!hwnd)
3039     {
3040         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3041         return NULL;
3042     }
3043     return list_window_children( 0, hwnd, NULL, 0 );
3044 }
3045
3046
3047 /*******************************************************************
3048  *              EnumWindows (USER32.@)
3049  */
3050 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
3051 {
3052     HWND *list;
3053     BOOL ret = TRUE;
3054     int i;
3055
3056     USER_CheckNotLock();
3057
3058     /* We have to build a list of all windows first, to avoid */
3059     /* unpleasant side-effects, for instance if the callback */
3060     /* function changes the Z-order of the windows.          */
3061
3062     if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
3063
3064     /* Now call the callback function for every window */
3065
3066     for (i = 0; list[i]; i++)
3067     {
3068         /* Make sure that the window still exists */
3069         if (!IsWindow( list[i] )) continue;
3070         if (!(ret = lpEnumFunc( list[i], lParam ))) break;
3071     }
3072     HeapFree( GetProcessHeap(), 0, list );
3073     return ret;
3074 }
3075
3076
3077 /**********************************************************************
3078  *              EnumThreadWindows (USER32.@)
3079  */
3080 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
3081 {
3082     HWND *list;
3083     int i;
3084
3085     USER_CheckNotLock();
3086
3087     if (!(list = list_window_children( 0, GetDesktopWindow(), NULL, id ))) return TRUE;
3088
3089     /* Now call the callback function for every window */
3090
3091     for (i = 0; list[i]; i++)
3092         if (!func( list[i], lParam )) break;
3093     HeapFree( GetProcessHeap(), 0, list );
3094     return TRUE;
3095 }
3096
3097
3098 /***********************************************************************
3099  *              EnumDesktopWindows   (USER32.@)
3100  */
3101 BOOL WINAPI EnumDesktopWindows( HDESK desktop, WNDENUMPROC func, LPARAM lparam )
3102 {
3103     HWND *list;
3104     int i;
3105
3106     USER_CheckNotLock();
3107
3108     if (!(list = list_window_children( desktop, 0, NULL, 0 ))) return TRUE;
3109
3110     for (i = 0; list[i]; i++)
3111         if (!func( list[i], lparam )) break;
3112     HeapFree( GetProcessHeap(), 0, list );
3113     return TRUE;
3114 }
3115
3116
3117 /**********************************************************************
3118  *           WIN_EnumChildWindows
3119  *
3120  * Helper function for EnumChildWindows().
3121  */
3122 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
3123 {
3124     HWND *childList;
3125     BOOL ret = FALSE;
3126
3127     for ( ; *list; list++)
3128     {
3129         /* Make sure that the window still exists */
3130         if (!IsWindow( *list )) continue;
3131         /* Build children list first */
3132         childList = WIN_ListChildren( *list );
3133
3134         ret = func( *list, lParam );
3135
3136         if (childList)
3137         {
3138             if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
3139             HeapFree( GetProcessHeap(), 0, childList );
3140         }
3141         if (!ret) return FALSE;
3142     }
3143     return TRUE;
3144 }
3145
3146
3147 /**********************************************************************
3148  *              EnumChildWindows (USER32.@)
3149  */
3150 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
3151 {
3152     HWND *list;
3153     BOOL ret;
3154
3155     USER_CheckNotLock();
3156
3157     if (!(list = WIN_ListChildren( parent ))) return FALSE;
3158     ret = WIN_EnumChildWindows( list, func, lParam );
3159     HeapFree( GetProcessHeap(), 0, list );
3160     return ret;
3161 }
3162
3163
3164 /*******************************************************************
3165  *              AnyPopup (USER.52)
3166  */
3167 BOOL16 WINAPI AnyPopup16(void)
3168 {
3169     return AnyPopup();
3170 }
3171
3172
3173 /*******************************************************************
3174  *              AnyPopup (USER32.@)
3175  */
3176 BOOL WINAPI AnyPopup(void)
3177 {
3178     int i;
3179     BOOL retvalue;
3180     HWND *list = WIN_ListChildren( GetDesktopWindow() );
3181
3182     if (!list) return FALSE;
3183     for (i = 0; list[i]; i++)
3184     {
3185         if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
3186     }
3187     retvalue = (list[i] != 0);
3188     HeapFree( GetProcessHeap(), 0, list );
3189     return retvalue;
3190 }
3191
3192
3193 /*******************************************************************
3194  *              FlashWindow (USER32.@)
3195  */
3196 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3197 {
3198     WND *wndPtr;
3199
3200     TRACE("%p\n", hWnd);
3201
3202     if (IsIconic( hWnd ))
3203     {
3204         RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
3205
3206         wndPtr = WIN_GetPtr(hWnd);
3207         if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3208         if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
3209         {
3210             wndPtr->flags |= WIN_NCACTIVATED;
3211         }
3212         else
3213         {
3214             wndPtr->flags &= ~WIN_NCACTIVATED;
3215         }
3216         WIN_ReleasePtr( wndPtr );
3217         return TRUE;
3218     }
3219     else
3220     {
3221         WPARAM wparam;
3222
3223         wndPtr = WIN_GetPtr(hWnd);
3224         if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3225         hWnd = wndPtr->hwndSelf;  /* make it a full handle */
3226
3227         if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3228         else wparam = (hWnd == GetForegroundWindow());
3229
3230         WIN_ReleasePtr( wndPtr );
3231         SendMessageW( hWnd, WM_NCACTIVATE, wparam, 0 );
3232         return wparam;
3233     }
3234 }
3235
3236 /*******************************************************************
3237  *              FlashWindowEx (USER32.@)
3238  */
3239 BOOL WINAPI FlashWindowEx( PFLASHWINFO pfwi )
3240 {
3241     FIXME("%p\n", pfwi);
3242     return TRUE;
3243 }
3244
3245 /*******************************************************************
3246  *              GetWindowContextHelpId (USER32.@)
3247  */
3248 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3249 {
3250     DWORD retval;
3251     WND *wnd = WIN_GetPtr( hwnd );
3252     if (!wnd || wnd == WND_DESKTOP) return 0;
3253     if (wnd == WND_OTHER_PROCESS)
3254     {
3255         if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3256         return 0;
3257     }
3258     retval = wnd->helpContext;
3259     WIN_ReleasePtr( wnd );
3260     return retval;
3261 }
3262
3263
3264 /*******************************************************************
3265  *              SetWindowContextHelpId (USER32.@)
3266  */
3267 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3268 {
3269     WND *wnd = WIN_GetPtr( hwnd );
3270     if (!wnd || wnd == WND_DESKTOP) return FALSE;
3271     if (wnd == WND_OTHER_PROCESS)
3272     {
3273         if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3274         return 0;
3275     }
3276     wnd->helpContext = id;
3277     WIN_ReleasePtr( wnd );
3278     return TRUE;
3279 }
3280
3281
3282 /*******************************************************************
3283  *              DragDetect (USER32.@)
3284  */
3285 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3286 {
3287     MSG msg;
3288     RECT rect;
3289     WORD wDragWidth = GetSystemMetrics(SM_CXDRAG);
3290     WORD wDragHeight= GetSystemMetrics(SM_CYDRAG);
3291
3292     rect.left = pt.x - wDragWidth;
3293     rect.right = pt.x + wDragWidth;
3294
3295     rect.top = pt.y - wDragHeight;
3296     rect.bottom = pt.y + wDragHeight;
3297
3298     SetCapture(hWnd);
3299
3300     while(1)
3301     {
3302         while (PeekMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ))
3303         {
3304             if( msg.message == WM_LBUTTONUP )
3305             {
3306                 ReleaseCapture();
3307                 return 0;
3308             }
3309             if( msg.message == WM_MOUSEMOVE )
3310             {
3311                 POINT tmp;
3312                 tmp.x = (short)LOWORD(msg.lParam);
3313                 tmp.y = (short)HIWORD(msg.lParam);
3314                 if( !PtInRect( &rect, tmp ))
3315                 {
3316                     ReleaseCapture();
3317                     return 1;
3318                 }
3319             }
3320         }
3321         WaitMessage();
3322     }
3323     return 0;
3324 }
3325
3326 /******************************************************************************
3327  *              GetWindowModuleFileNameA (USER32.@)
3328  */
3329 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR module, UINT size )
3330 {
3331     WND *win;
3332     HINSTANCE hinst;
3333
3334     TRACE( "%p, %p, %u\n", hwnd, module, size );
3335
3336     win = WIN_GetPtr( hwnd );
3337     if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3338     {
3339         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3340         return 0;
3341     }
3342     hinst = win->hInstance;
3343     WIN_ReleasePtr( win );
3344
3345     return GetModuleFileNameA( hinst, module, size );
3346 }
3347
3348 /******************************************************************************
3349  *              GetWindowModuleFileNameW (USER32.@)
3350  */
3351 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR module, UINT size )
3352 {
3353     WND *win;
3354     HINSTANCE hinst;
3355
3356     TRACE( "%p, %p, %u\n", hwnd, module, size );
3357
3358     win = WIN_GetPtr( hwnd );
3359     if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3360     {
3361         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3362         return 0;
3363     }
3364     hinst = win->hInstance;
3365     WIN_ReleasePtr( win );
3366
3367     return GetModuleFileNameW( hinst, module, size );
3368 }
3369
3370 /******************************************************************************
3371  *              GetWindowInfo (USER32.@)
3372  *
3373  * Note: tests show that Windows doesn't check cbSize of the structure.
3374  */
3375 BOOL WINAPI GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3376 {
3377     if (!pwi) return FALSE;
3378     if (!IsWindow(hwnd)) return FALSE;
3379
3380     GetWindowRect(hwnd, &pwi->rcWindow);
3381     GetClientRect(hwnd, &pwi->rcClient);
3382     /* translate to screen coordinates */
3383     MapWindowPoints(hwnd, 0, (LPPOINT)&pwi->rcClient, 2);
3384
3385     pwi->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
3386     pwi->dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3387     pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3388
3389     pwi->cxWindowBorders = pwi->rcClient.left - pwi->rcWindow.left;
3390     pwi->cyWindowBorders = pwi->rcWindow.bottom - pwi->rcClient.bottom;
3391
3392     pwi->atomWindowType = GetClassLongW( hwnd, GCW_ATOM );
3393     pwi->wCreatorVersion = 0x0400;
3394
3395     return TRUE;
3396 }
3397
3398 /******************************************************************************
3399  *              SwitchDesktop (USER32.@)
3400  *
3401  * NOTES: Sets the current input or interactive desktop.
3402  */
3403 BOOL WINAPI SwitchDesktop( HDESK hDesktop)
3404 {
3405     FIXME("SwitchDesktop(hwnd %p) stub!\n", hDesktop);
3406     return TRUE;
3407 }
3408
3409 /*****************************************************************************
3410  *              SetLayeredWindowAttributes (USER32.@)
3411  */
3412 BOOL WINAPI SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, DWORD flags )
3413 {
3414     BOOL ret;
3415
3416     TRACE("(%p,%08x,%d,%x): stub!\n", hwnd, key, alpha, flags);
3417
3418     SERVER_START_REQ( set_window_layered_info )
3419     {
3420         req->handle = wine_server_user_handle( hwnd );
3421         req->color_key = key;
3422         req->alpha = alpha;
3423         req->flags = flags;
3424         ret = !wine_server_call_err( req );
3425     }
3426     SERVER_END_REQ;
3427
3428     if (ret) USER_Driver->pSetLayeredWindowAttributes( hwnd, key, alpha, flags );
3429
3430     return ret;
3431 }
3432
3433
3434 /*****************************************************************************
3435  *              GetLayeredWindowAttributes (USER32.@)
3436  */
3437 BOOL WINAPI GetLayeredWindowAttributes( HWND hwnd, COLORREF *key, BYTE *alpha, DWORD *flags )
3438 {
3439     BOOL ret;
3440
3441     SERVER_START_REQ( get_window_layered_info )
3442     {
3443         req->handle = wine_server_user_handle( hwnd );
3444         if ((ret = !wine_server_call_err( req )))
3445         {
3446             if (key) *key = reply->color_key;
3447             if (alpha) *alpha = reply->alpha;
3448             if (flags) *flags = reply->flags;
3449         }
3450     }
3451     SERVER_END_REQ;
3452
3453     return ret;
3454 }
3455
3456
3457 /*****************************************************************************
3458  *              UpdateLayeredWindowIndirect  (USER32.@)
3459  */
3460 BOOL WINAPI UpdateLayeredWindowIndirect( HWND hwnd, const UPDATELAYEREDWINDOWINFO *info )
3461 {
3462     BYTE alpha = 0xff;
3463
3464     if (!(info->dwFlags & ULW_EX_NORESIZE) && (info->pptDst || info->psize))
3465     {
3466         int x = 0, y = 0, cx = 0, cy = 0;
3467         DWORD flags = SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOSENDCHANGING;
3468
3469         if (info->pptDst)
3470         {
3471             x = info->pptDst->x;
3472             y = info->pptDst->y;
3473             flags &= ~SWP_NOMOVE;
3474         }
3475         if (info->psize)
3476         {
3477             cx = info->psize->cx;
3478             cy = info->psize->cy;
3479             flags &= ~SWP_NOSIZE;
3480         }
3481         TRACE( "moving window %p pos %d,%d %dx%x\n", hwnd, x, y, cx, cy );
3482         SetWindowPos( hwnd, 0, x, y, cx, cy, flags );
3483     }
3484
3485     if (info->hdcSrc)
3486     {
3487         RECT rect;
3488         HDC hdc = GetDCEx( hwnd, 0, DCX_CACHE );
3489
3490         if (hdc)
3491         {
3492             int x = 0, y = 0;
3493
3494             GetClientRect( hwnd, &rect );
3495             if (info->pptSrc)
3496             {
3497                 x = info->pptSrc->x;
3498                 y = info->pptSrc->y;
3499             }
3500             /* FIXME: intersect rect with info->prcDirty */
3501             TRACE( "copying window %p pos %d,%d\n", hwnd, x, y );
3502             BitBlt( hdc, rect.left, rect.top, rect.right, rect.bottom,
3503                     info->hdcSrc, rect.left + x, rect.top + y, SRCCOPY );
3504             ReleaseDC( hwnd, hdc );
3505         }
3506     }
3507
3508     if (info->pblend && !(info->dwFlags & ULW_OPAQUE)) alpha = info->pblend->SourceConstantAlpha;
3509     TRACE( "setting window %p alpha %u\n", hwnd, alpha );
3510     USER_Driver->pSetLayeredWindowAttributes( hwnd, info->crKey, alpha,
3511                                               info->dwFlags & (LWA_ALPHA | LWA_COLORKEY) );
3512     return TRUE;
3513 }
3514
3515
3516 /*****************************************************************************
3517  *              UpdateLayeredWindow (USER32.@)
3518  */
3519 BOOL WINAPI UpdateLayeredWindow( HWND hwnd, HDC hdcDst, POINT *pptDst, SIZE *psize,
3520                                  HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend,
3521                                  DWORD dwFlags)
3522 {
3523     UPDATELAYEREDWINDOWINFO info;
3524
3525     info.cbSize   = sizeof(info);
3526     info.hdcDst   = hdcDst;
3527     info.pptDst   = pptDst;
3528     info.psize    = psize;
3529     info.hdcSrc   = hdcSrc;
3530     info.pptSrc   = pptSrc;
3531     info.crKey    = crKey;
3532     info.pblend   = pblend;
3533     info.dwFlags  = dwFlags;
3534     info.prcDirty = NULL;
3535     return UpdateLayeredWindowIndirect( hwnd, &info );
3536 }
3537
3538 /* 64bit versions */
3539
3540 #ifdef GetWindowLongPtrW
3541 #undef GetWindowLongPtrW
3542 #endif
3543
3544 #ifdef GetWindowLongPtrA
3545 #undef GetWindowLongPtrA
3546 #endif
3547
3548 #ifdef SetWindowLongPtrW
3549 #undef SetWindowLongPtrW
3550 #endif
3551
3552 #ifdef SetWindowLongPtrA
3553 #undef SetWindowLongPtrA
3554 #endif
3555
3556 /*****************************************************************************
3557  *              GetWindowLongPtrW (USER32.@)
3558  */
3559 LONG_PTR WINAPI GetWindowLongPtrW( HWND hwnd, INT offset )
3560 {
3561     return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), TRUE );
3562 }
3563
3564 /*****************************************************************************
3565  *              GetWindowLongPtrA (USER32.@)
3566  */
3567 LONG_PTR WINAPI GetWindowLongPtrA( HWND hwnd, INT offset )
3568 {
3569     return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), FALSE );
3570 }
3571
3572 /*****************************************************************************
3573  *              SetWindowLongPtrW (USER32.@)
3574  */
3575 LONG_PTR WINAPI SetWindowLongPtrW( HWND hwnd, INT offset, LONG_PTR newval )
3576 {
3577     return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, TRUE );
3578 }
3579
3580 /*****************************************************************************
3581  *              SetWindowLongPtrA (USER32.@)
3582  */
3583 LONG_PTR WINAPI SetWindowLongPtrA( HWND hwnd, INT offset, LONG_PTR newval )
3584 {
3585     return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, FALSE );
3586 }