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