user32/tests: Fix some more message test failures.
[wine/wine64.git] / dlls / user32 / win.c
blobddea523ae85c90dee199882caa7db324760fd7a9
1 /*
2 * Window related functions
4 * Copyright 1993, 1994 Alexandre Julliard
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.
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.
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
21 #include "config.h"
22 #include "wine/port.h"
24 #include <assert.h>
25 #include <stdarg.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include "windef.h"
29 #include "winbase.h"
30 #include "wine/winbase16.h"
31 #include "wine/winuser16.h"
32 #include "wownt32.h"
33 #include "wine/server.h"
34 #include "wine/unicode.h"
35 #include "win.h"
36 #include "user_private.h"
37 #include "controls.h"
38 #include "winerror.h"
39 #include "wine/debug.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(win);
43 #define NB_USER_HANDLES ((LAST_USER_HANDLE - FIRST_USER_HANDLE + 1) >> 1)
44 #define USER_HANDLE_TO_INDEX(hwnd) ((LOWORD(hwnd) - FIRST_USER_HANDLE) >> 1)
46 /**********************************************************************/
48 /* helper for Get/SetWindowLong */
49 static inline LONG_PTR get_win_data( const void *ptr, UINT size )
51 if (size == sizeof(WORD))
53 WORD ret;
54 memcpy( &ret, ptr, sizeof(ret) );
55 return ret;
57 else if (size == sizeof(DWORD))
59 DWORD ret;
60 memcpy( &ret, ptr, sizeof(ret) );
61 return ret;
63 else
65 LONG_PTR ret;
66 memcpy( &ret, ptr, sizeof(ret) );
67 return ret;
71 /* helper for Get/SetWindowLong */
72 static inline void set_win_data( void *ptr, LONG_PTR val, UINT size )
74 if (size == sizeof(WORD))
76 WORD newval = val;
77 memcpy( ptr, &newval, sizeof(newval) );
79 else if (size == sizeof(DWORD))
81 DWORD newval = val;
82 memcpy( ptr, &newval, sizeof(newval) );
84 else
86 memcpy( ptr, &val, sizeof(val) );
91 static void *user_handles[NB_USER_HANDLES];
93 /***********************************************************************
94 * create_window_handle
96 * Create a window handle with the server.
98 static WND *create_window_handle( HWND parent, HWND owner, LPCWSTR name,
99 HINSTANCE instance, BOOL unicode )
101 WORD index;
102 WND *win;
103 HWND full_parent = 0, full_owner = 0;
104 struct tagCLASS *class = NULL;
105 user_handle_t handle = 0;
106 int extra_bytes = 0;
108 /* if 16-bit instance, map to module handle */
109 if (instance && !HIWORD(instance))
110 instance = HINSTANCE_32(GetExePtr(HINSTANCE_16(instance)));
112 SERVER_START_REQ( create_window )
114 req->parent = parent;
115 req->owner = owner;
116 req->instance = instance;
117 if (!(req->atom = get_int_atom_value( name )) && name)
118 wine_server_add_data( req, name, strlenW(name)*sizeof(WCHAR) );
119 if (!wine_server_call_err( req ))
121 handle = reply->handle;
122 full_parent = reply->parent;
123 full_owner = reply->owner;
124 extra_bytes = reply->extra;
125 class = reply->class_ptr;
128 SERVER_END_REQ;
130 if (!handle)
132 WARN( "error %d creating window\n", GetLastError() );
133 return NULL;
136 if (!(win = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
137 sizeof(WND) + extra_bytes - sizeof(win->wExtra) )))
139 SERVER_START_REQ( destroy_window )
141 req->handle = handle;
142 wine_server_call( req );
144 SERVER_END_REQ;
145 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
146 return NULL;
149 if (!parent) /* if parent is 0 we don't have a desktop window yet */
151 struct user_thread_info *thread_info = get_user_thread_info();
153 if (name == (LPCWSTR)DESKTOP_CLASS_ATOM)
155 if (!thread_info->top_window) thread_info->top_window = full_parent ? full_parent : handle;
156 else assert( full_parent == thread_info->top_window );
157 if (full_parent && !USER_Driver->pCreateDesktopWindow( thread_info->top_window ))
158 ERR( "failed to create desktop window\n" );
160 else /* HWND_MESSAGE parent */
162 if (!thread_info->msg_window && !full_parent) thread_info->msg_window = handle;
166 USER_Lock();
168 index = USER_HANDLE_TO_INDEX(handle);
169 assert( index < NB_USER_HANDLES );
170 user_handles[index] = win;
171 win->hwndSelf = handle;
172 win->parent = full_parent;
173 win->owner = full_owner;
174 win->class = class;
175 win->winproc = get_class_winproc( class );
176 win->dwMagic = WND_MAGIC;
177 win->cbWndExtra = extra_bytes;
178 if (WINPROC_IsUnicode( win->winproc, unicode )) win->flags |= WIN_ISUNICODE;
179 return win;
183 /***********************************************************************
184 * free_window_handle
186 * Free a window handle.
188 static WND *free_window_handle( HWND hwnd )
190 WND *ptr;
191 WORD index = USER_HANDLE_TO_INDEX(hwnd);
193 if (index >= NB_USER_HANDLES) return NULL;
194 USER_Lock();
195 if ((ptr = user_handles[index]))
197 SERVER_START_REQ( destroy_window )
199 req->handle = hwnd;
200 if (!wine_server_call_err( req ))
202 user_handles[index] = NULL;
203 ptr->dwMagic = 0;
205 else
206 ptr = NULL;
208 SERVER_END_REQ;
210 USER_Unlock();
211 HeapFree( GetProcessHeap(), 0, ptr );
212 return ptr;
216 /*******************************************************************
217 * list_window_children
219 * Build an array of the children of a given window. The array must be
220 * freed with HeapFree. Returns NULL when no windows are found.
222 static HWND *list_window_children( HDESK desktop, HWND hwnd, LPCWSTR class, DWORD tid )
224 HWND *list;
225 int size = 128;
227 for (;;)
229 int count = 0;
231 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) break;
233 SERVER_START_REQ( get_window_children )
235 req->desktop = desktop;
236 req->parent = hwnd;
237 req->tid = tid;
238 if (!(req->atom = get_int_atom_value( class )) && class)
239 wine_server_add_data( req, class, strlenW(class)*sizeof(WCHAR) );
240 wine_server_set_reply( req, list, (size-1) * sizeof(HWND) );
241 if (!wine_server_call( req )) count = reply->count;
243 SERVER_END_REQ;
244 if (count && count < size)
246 list[count] = 0;
247 return list;
249 HeapFree( GetProcessHeap(), 0, list );
250 if (!count) break;
251 size = count + 1; /* restart with a large enough buffer */
253 return NULL;
257 /*******************************************************************
258 * list_window_parents
260 * Build an array of all parents of a given window, starting with
261 * the immediate parent. The array must be freed with HeapFree.
263 static HWND *list_window_parents( HWND hwnd )
265 WND *win;
266 HWND current, *list;
267 int pos = 0, size = 16, count = 0;
269 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
271 current = hwnd;
272 for (;;)
274 if (!(win = WIN_GetPtr( current ))) goto empty;
275 if (win == WND_OTHER_PROCESS) break; /* need to do it the hard way */
276 if (win == WND_DESKTOP)
278 if (!pos) goto empty;
279 list[pos] = 0;
280 return list;
282 list[pos] = current = win->parent;
283 WIN_ReleasePtr( win );
284 if (!current) return list;
285 if (++pos == size - 1)
287 /* need to grow the list */
288 HWND *new_list = HeapReAlloc( GetProcessHeap(), 0, list, (size+16) * sizeof(HWND) );
289 if (!new_list) goto empty;
290 list = new_list;
291 size += 16;
295 /* at least one parent belongs to another process, have to query the server */
297 for (;;)
299 count = 0;
300 SERVER_START_REQ( get_window_parents )
302 req->handle = hwnd;
303 wine_server_set_reply( req, list, (size-1) * sizeof(HWND) );
304 if (!wine_server_call( req )) count = reply->count;
306 SERVER_END_REQ;
307 if (!count) goto empty;
308 if (size > count)
310 list[count] = 0;
311 return list;
313 HeapFree( GetProcessHeap(), 0, list );
314 size = count + 1;
315 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
318 empty:
319 HeapFree( GetProcessHeap(), 0, list );
320 return NULL;
324 /*******************************************************************
325 * send_parent_notify
327 static void send_parent_notify( HWND hwnd, UINT msg )
329 if ((GetWindowLongW( hwnd, GWL_STYLE ) & (WS_CHILD | WS_POPUP)) == WS_CHILD &&
330 !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOPARENTNOTIFY))
332 HWND parent = GetParent(hwnd);
333 if (parent && parent != GetDesktopWindow())
334 SendMessageW( parent, WM_PARENTNOTIFY,
335 MAKEWPARAM( msg, GetWindowLongPtrW( hwnd, GWLP_ID )), (LPARAM)hwnd );
340 /*******************************************************************
341 * get_server_window_text
343 * Retrieve the window text from the server.
345 static void get_server_window_text( HWND hwnd, LPWSTR text, INT count )
347 size_t len = 0;
349 SERVER_START_REQ( get_window_text )
351 req->handle = hwnd;
352 wine_server_set_reply( req, text, (count - 1) * sizeof(WCHAR) );
353 if (!wine_server_call_err( req )) len = wine_server_reply_size(reply);
355 SERVER_END_REQ;
356 text[len / sizeof(WCHAR)] = 0;
360 /*******************************************************************
361 * get_hwnd_message_parent
363 * Return the parent for HWND_MESSAGE windows.
365 HWND get_hwnd_message_parent(void)
367 struct user_thread_info *thread_info = get_user_thread_info();
369 if (!thread_info->msg_window) GetDesktopWindow(); /* trigger creation */
370 return thread_info->msg_window;
374 /*******************************************************************
375 * is_desktop_window
377 * Check if window is the desktop or the HWND_MESSAGE top parent.
379 BOOL is_desktop_window( HWND hwnd )
381 struct user_thread_info *thread_info = get_user_thread_info();
383 if (!hwnd) return FALSE;
384 if (hwnd == thread_info->top_window) return TRUE;
385 if (hwnd == thread_info->msg_window) return TRUE;
387 if (!HIWORD(hwnd) || HIWORD(hwnd) == 0xffff)
389 if (LOWORD(thread_info->top_window) == LOWORD(hwnd)) return TRUE;
390 if (LOWORD(thread_info->msg_window) == LOWORD(hwnd)) return TRUE;
392 return FALSE;
396 /***********************************************************************
397 * WIN_GetPtr
399 * Return a pointer to the WND structure if local to the process,
400 * or WND_OTHER_PROCESS if handle may be valid in other process.
401 * If ret value is a valid pointer, it must be released with WIN_ReleasePtr.
403 WND *WIN_GetPtr( HWND hwnd )
405 WND * ptr;
406 WORD index = USER_HANDLE_TO_INDEX(hwnd);
408 if (index >= NB_USER_HANDLES) return NULL;
410 USER_Lock();
411 if ((ptr = user_handles[index]))
413 if (ptr->dwMagic == WND_MAGIC &&
414 (hwnd == ptr->hwndSelf || !HIWORD(hwnd) || HIWORD(hwnd) == 0xffff))
415 return ptr;
416 ptr = NULL;
418 else if (is_desktop_window( hwnd )) ptr = WND_DESKTOP;
419 else ptr = WND_OTHER_PROCESS;
420 USER_Unlock();
421 return ptr;
425 /***********************************************************************
426 * WIN_IsCurrentProcess
428 * Check whether a given window belongs to the current process (and return the full handle).
430 HWND WIN_IsCurrentProcess( HWND hwnd )
432 WND *ptr;
433 HWND ret;
435 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
436 ret = ptr->hwndSelf;
437 WIN_ReleasePtr( ptr );
438 return ret;
442 /***********************************************************************
443 * WIN_IsCurrentThread
445 * Check whether a given window belongs to the current thread (and return the full handle).
447 HWND WIN_IsCurrentThread( HWND hwnd )
449 WND *ptr;
450 HWND ret = 0;
452 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
453 if (ptr->tid == GetCurrentThreadId()) ret = ptr->hwndSelf;
454 WIN_ReleasePtr( ptr );
455 return ret;
459 /***********************************************************************
460 * WIN_Handle32
462 * Convert a 16-bit window handle to a full 32-bit handle.
464 HWND WIN_Handle32( HWND16 hwnd16 )
466 WND *ptr;
467 HWND hwnd = (HWND)(ULONG_PTR)hwnd16;
469 if (hwnd16 <= 1 || hwnd16 == 0xffff) return hwnd;
470 /* do sign extension for -2 and -3 */
471 if (hwnd16 >= (HWND16)-3) return (HWND)(LONG_PTR)(INT16)hwnd16;
473 if (!(ptr = WIN_GetPtr( hwnd ))) return hwnd;
475 if (ptr == WND_DESKTOP)
477 if (LOWORD(hwnd) == LOWORD(GetDesktopWindow())) return GetDesktopWindow();
478 else return get_hwnd_message_parent();
481 if (ptr != WND_OTHER_PROCESS)
483 hwnd = ptr->hwndSelf;
484 WIN_ReleasePtr( ptr );
486 else /* may belong to another process */
488 SERVER_START_REQ( get_window_info )
490 req->handle = hwnd;
491 if (!wine_server_call_err( req )) hwnd = reply->full_handle;
493 SERVER_END_REQ;
495 return hwnd;
499 /***********************************************************************
500 * WIN_SetOwner
502 * Change the owner of a window.
504 HWND WIN_SetOwner( HWND hwnd, HWND owner )
506 WND *win = WIN_GetPtr( hwnd );
507 HWND ret = 0;
509 if (!win || win == WND_DESKTOP) return 0;
510 if (win == WND_OTHER_PROCESS)
512 if (IsWindow(hwnd)) ERR( "cannot set owner %p on other process window %p\n", owner, hwnd );
513 return 0;
515 SERVER_START_REQ( set_window_owner )
517 req->handle = hwnd;
518 req->owner = owner;
519 if (!wine_server_call( req ))
521 win->owner = reply->full_owner;
522 ret = reply->prev_owner;
525 SERVER_END_REQ;
526 WIN_ReleasePtr( win );
527 return ret;
531 /***********************************************************************
532 * WIN_SetStyle
534 * Change the style of a window.
536 ULONG WIN_SetStyle( HWND hwnd, ULONG set_bits, ULONG clear_bits )
538 BOOL ok;
539 STYLESTRUCT style;
540 WND *win = WIN_GetPtr( hwnd );
542 if (!win || win == WND_DESKTOP) return 0;
543 if (win == WND_OTHER_PROCESS)
545 if (IsWindow(hwnd))
546 ERR( "cannot set style %x/%x on other process window %p\n",
547 set_bits, clear_bits, hwnd );
548 return 0;
550 style.styleOld = win->dwStyle;
551 style.styleNew = (win->dwStyle | set_bits) & ~clear_bits;
552 if (style.styleNew == style.styleOld)
554 WIN_ReleasePtr( win );
555 return style.styleNew;
557 SERVER_START_REQ( set_window_info )
559 req->handle = hwnd;
560 req->flags = SET_WIN_STYLE;
561 req->style = style.styleNew;
562 req->extra_offset = -1;
563 if ((ok = !wine_server_call( req )))
565 style.styleOld = reply->old_style;
566 win->dwStyle = style.styleNew;
569 SERVER_END_REQ;
570 WIN_ReleasePtr( win );
571 if (ok)
573 USER_Driver->pSetWindowStyle( hwnd, GWL_STYLE, &style );
574 if ((style.styleOld ^ style.styleNew) & WS_VISIBLE) invalidate_dce( hwnd, NULL );
576 return style.styleOld;
580 /***********************************************************************
581 * WIN_GetRectangles
583 * Get the window and client rectangles.
585 BOOL WIN_GetRectangles( HWND hwnd, RECT *rectWindow, RECT *rectClient )
587 WND *win = WIN_GetPtr( hwnd );
588 BOOL ret = TRUE;
590 if (!win) return FALSE;
591 if (win == WND_DESKTOP)
593 RECT rect;
594 rect.left = rect.top = 0;
595 if (hwnd == get_hwnd_message_parent())
597 rect.right = 100;
598 rect.bottom = 100;
600 else
602 rect.right = GetSystemMetrics(SM_CXSCREEN);
603 rect.bottom = GetSystemMetrics(SM_CYSCREEN);
605 if (rectWindow) *rectWindow = rect;
606 if (rectClient) *rectClient = rect;
608 else if (win == WND_OTHER_PROCESS)
610 SERVER_START_REQ( get_window_rectangles )
612 req->handle = hwnd;
613 if ((ret = !wine_server_call( req )))
615 if (rectWindow)
617 rectWindow->left = reply->window.left;
618 rectWindow->top = reply->window.top;
619 rectWindow->right = reply->window.right;
620 rectWindow->bottom = reply->window.bottom;
622 if (rectClient)
624 rectClient->left = reply->client.left;
625 rectClient->top = reply->client.top;
626 rectClient->right = reply->client.right;
627 rectClient->bottom = reply->client.bottom;
631 SERVER_END_REQ;
633 else
635 if (rectWindow) *rectWindow = win->rectWindow;
636 if (rectClient) *rectClient = win->rectClient;
637 WIN_ReleasePtr( win );
639 return ret;
643 /***********************************************************************
644 * WIN_DestroyWindow
646 * Destroy storage associated to a window. "Internals" p.358
648 LRESULT WIN_DestroyWindow( HWND hwnd )
650 WND *wndPtr;
651 HWND *list;
652 HMENU menu = 0, sys_menu;
653 HWND icon_title;
655 TRACE("%p\n", hwnd );
657 /* free child windows */
658 if ((list = WIN_ListChildren( hwnd )))
660 int i;
661 for (i = 0; list[i]; i++)
663 if (WIN_IsCurrentThread( list[i] )) WIN_DestroyWindow( list[i] );
664 else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
666 HeapFree( GetProcessHeap(), 0, list );
669 /* Unlink now so we won't bother with the children later on */
670 SERVER_START_REQ( set_parent )
672 req->handle = hwnd;
673 req->parent = 0;
674 wine_server_call( req );
676 SERVER_END_REQ;
679 * Send the WM_NCDESTROY to the window being destroyed.
681 SendMessageW( hwnd, WM_NCDESTROY, 0, 0 );
683 /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
685 /* free resources associated with the window */
687 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
688 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
689 menu = (HMENU)wndPtr->wIDmenu;
690 sys_menu = wndPtr->hSysMenu;
691 free_dce( wndPtr->dce, hwnd );
692 wndPtr->dce = NULL;
693 icon_title = wndPtr->icon_title;
694 WIN_ReleasePtr( wndPtr );
696 if (icon_title) DestroyWindow( icon_title );
697 if (menu) DestroyMenu( menu );
698 if (sys_menu) DestroyMenu( sys_menu );
700 USER_Driver->pDestroyWindow( hwnd );
702 free_window_handle( hwnd );
703 return 0;
706 /***********************************************************************
707 * WIN_DestroyThreadWindows
709 * Destroy all children of 'wnd' owned by the current thread.
711 void WIN_DestroyThreadWindows( HWND hwnd )
713 HWND *list;
714 int i;
716 if (!(list = WIN_ListChildren( hwnd ))) return;
717 for (i = 0; list[i]; i++)
719 if (WIN_IsCurrentThread( list[i] ))
720 DestroyWindow( list[i] );
721 else
722 WIN_DestroyThreadWindows( list[i] );
724 HeapFree( GetProcessHeap(), 0, list );
728 /***********************************************************************
729 * WIN_FixCoordinates
731 * Fix the coordinates - Helper for WIN_CreateWindowEx.
732 * returns default show mode in sw.
734 static void WIN_FixCoordinates( CREATESTRUCTA *cs, INT *sw)
736 #define IS_DEFAULT(x) ((x) == CW_USEDEFAULT || (x) == CW_USEDEFAULT16)
737 POINT pos[2];
739 if (cs->dwExStyle & WS_EX_MDICHILD)
741 UINT id = 0;
743 MDI_CalcDefaultChildPos(cs->hwndParent, -1, pos, 0, &id);
744 if (!(cs->style & WS_POPUP)) cs->hMenu = ULongToHandle(id);
746 TRACE("MDI child id %04x\n", id);
749 if (cs->style & (WS_CHILD | WS_POPUP))
751 if (cs->dwExStyle & WS_EX_MDICHILD)
753 if (IS_DEFAULT(cs->x))
755 cs->x = pos[0].x;
756 cs->y = pos[0].y;
758 if (IS_DEFAULT(cs->cx) || !cs->cx) cs->cx = pos[1].x;
759 if (IS_DEFAULT(cs->cy) || !cs->cy) cs->cy = pos[1].y;
761 else
763 if (IS_DEFAULT(cs->x)) cs->x = cs->y = 0;
764 if (IS_DEFAULT(cs->cx)) cs->cx = cs->cy = 0;
767 else /* overlapped window */
769 HMONITOR monitor;
770 MONITORINFO mon_info;
771 STARTUPINFOW info;
773 if (!IS_DEFAULT(cs->x) && !IS_DEFAULT(cs->cx) && !IS_DEFAULT(cs->cy)) return;
775 monitor = MonitorFromWindow( cs->hwndParent, MONITOR_DEFAULTTOPRIMARY );
776 mon_info.cbSize = sizeof(mon_info);
777 GetMonitorInfoW( monitor, &mon_info );
778 GetStartupInfoW( &info );
780 if (IS_DEFAULT(cs->x))
782 if (!IS_DEFAULT(cs->y)) *sw = cs->y;
783 cs->x = (info.dwFlags & STARTF_USEPOSITION) ? info.dwX : mon_info.rcWork.left;
784 cs->y = (info.dwFlags & STARTF_USEPOSITION) ? info.dwY : mon_info.rcWork.top;
787 if (IS_DEFAULT(cs->cx))
789 if (info.dwFlags & STARTF_USESIZE)
791 cs->cx = info.dwXSize;
792 cs->cy = info.dwYSize;
794 else
796 cs->cx = (mon_info.rcWork.right - mon_info.rcWork.left) * 3 / 4 - cs->x;
797 cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
800 /* neither x nor cx are default. Check the y values .
801 * In the trace we see Outlook and Outlook Express using
802 * cy set to CW_USEDEFAULT when opening the address book.
804 else if (IS_DEFAULT(cs->cy))
806 FIXME("Strange use of CW_USEDEFAULT in nHeight\n");
807 cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
810 #undef IS_DEFAULT
813 /***********************************************************************
814 * dump_window_styles
816 static void dump_window_styles( DWORD style, DWORD exstyle )
818 TRACE( "style:" );
819 if(style & WS_POPUP) TRACE(" WS_POPUP");
820 if(style & WS_CHILD) TRACE(" WS_CHILD");
821 if(style & WS_MINIMIZE) TRACE(" WS_MINIMIZE");
822 if(style & WS_VISIBLE) TRACE(" WS_VISIBLE");
823 if(style & WS_DISABLED) TRACE(" WS_DISABLED");
824 if(style & WS_CLIPSIBLINGS) TRACE(" WS_CLIPSIBLINGS");
825 if(style & WS_CLIPCHILDREN) TRACE(" WS_CLIPCHILDREN");
826 if(style & WS_MAXIMIZE) TRACE(" WS_MAXIMIZE");
827 if((style & WS_CAPTION) == WS_CAPTION) TRACE(" WS_CAPTION");
828 else
830 if(style & WS_BORDER) TRACE(" WS_BORDER");
831 if(style & WS_DLGFRAME) TRACE(" WS_DLGFRAME");
833 if(style & WS_VSCROLL) TRACE(" WS_VSCROLL");
834 if(style & WS_HSCROLL) TRACE(" WS_HSCROLL");
835 if(style & WS_SYSMENU) TRACE(" WS_SYSMENU");
836 if(style & WS_THICKFRAME) TRACE(" WS_THICKFRAME");
837 if (style & WS_CHILD)
839 if(style & WS_GROUP) TRACE(" WS_GROUP");
840 if(style & WS_TABSTOP) TRACE(" WS_TABSTOP");
842 else
844 if(style & WS_MINIMIZEBOX) TRACE(" WS_MINIMIZEBOX");
845 if(style & WS_MAXIMIZEBOX) TRACE(" WS_MAXIMIZEBOX");
848 /* FIXME: Add dumping of BS_/ES_/SBS_/LBS_/CBS_/DS_/etc. styles */
849 #define DUMPED_STYLES \
850 (WS_POPUP | \
851 WS_CHILD | \
852 WS_MINIMIZE | \
853 WS_VISIBLE | \
854 WS_DISABLED | \
855 WS_CLIPSIBLINGS | \
856 WS_CLIPCHILDREN | \
857 WS_MAXIMIZE | \
858 WS_BORDER | \
859 WS_DLGFRAME | \
860 WS_VSCROLL | \
861 WS_HSCROLL | \
862 WS_SYSMENU | \
863 WS_THICKFRAME | \
864 WS_GROUP | \
865 WS_TABSTOP | \
866 WS_MINIMIZEBOX | \
867 WS_MAXIMIZEBOX)
869 if(style & ~DUMPED_STYLES) TRACE(" %08lx", style & ~DUMPED_STYLES);
870 TRACE("\n");
871 #undef DUMPED_STYLES
873 TRACE( "exstyle:" );
874 if(exstyle & WS_EX_DLGMODALFRAME) TRACE(" WS_EX_DLGMODALFRAME");
875 if(exstyle & WS_EX_DRAGDETECT) TRACE(" WS_EX_DRAGDETECT");
876 if(exstyle & WS_EX_NOPARENTNOTIFY) TRACE(" WS_EX_NOPARENTNOTIFY");
877 if(exstyle & WS_EX_TOPMOST) TRACE(" WS_EX_TOPMOST");
878 if(exstyle & WS_EX_ACCEPTFILES) TRACE(" WS_EX_ACCEPTFILES");
879 if(exstyle & WS_EX_TRANSPARENT) TRACE(" WS_EX_TRANSPARENT");
880 if(exstyle & WS_EX_MDICHILD) TRACE(" WS_EX_MDICHILD");
881 if(exstyle & WS_EX_TOOLWINDOW) TRACE(" WS_EX_TOOLWINDOW");
882 if(exstyle & WS_EX_WINDOWEDGE) TRACE(" WS_EX_WINDOWEDGE");
883 if(exstyle & WS_EX_CLIENTEDGE) TRACE(" WS_EX_CLIENTEDGE");
884 if(exstyle & WS_EX_CONTEXTHELP) TRACE(" WS_EX_CONTEXTHELP");
885 if(exstyle & WS_EX_RIGHT) TRACE(" WS_EX_RIGHT");
886 if(exstyle & WS_EX_RTLREADING) TRACE(" WS_EX_RTLREADING");
887 if(exstyle & WS_EX_LEFTSCROLLBAR) TRACE(" WS_EX_LEFTSCROLLBAR");
888 if(exstyle & WS_EX_CONTROLPARENT) TRACE(" WS_EX_CONTROLPARENT");
889 if(exstyle & WS_EX_STATICEDGE) TRACE(" WS_EX_STATICEDGE");
890 if(exstyle & WS_EX_APPWINDOW) TRACE(" WS_EX_APPWINDOW");
891 if(exstyle & WS_EX_LAYERED) TRACE(" WS_EX_LAYERED");
893 #define DUMPED_EX_STYLES \
894 (WS_EX_DLGMODALFRAME | \
895 WS_EX_DRAGDETECT | \
896 WS_EX_NOPARENTNOTIFY | \
897 WS_EX_TOPMOST | \
898 WS_EX_ACCEPTFILES | \
899 WS_EX_TRANSPARENT | \
900 WS_EX_MDICHILD | \
901 WS_EX_TOOLWINDOW | \
902 WS_EX_WINDOWEDGE | \
903 WS_EX_CLIENTEDGE | \
904 WS_EX_CONTEXTHELP | \
905 WS_EX_RIGHT | \
906 WS_EX_RTLREADING | \
907 WS_EX_LEFTSCROLLBAR | \
908 WS_EX_CONTROLPARENT | \
909 WS_EX_STATICEDGE | \
910 WS_EX_APPWINDOW | \
911 WS_EX_LAYERED)
913 if(exstyle & ~DUMPED_EX_STYLES) TRACE(" %08lx", exstyle & ~DUMPED_EX_STYLES);
914 TRACE("\n");
915 #undef DUMPED_EX_STYLES
919 /***********************************************************************
920 * WIN_CreateWindowEx
922 * Implementation of CreateWindowEx().
924 static HWND WIN_CreateWindowEx( CREATESTRUCTA *cs, LPCWSTR className, UINT flags )
926 INT cx, cy, style, sw = SW_SHOW;
927 LRESULT result;
928 RECT rect;
929 WND *wndPtr;
930 HWND hwnd, parent, owner, top_child = 0;
931 BOOL unicode = (flags & WIN_ISUNICODE) != 0;
932 MDICREATESTRUCTA mdi_cs;
933 CBT_CREATEWNDA cbtc;
934 CREATESTRUCTA cbcs;
936 TRACE("%s %s ex=%08x style=%08x %d,%d %dx%d parent=%p menu=%p inst=%p params=%p\n",
937 unicode ? debugstr_w((LPCWSTR)cs->lpszName) : debugstr_a(cs->lpszName),
938 debugstr_w(className),
939 cs->dwExStyle, cs->style, cs->x, cs->y, cs->cx, cs->cy,
940 cs->hwndParent, cs->hMenu, cs->hInstance, cs->lpCreateParams );
941 if(TRACE_ON(win)) dump_window_styles( cs->style, cs->dwExStyle );
943 /* Fix the styles for MDI children */
944 if (cs->dwExStyle & WS_EX_MDICHILD)
946 UINT flags = 0;
948 wndPtr = WIN_GetPtr(cs->hwndParent);
949 if (wndPtr && wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
951 flags = wndPtr->flags;
952 WIN_ReleasePtr(wndPtr);
955 if (!(flags & WIN_ISMDICLIENT))
957 WARN("WS_EX_MDICHILD, but parent %p is not MDIClient\n", cs->hwndParent);
958 return 0;
961 /* cs->lpCreateParams of WM_[NC]CREATE is different for MDI children.
962 * MDICREATESTRUCT members have the originally passed values.
964 * Note: we rely on the fact that MDICREATESTRUCTA and MDICREATESTRUCTW
965 * have the same layout.
967 mdi_cs.szClass = cs->lpszClass;
968 mdi_cs.szTitle = cs->lpszName;
969 mdi_cs.hOwner = cs->hInstance;
970 mdi_cs.x = cs->x;
971 mdi_cs.y = cs->y;
972 mdi_cs.cx = cs->cx;
973 mdi_cs.cy = cs->cy;
974 mdi_cs.style = cs->style;
975 mdi_cs.lParam = (LPARAM)cs->lpCreateParams;
977 cs->lpCreateParams = (LPVOID)&mdi_cs;
979 if (GetWindowLongW(cs->hwndParent, GWL_STYLE) & MDIS_ALLCHILDSTYLES)
981 if (cs->style & WS_POPUP)
983 TRACE("WS_POPUP with MDIS_ALLCHILDSTYLES is not allowed\n");
984 return 0;
986 cs->style |= WS_CHILD | WS_CLIPSIBLINGS;
988 else
990 cs->style &= ~WS_POPUP;
991 cs->style |= WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION |
992 WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
995 top_child = GetWindow(cs->hwndParent, GW_CHILD);
997 if (top_child)
999 /* Restore current maximized child */
1000 if((cs->style & WS_VISIBLE) && IsZoomed(top_child))
1002 TRACE("Restoring current maximized child %p\n", top_child);
1003 SendMessageW( top_child, WM_SETREDRAW, FALSE, 0 );
1004 ShowWindow( top_child, SW_SHOWNORMAL );
1005 SendMessageW( top_child, WM_SETREDRAW, TRUE, 0 );
1010 /* Find the parent window */
1012 parent = cs->hwndParent;
1013 owner = 0;
1015 if (cs->hwndParent == HWND_MESSAGE)
1017 cs->hwndParent = parent = get_hwnd_message_parent();
1019 else if (cs->hwndParent)
1021 if ((cs->style & (WS_CHILD|WS_POPUP)) != WS_CHILD)
1023 parent = GetDesktopWindow();
1024 owner = cs->hwndParent;
1027 else
1029 static const WCHAR messageW[] = {'M','e','s','s','a','g','e',0};
1031 if ((cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
1033 WARN("No parent for child window\n" );
1034 SetLastError(ERROR_TLW_WITH_WSCHILD);
1035 return 0; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
1037 /* are we creating the desktop or HWND_MESSAGE parent itself? */
1038 if (className != (LPCWSTR)DESKTOP_CLASS_ATOM &&
1039 (IS_INTRESOURCE(className) || strcmpiW( className, messageW )))
1040 parent = GetDesktopWindow();
1043 WIN_FixCoordinates(cs, &sw); /* fix default coordinates */
1045 if ((cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
1046 ((!(cs->dwExStyle & WS_EX_STATICEDGE)) &&
1047 (cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
1048 cs->dwExStyle |= WS_EX_WINDOWEDGE;
1049 else
1050 cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
1052 /* Create the window structure */
1054 if (!(wndPtr = create_window_handle( parent, owner, className, cs->hInstance, unicode )))
1055 return 0;
1056 hwnd = wndPtr->hwndSelf;
1058 /* Fill the window structure */
1060 wndPtr->tid = GetCurrentThreadId();
1061 wndPtr->hInstance = cs->hInstance;
1062 wndPtr->text = NULL;
1063 wndPtr->dwStyle = cs->style & ~WS_VISIBLE;
1064 wndPtr->dwExStyle = cs->dwExStyle;
1065 wndPtr->wIDmenu = 0;
1066 wndPtr->helpContext = 0;
1067 wndPtr->pVScroll = NULL;
1068 wndPtr->pHScroll = NULL;
1069 wndPtr->userdata = 0;
1070 wndPtr->hIcon = 0;
1071 wndPtr->hIconSmall = 0;
1072 wndPtr->hSysMenu = 0;
1073 wndPtr->flags |= (flags & WIN_ISWIN32);
1075 wndPtr->min_pos.x = wndPtr->min_pos.y = -1;
1076 wndPtr->max_pos.x = wndPtr->max_pos.y = -1;
1078 if (wndPtr->dwStyle & WS_SYSMENU) SetSystemMenu( hwnd, 0 );
1081 * Correct the window styles.
1083 * It affects only the style loaded into the WIN structure.
1086 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1088 wndPtr->dwStyle |= WS_CLIPSIBLINGS;
1089 if (!(wndPtr->dwStyle & WS_POPUP))
1090 wndPtr->dwStyle |= WS_CAPTION;
1094 * WS_EX_WINDOWEDGE appears to be enforced based on the other styles, so
1095 * why does the user get to set it?
1098 if ((wndPtr->dwExStyle & WS_EX_DLGMODALFRAME) ||
1099 (wndPtr->dwStyle & (WS_DLGFRAME | WS_THICKFRAME)))
1100 wndPtr->dwExStyle |= WS_EX_WINDOWEDGE;
1101 else
1102 wndPtr->dwExStyle &= ~WS_EX_WINDOWEDGE;
1104 if (!(wndPtr->dwStyle & (WS_CHILD | WS_POPUP)))
1105 wndPtr->flags |= WIN_NEED_SIZE;
1107 SERVER_START_REQ( set_window_info )
1109 req->handle = hwnd;
1110 req->flags = SET_WIN_STYLE | SET_WIN_EXSTYLE | SET_WIN_INSTANCE | SET_WIN_UNICODE;
1111 req->style = wndPtr->dwStyle;
1112 req->ex_style = wndPtr->dwExStyle;
1113 req->instance = (void *)wndPtr->hInstance;
1114 req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
1115 req->extra_offset = -1;
1116 wine_server_call( req );
1118 SERVER_END_REQ;
1120 /* Set the window menu */
1122 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1124 if (cs->hMenu)
1126 if (!MENU_SetMenu(hwnd, cs->hMenu))
1128 WIN_ReleasePtr( wndPtr );
1129 free_window_handle( hwnd );
1130 return 0;
1133 else
1135 LPCSTR menuName = (LPCSTR)GetClassLongPtrA( hwnd, GCLP_MENUNAME );
1136 if (menuName)
1138 if (!cs->hInstance || HIWORD(cs->hInstance))
1139 cs->hMenu = LoadMenuA(cs->hInstance,menuName);
1140 else
1141 cs->hMenu = HMENU_32(LoadMenu16(HINSTANCE_16(cs->hInstance),menuName));
1143 if (cs->hMenu) MENU_SetMenu( hwnd, cs->hMenu );
1147 else SetWindowLongPtrW( hwnd, GWLP_ID, (ULONG_PTR)cs->hMenu );
1149 /* call the WH_CBT hook */
1151 /* the window style passed to the hook must be the real window style,
1152 * rather than just the window style that the caller to CreateWindowEx
1153 * passed in, so we have to copy the original CREATESTRUCT and get the
1154 * the real style. */
1155 cbcs = *cs;
1156 cbcs.style = wndPtr->dwStyle;
1157 cbtc.lpcs = &cbcs;
1158 cbtc.hwndInsertAfter = HWND_TOP;
1159 WIN_ReleasePtr( wndPtr );
1160 if (HOOK_CallHooks( WH_CBT, HCBT_CREATEWND, (WPARAM)hwnd, (LPARAM)&cbtc, unicode )) goto failed;
1162 /* send the WM_GETMINMAXINFO message and fix the size if needed */
1164 cx = cs->cx;
1165 cy = cs->cy;
1166 if ((cs->style & WS_THICKFRAME) || !(cs->style & (WS_POPUP | WS_CHILD)))
1168 POINT maxSize, maxPos, minTrack, maxTrack;
1169 WINPOS_GetMinMaxInfo( hwnd, &maxSize, &maxPos, &minTrack, &maxTrack);
1170 if (maxTrack.x < cx) cx = maxTrack.x;
1171 if (maxTrack.y < cy) cy = maxTrack.y;
1172 if (minTrack.x > cx) cx = minTrack.x;
1173 if (minTrack.y > cy) cy = minTrack.y;
1176 if (cx < 0) cx = 0;
1177 if (cy < 0) cy = 0;
1178 SetRect( &rect, cs->x, cs->y, cs->x + cx, cs->y + cy );
1179 /* check for wraparound */
1180 if (cs->x + cx < cs->x) rect.right = 0x7fffffff;
1181 if (cs->y + cy < cs->y) rect.bottom = 0x7fffffff;
1182 if (!set_window_pos( hwnd, 0, SWP_NOZORDER | SWP_NOACTIVATE, &rect, &rect, NULL )) goto failed;
1184 /* send WM_NCCREATE */
1186 TRACE( "hwnd %p cs %d,%d %dx%d\n", hwnd, cs->x, cs->y, cx, cy );
1187 if (unicode)
1188 result = SendMessageW( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1189 else
1190 result = SendMessageA( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1191 if (!result)
1193 WARN( "%p: aborted by WM_NCCREATE\n", hwnd );
1194 goto failed;
1197 /* send WM_NCCALCSIZE */
1199 if ((wndPtr = WIN_GetPtr(hwnd)))
1201 /* yes, even if the CBT hook was called with HWND_TOP */
1202 POINT pt;
1203 HWND insert_after = (wndPtr->dwStyle & WS_CHILD) ? HWND_BOTTOM : HWND_TOP;
1204 RECT window_rect = wndPtr->rectWindow;
1205 RECT client_rect = window_rect;
1206 WIN_ReleasePtr( wndPtr );
1208 /* the rectangle is in screen coords for WM_NCCALCSIZE when wparam is FALSE */
1209 pt.x = pt.y = 0;
1210 MapWindowPoints( parent, 0, &pt, 1 );
1211 OffsetRect( &client_rect, pt.x, pt.y );
1212 SendMessageW( hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&client_rect );
1213 OffsetRect( &client_rect, -pt.x, -pt.y );
1214 set_window_pos( hwnd, insert_after, SWP_NOACTIVATE, &window_rect, &client_rect, NULL );
1216 else return 0;
1218 /* send WM_CREATE */
1220 if (unicode)
1221 result = SendMessageW( hwnd, WM_CREATE, 0, (LPARAM)cs );
1222 else
1223 result = SendMessageA( hwnd, WM_CREATE, 0, (LPARAM)cs );
1224 if (result == -1) goto failed;
1226 /* call the driver */
1228 if (!USER_Driver->pCreateWindow( hwnd )) goto failed;
1230 NotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_WINDOW, 0);
1232 /* send the size messages */
1234 if (!(wndPtr = WIN_GetPtr(hwnd))) return 0;
1235 if (!(wndPtr->flags & WIN_NEED_SIZE))
1237 rect = wndPtr->rectClient;
1238 WIN_ReleasePtr( wndPtr );
1239 SendMessageW( hwnd, WM_SIZE, SIZE_RESTORED,
1240 MAKELONG(rect.right-rect.left, rect.bottom-rect.top));
1241 SendMessageW( hwnd, WM_MOVE, 0, MAKELONG( rect.left, rect.top ) );
1243 else WIN_ReleasePtr( wndPtr );
1245 /* Show the window, maximizing or minimizing if needed */
1247 style = WIN_SetStyle( hwnd, 0, WS_MAXIMIZE | WS_MINIMIZE );
1248 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
1250 RECT newPos;
1251 UINT swFlag = (style & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;
1253 swFlag = WINPOS_MinMaximize( hwnd, swFlag, &newPos );
1254 swFlag |= SWP_FRAMECHANGED; /* Frame always gets changed */
1255 if (!(style & WS_VISIBLE) || (style & WS_CHILD) || GetActiveWindow()) swFlag |= SWP_NOACTIVATE;
1256 SetWindowPos( hwnd, 0, newPos.left, newPos.top, newPos.right - newPos.left,
1257 newPos.bottom - newPos.top, swFlag );
1260 /* Notify the parent window only */
1262 send_parent_notify( hwnd, WM_CREATE );
1263 if (!IsWindow( hwnd )) return 0;
1265 if (cs->style & WS_VISIBLE)
1267 if (cs->style & WS_MAXIMIZE)
1268 sw = SW_SHOW;
1269 else if (cs->style & WS_MINIMIZE)
1270 sw = SW_SHOWMINIMIZED;
1272 ShowWindow( hwnd, sw );
1273 if (cs->dwExStyle & WS_EX_MDICHILD)
1275 SendMessageW(cs->hwndParent, WM_MDIREFRESHMENU, 0, 0);
1276 /* ShowWindow won't activate child windows */
1277 SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE );
1281 /* Call WH_SHELL hook */
1283 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1284 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0, TRUE );
1286 TRACE("created window %p\n", hwnd);
1287 return hwnd;
1289 failed:
1290 WIN_DestroyWindow( hwnd );
1291 return 0;
1295 /***********************************************************************
1296 * CreateWindow (USER.41)
1298 HWND16 WINAPI CreateWindow16( LPCSTR className, LPCSTR windowName,
1299 DWORD style, INT16 x, INT16 y, INT16 width,
1300 INT16 height, HWND16 parent, HMENU16 menu,
1301 HINSTANCE16 instance, LPVOID data )
1303 return CreateWindowEx16( 0, className, windowName, style,
1304 x, y, width, height, parent, menu, instance, data );
1308 /***********************************************************************
1309 * CreateWindowEx (USER.452)
1311 HWND16 WINAPI CreateWindowEx16( DWORD exStyle, LPCSTR className,
1312 LPCSTR windowName, DWORD style, INT16 x,
1313 INT16 y, INT16 width, INT16 height,
1314 HWND16 parent, HMENU16 menu,
1315 HINSTANCE16 instance, LPVOID data )
1317 CREATESTRUCTA cs;
1318 char buffer[256];
1320 /* Fix the coordinates */
1322 cs.x = (x == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)x;
1323 cs.y = (y == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)y;
1324 cs.cx = (width == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)width;
1325 cs.cy = (height == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)height;
1327 /* Create the window */
1329 cs.lpCreateParams = data;
1330 cs.hInstance = HINSTANCE_32(instance);
1331 cs.hMenu = HMENU_32(menu);
1332 cs.hwndParent = WIN_Handle32( parent );
1333 cs.style = style;
1334 cs.lpszName = windowName;
1335 cs.lpszClass = className;
1336 cs.dwExStyle = exStyle;
1338 if (!IS_INTRESOURCE(className))
1340 WCHAR bufferW[256];
1342 if (!MultiByteToWideChar( CP_ACP, 0, className, -1, bufferW, sizeof(bufferW)/sizeof(WCHAR) ))
1343 return 0;
1344 return HWND_16( WIN_CreateWindowEx( &cs, bufferW, 0 ));
1346 else
1348 if (!GlobalGetAtomNameA( LOWORD(className), buffer, sizeof(buffer) ))
1350 ERR( "bad atom %x\n", LOWORD(className));
1351 return 0;
1353 cs.lpszClass = buffer;
1354 return HWND_16( WIN_CreateWindowEx( &cs, (LPCWSTR)className, 0 ));
1359 /***********************************************************************
1360 * CreateWindowExA (USER32.@)
1362 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1363 LPCSTR windowName, DWORD style, INT x,
1364 INT y, INT width, INT height,
1365 HWND parent, HMENU menu,
1366 HINSTANCE instance, LPVOID data )
1368 CREATESTRUCTA cs;
1370 cs.lpCreateParams = data;
1371 cs.hInstance = instance;
1372 cs.hMenu = menu;
1373 cs.hwndParent = parent;
1374 cs.x = x;
1375 cs.y = y;
1376 cs.cx = width;
1377 cs.cy = height;
1378 cs.style = style;
1379 cs.lpszName = windowName;
1380 cs.lpszClass = className;
1381 cs.dwExStyle = exStyle;
1383 if (!IS_INTRESOURCE(className))
1385 WCHAR bufferW[256];
1386 if (!MultiByteToWideChar( CP_ACP, 0, className, -1, bufferW, sizeof(bufferW)/sizeof(WCHAR) ))
1387 return 0;
1388 return WIN_CreateWindowEx( &cs, bufferW, WIN_ISWIN32 );
1390 return WIN_CreateWindowEx( &cs, (LPCWSTR)className, WIN_ISWIN32 );
1394 /***********************************************************************
1395 * CreateWindowExW (USER32.@)
1397 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1398 LPCWSTR windowName, DWORD style, INT x,
1399 INT y, INT width, INT height,
1400 HWND parent, HMENU menu,
1401 HINSTANCE instance, LPVOID data )
1403 CREATESTRUCTW cs;
1405 cs.lpCreateParams = data;
1406 cs.hInstance = instance;
1407 cs.hMenu = menu;
1408 cs.hwndParent = parent;
1409 cs.x = x;
1410 cs.y = y;
1411 cs.cx = width;
1412 cs.cy = height;
1413 cs.style = style;
1414 cs.lpszName = windowName;
1415 cs.lpszClass = className;
1416 cs.dwExStyle = exStyle;
1418 /* Note: we rely on the fact that CREATESTRUCTA and */
1419 /* CREATESTRUCTW have the same layout. */
1420 return WIN_CreateWindowEx( (CREATESTRUCTA *)&cs, className, WIN_ISWIN32 | WIN_ISUNICODE );
1424 /***********************************************************************
1425 * WIN_SendDestroyMsg
1427 static void WIN_SendDestroyMsg( HWND hwnd )
1429 GUITHREADINFO info;
1431 if (GetGUIThreadInfo( GetCurrentThreadId(), &info ))
1433 if (hwnd == info.hwndCaret) DestroyCaret();
1434 if (hwnd == info.hwndActive) WINPOS_ActivateOtherWindow( hwnd );
1438 * Send the WM_DESTROY to the window.
1440 SendMessageW( hwnd, WM_DESTROY, 0, 0);
1443 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1444 * make sure that the window still exists when we come back.
1446 if (IsWindow(hwnd))
1448 HWND* pWndArray;
1449 int i;
1451 if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1453 for (i = 0; pWndArray[i]; i++)
1455 if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1457 HeapFree( GetProcessHeap(), 0, pWndArray );
1459 else
1460 WARN("\tdestroyed itself while in WM_DESTROY!\n");
1464 /***********************************************************************
1465 * DestroyWindow (USER32.@)
1467 BOOL WINAPI DestroyWindow( HWND hwnd )
1469 BOOL is_child;
1471 if (!(hwnd = WIN_IsCurrentThread( hwnd )) || is_desktop_window( hwnd ))
1473 SetLastError( ERROR_ACCESS_DENIED );
1474 return FALSE;
1477 TRACE("(%p)\n", hwnd);
1479 /* Call hooks */
1481 if (HOOK_CallHooks( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0, TRUE )) return FALSE;
1483 if (MENU_IsMenuActive() == hwnd)
1484 EndMenu();
1486 is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;
1488 if (is_child)
1490 if (!USER_IsExitingThread( GetCurrentThreadId() ))
1491 send_parent_notify( hwnd, WM_DESTROY );
1493 else if (!GetWindow( hwnd, GW_OWNER ))
1495 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
1496 /* FIXME: clean up palette - see "Internals" p.352 */
1499 if (!IsWindow(hwnd)) return TRUE;
1501 /* Hide the window */
1502 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)
1504 /* Only child windows receive WM_SHOWWINDOW in DestroyWindow() */
1505 if (is_child)
1506 ShowWindow( hwnd, SW_HIDE );
1507 else
1508 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE |
1509 SWP_NOZORDER | SWP_NOACTIVATE | SWP_HIDEWINDOW );
1512 if (!IsWindow(hwnd)) return TRUE;
1514 /* Recursively destroy owned windows */
1516 if (!is_child)
1518 for (;;)
1520 int i, got_one = 0;
1521 HWND *list = WIN_ListChildren( GetDesktopWindow() );
1522 if (list)
1524 for (i = 0; list[i]; i++)
1526 if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1527 if (WIN_IsCurrentThread( list[i] ))
1529 DestroyWindow( list[i] );
1530 got_one = 1;
1531 continue;
1533 WIN_SetOwner( list[i], 0 );
1535 HeapFree( GetProcessHeap(), 0, list );
1537 if (!got_one) break;
1541 /* Send destroy messages */
1543 WIN_SendDestroyMsg( hwnd );
1544 if (!IsWindow( hwnd )) return TRUE;
1546 if (GetClipboardOwner() == hwnd)
1547 CLIPBOARD_ReleaseOwner();
1549 /* Destroy the window storage */
1551 WIN_DestroyWindow( hwnd );
1552 return TRUE;
1556 /***********************************************************************
1557 * CloseWindow (USER32.@)
1559 BOOL WINAPI CloseWindow( HWND hwnd )
1561 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1562 ShowWindow( hwnd, SW_MINIMIZE );
1563 return TRUE;
1567 /***********************************************************************
1568 * OpenIcon (USER32.@)
1570 BOOL WINAPI OpenIcon( HWND hwnd )
1572 if (!IsIconic( hwnd )) return FALSE;
1573 ShowWindow( hwnd, SW_SHOWNORMAL );
1574 return TRUE;
1578 /***********************************************************************
1579 * FindWindowExW (USER32.@)
1581 HWND WINAPI FindWindowExW( HWND parent, HWND child, LPCWSTR className, LPCWSTR title )
1583 HWND *list = NULL;
1584 HWND retvalue = 0;
1585 int i = 0, len = 0;
1586 WCHAR *buffer = NULL;
1588 if (!parent && child) parent = GetDesktopWindow();
1589 else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
1591 if (title)
1593 len = strlenW(title) + 1; /* one extra char to check for chars beyond the end */
1594 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1597 if (!(list = list_window_children( 0, parent, className, 0 ))) goto done;
1599 if (child)
1601 child = WIN_GetFullHandle( child );
1602 while (list[i] && list[i] != child) i++;
1603 if (!list[i]) goto done;
1604 i++; /* start from next window */
1607 if (title)
1609 while (list[i])
1611 if (GetWindowTextW( list[i], buffer, len + 1 ) && !strcmpiW( buffer, title )) break;
1612 i++;
1615 retvalue = list[i];
1617 done:
1618 HeapFree( GetProcessHeap(), 0, list );
1619 HeapFree( GetProcessHeap(), 0, buffer );
1620 return retvalue;
1625 /***********************************************************************
1626 * FindWindowA (USER32.@)
1628 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1630 HWND ret = FindWindowExA( 0, 0, className, title );
1631 if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1632 return ret;
1636 /***********************************************************************
1637 * FindWindowExA (USER32.@)
1639 HWND WINAPI FindWindowExA( HWND parent, HWND child, LPCSTR className, LPCSTR title )
1641 LPWSTR titleW = NULL;
1642 HWND hwnd = 0;
1644 if (title)
1646 DWORD len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
1647 if (!(titleW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
1648 MultiByteToWideChar( CP_ACP, 0, title, -1, titleW, len );
1651 if (!IS_INTRESOURCE(className))
1653 WCHAR classW[256];
1654 if (MultiByteToWideChar( CP_ACP, 0, className, -1, classW, sizeof(classW)/sizeof(WCHAR) ))
1655 hwnd = FindWindowExW( parent, child, classW, titleW );
1657 else
1659 hwnd = FindWindowExW( parent, child, (LPCWSTR)className, titleW );
1662 HeapFree( GetProcessHeap(), 0, titleW );
1663 return hwnd;
1667 /***********************************************************************
1668 * FindWindowW (USER32.@)
1670 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
1672 return FindWindowExW( 0, 0, className, title );
1676 /**********************************************************************
1677 * GetDesktopWindow (USER32.@)
1679 HWND WINAPI GetDesktopWindow(void)
1681 struct user_thread_info *thread_info = get_user_thread_info();
1683 if (thread_info->top_window) return thread_info->top_window;
1685 SERVER_START_REQ( get_desktop_window )
1687 req->force = 0;
1688 if (!wine_server_call( req ))
1690 thread_info->top_window = reply->top_window;
1691 thread_info->msg_window = reply->msg_window;
1694 SERVER_END_REQ;
1696 if (!thread_info->top_window)
1698 USEROBJECTFLAGS flags;
1699 if (!GetUserObjectInformationW( GetProcessWindowStation(), UOI_FLAGS, &flags,
1700 sizeof(flags), NULL ) || (flags.dwFlags & WSF_VISIBLE))
1702 static const WCHAR command_line[] = {'\\','e','x','p','l','o','r','e','r','.','e','x','e',' ','/','d','e','s','k','t','o','p',0};
1703 STARTUPINFOW si;
1704 PROCESS_INFORMATION pi;
1705 WCHAR cmdline[MAX_PATH + sizeof(command_line)/sizeof(WCHAR)];
1707 memset( &si, 0, sizeof(si) );
1708 si.cb = sizeof(si);
1709 si.dwFlags = STARTF_USESTDHANDLES;
1710 si.hStdInput = 0;
1711 si.hStdOutput = 0;
1712 si.hStdError = GetStdHandle( STD_ERROR_HANDLE );
1714 GetSystemDirectoryW( cmdline, MAX_PATH );
1715 lstrcatW( cmdline, command_line );
1716 if (CreateProcessW( NULL, cmdline, NULL, NULL, FALSE, DETACHED_PROCESS,
1717 NULL, NULL, &si, &pi ))
1719 TRACE( "started explorer pid %04x tid %04x\n", pi.dwProcessId, pi.dwThreadId );
1720 WaitForInputIdle( pi.hProcess, 10000 );
1721 CloseHandle( pi.hThread );
1722 CloseHandle( pi.hProcess );
1724 else WARN( "failed to start explorer, err %d\n", GetLastError() );
1726 else TRACE( "not starting explorer since winstation is not visible\n" );
1728 SERVER_START_REQ( get_desktop_window )
1730 req->force = 1;
1731 if (!wine_server_call( req ))
1733 thread_info->top_window = reply->top_window;
1734 thread_info->msg_window = reply->msg_window;
1737 SERVER_END_REQ;
1740 if (!thread_info->top_window || !USER_Driver->pCreateDesktopWindow( thread_info->top_window ))
1741 ERR( "failed to create desktop window\n" );
1743 return thread_info->top_window;
1747 /*******************************************************************
1748 * EnableWindow (USER32.@)
1750 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
1752 BOOL retvalue;
1753 HWND full_handle;
1755 if (is_broadcast(hwnd))
1757 SetLastError( ERROR_INVALID_PARAMETER );
1758 return FALSE;
1761 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
1762 return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
1764 hwnd = full_handle;
1766 TRACE("( %p, %d )\n", hwnd, enable);
1768 retvalue = !IsWindowEnabled( hwnd );
1770 if (enable && retvalue)
1772 WIN_SetStyle( hwnd, 0, WS_DISABLED );
1773 SendMessageW( hwnd, WM_ENABLE, TRUE, 0 );
1775 else if (!enable && !retvalue)
1777 HWND capture_wnd;
1779 SendMessageW( hwnd, WM_CANCELMODE, 0, 0);
1781 WIN_SetStyle( hwnd, WS_DISABLED, 0 );
1783 if (hwnd == GetFocus())
1784 SetFocus( 0 ); /* A disabled window can't have the focus */
1786 capture_wnd = GetCapture();
1787 if (hwnd == capture_wnd || IsChild(hwnd, capture_wnd))
1788 ReleaseCapture(); /* A disabled window can't capture the mouse */
1790 SendMessageW( hwnd, WM_ENABLE, FALSE, 0 );
1792 return retvalue;
1796 /***********************************************************************
1797 * IsWindowEnabled (USER32.@)
1799 BOOL WINAPI IsWindowEnabled(HWND hWnd)
1801 return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
1805 /***********************************************************************
1806 * IsWindowUnicode (USER32.@)
1808 BOOL WINAPI IsWindowUnicode( HWND hwnd )
1810 WND * wndPtr;
1811 BOOL retvalue = FALSE;
1813 if (!(wndPtr = WIN_GetPtr(hwnd))) return FALSE;
1815 if (wndPtr == WND_DESKTOP) return TRUE;
1817 if (wndPtr != WND_OTHER_PROCESS)
1819 retvalue = (wndPtr->flags & WIN_ISUNICODE) != 0;
1820 WIN_ReleasePtr( wndPtr );
1822 else
1824 SERVER_START_REQ( get_window_info )
1826 req->handle = hwnd;
1827 if (!wine_server_call_err( req )) retvalue = reply->is_unicode;
1829 SERVER_END_REQ;
1831 return retvalue;
1835 /**********************************************************************
1836 * WIN_GetWindowLong
1838 * Helper function for GetWindowLong().
1840 static LONG_PTR WIN_GetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicode )
1842 LONG_PTR retvalue = 0;
1843 WND *wndPtr;
1845 if (offset == GWLP_HWNDPARENT)
1847 HWND parent = GetAncestor( hwnd, GA_PARENT );
1848 if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
1849 return (ULONG_PTR)parent;
1852 if (!(wndPtr = WIN_GetPtr( hwnd )))
1854 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1855 return 0;
1858 if (wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP)
1860 if (offset == GWLP_WNDPROC)
1862 SetLastError( ERROR_ACCESS_DENIED );
1863 return 0;
1865 SERVER_START_REQ( set_window_info )
1867 req->handle = hwnd;
1868 req->flags = 0; /* don't set anything, just retrieve */
1869 req->extra_offset = (offset >= 0) ? offset : -1;
1870 req->extra_size = (offset >= 0) ? size : 0;
1871 if (!wine_server_call_err( req ))
1873 switch(offset)
1875 case GWL_STYLE: retvalue = reply->old_style; break;
1876 case GWL_EXSTYLE: retvalue = reply->old_ex_style; break;
1877 case GWLP_ID: retvalue = reply->old_id; break;
1878 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)reply->old_instance; break;
1879 case GWLP_USERDATA: retvalue = reply->old_user_data; break;
1880 default:
1881 if (offset >= 0) retvalue = get_win_data( &reply->old_extra_value, size );
1882 else SetLastError( ERROR_INVALID_INDEX );
1883 break;
1887 SERVER_END_REQ;
1888 return retvalue;
1891 /* now we have a valid wndPtr */
1893 if (offset >= 0)
1895 if (offset > (int)(wndPtr->cbWndExtra - size))
1897 WARN("Invalid offset %d\n", offset );
1898 WIN_ReleasePtr( wndPtr );
1899 SetLastError( ERROR_INVALID_INDEX );
1900 return 0;
1902 retvalue = get_win_data( (char *)wndPtr->wExtra + offset, size );
1904 /* Special case for dialog window procedure */
1905 if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && (wndPtr->flags & WIN_ISDIALOG))
1906 retvalue = (LONG_PTR)WINPROC_GetProc( (WNDPROC)retvalue, unicode );
1907 WIN_ReleasePtr( wndPtr );
1908 return retvalue;
1911 switch(offset)
1913 case GWLP_USERDATA: retvalue = wndPtr->userdata; break;
1914 case GWL_STYLE: retvalue = wndPtr->dwStyle; break;
1915 case GWL_EXSTYLE: retvalue = wndPtr->dwExStyle; break;
1916 case GWLP_ID: retvalue = wndPtr->wIDmenu; break;
1917 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hInstance; break;
1918 case GWLP_WNDPROC:
1919 /* This looks like a hack only for the edit control (see tests). This makes these controls
1920 * more tolerant to A/W mismatches. The lack of W->A->W conversion for such a mismatch suggests
1921 * that the hack is in GetWindowLongPtr[AW], not in winprocs.
1923 if (wndPtr->winproc == EDIT_winproc_handle && (!unicode != !(wndPtr->flags & WIN_ISUNICODE)))
1924 retvalue = (ULONG_PTR)wndPtr->winproc;
1925 else
1926 retvalue = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, unicode );
1927 break;
1928 default:
1929 WARN("Unknown offset %d\n", offset );
1930 SetLastError( ERROR_INVALID_INDEX );
1931 break;
1933 WIN_ReleasePtr(wndPtr);
1934 return retvalue;
1938 /**********************************************************************
1939 * WIN_SetWindowLong
1941 * Helper function for SetWindowLong().
1943 * 0 is the failure code. However, in the case of failure SetLastError
1944 * must be set to distinguish between a 0 return value and a failure.
1946 LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, UINT size, LONG_PTR newval, BOOL unicode )
1948 STYLESTRUCT style;
1949 BOOL ok;
1950 LONG_PTR retval = 0;
1951 WND *wndPtr;
1953 TRACE( "%p %d %lx %c\n", hwnd, offset, newval, unicode ? 'W' : 'A' );
1955 if (is_broadcast(hwnd))
1957 SetLastError( ERROR_INVALID_PARAMETER );
1958 return FALSE;
1961 if (!(wndPtr = WIN_GetPtr( hwnd )))
1963 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1964 return 0;
1966 if (wndPtr == WND_DESKTOP)
1968 /* can't change anything on the desktop window */
1969 SetLastError( ERROR_ACCESS_DENIED );
1970 return 0;
1972 if (wndPtr == WND_OTHER_PROCESS)
1974 if (offset == GWLP_WNDPROC)
1976 SetLastError( ERROR_ACCESS_DENIED );
1977 return 0;
1979 if (offset > 32767 || offset < -32767)
1981 SetLastError( ERROR_INVALID_INDEX );
1982 return 0;
1984 return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, MAKEWPARAM( offset, size ), newval );
1987 /* first some special cases */
1988 switch( offset )
1990 case GWL_STYLE:
1991 case GWL_EXSTYLE:
1992 style.styleOld =
1993 offset == GWL_STYLE ? wndPtr->dwStyle : wndPtr->dwExStyle;
1994 style.styleNew = newval;
1995 WIN_ReleasePtr( wndPtr );
1996 SendMessageW( hwnd, WM_STYLECHANGING, offset, (LPARAM)&style );
1997 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
1998 newval = style.styleNew;
1999 break;
2000 case GWLP_HWNDPARENT:
2001 if (wndPtr->parent == GetDesktopWindow())
2003 WIN_ReleasePtr( wndPtr );
2004 return (ULONG_PTR)WIN_SetOwner( hwnd, (HWND)newval );
2006 else
2008 WIN_ReleasePtr( wndPtr );
2009 return (ULONG_PTR)SetParent( hwnd, (HWND)newval );
2011 case GWLP_WNDPROC:
2013 WNDPROC proc;
2014 UINT old_flags = wndPtr->flags;
2015 retval = WIN_GetWindowLong( hwnd, offset, size, unicode );
2016 if (unicode) proc = WINPROC_AllocProc( NULL, (WNDPROC)newval );
2017 else proc = WINPROC_AllocProc( (WNDPROC)newval, NULL );
2018 if (proc) wndPtr->winproc = proc;
2019 if (WINPROC_IsUnicode( proc, unicode )) wndPtr->flags |= WIN_ISUNICODE;
2020 else wndPtr->flags &= ~WIN_ISUNICODE;
2021 if (!((old_flags ^ wndPtr->flags) & WIN_ISUNICODE))
2023 WIN_ReleasePtr( wndPtr );
2024 return retval;
2026 /* update is_unicode flag on the server side */
2027 break;
2029 case GWLP_ID:
2030 case GWLP_HINSTANCE:
2031 case GWLP_USERDATA:
2032 break;
2033 case DWLP_DLGPROC:
2034 if ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
2035 (size == sizeof(LONG_PTR)) && (wndPtr->flags & WIN_ISDIALOG))
2037 WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWLP_DLGPROC);
2038 retval = (ULONG_PTR)WINPROC_GetProc( *ptr, unicode );
2039 if (unicode) *ptr = WINPROC_AllocProc( NULL, (WNDPROC)newval );
2040 else *ptr = WINPROC_AllocProc( (WNDPROC)newval, NULL );
2041 WIN_ReleasePtr( wndPtr );
2042 return retval;
2044 /* fall through */
2045 default:
2046 if (offset < 0 || offset > (int)(wndPtr->cbWndExtra - size))
2048 WARN("Invalid offset %d\n", offset );
2049 WIN_ReleasePtr( wndPtr );
2050 SetLastError( ERROR_INVALID_INDEX );
2051 return 0;
2053 else if (get_win_data( (char *)wndPtr->wExtra + offset, size ) == newval)
2055 /* already set to the same value */
2056 WIN_ReleasePtr( wndPtr );
2057 return newval;
2059 break;
2062 SERVER_START_REQ( set_window_info )
2064 req->handle = hwnd;
2065 req->extra_offset = -1;
2066 switch(offset)
2068 case GWL_STYLE:
2069 req->flags = SET_WIN_STYLE;
2070 req->style = newval;
2071 break;
2072 case GWL_EXSTYLE:
2073 req->flags = SET_WIN_EXSTYLE;
2074 /* WS_EX_TOPMOST can only be changed through SetWindowPos */
2075 newval = (newval & ~WS_EX_TOPMOST) | (wndPtr->dwExStyle & WS_EX_TOPMOST);
2076 req->ex_style = newval;
2077 break;
2078 case GWLP_ID:
2079 req->flags = SET_WIN_ID;
2080 req->id = newval;
2081 break;
2082 case GWLP_HINSTANCE:
2083 req->flags = SET_WIN_INSTANCE;
2084 req->instance = (void *)newval;
2085 break;
2086 case GWLP_WNDPROC:
2087 req->flags = SET_WIN_UNICODE;
2088 req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
2089 break;
2090 case GWLP_USERDATA:
2091 req->flags = SET_WIN_USERDATA;
2092 req->user_data = newval;
2093 break;
2094 default:
2095 req->flags = SET_WIN_EXTRA;
2096 req->extra_offset = offset;
2097 req->extra_size = size;
2098 set_win_data( &req->extra_value, newval, size );
2100 if ((ok = !wine_server_call_err( req )))
2102 switch(offset)
2104 case GWL_STYLE:
2105 wndPtr->dwStyle = newval;
2106 retval = reply->old_style;
2107 break;
2108 case GWL_EXSTYLE:
2109 wndPtr->dwExStyle = newval;
2110 retval = reply->old_ex_style;
2111 break;
2112 case GWLP_ID:
2113 wndPtr->wIDmenu = newval;
2114 retval = reply->old_id;
2115 break;
2116 case GWLP_HINSTANCE:
2117 wndPtr->hInstance = (HINSTANCE)newval;
2118 retval = (ULONG_PTR)reply->old_instance;
2119 break;
2120 case GWLP_WNDPROC:
2121 break;
2122 case GWLP_USERDATA:
2123 wndPtr->userdata = newval;
2124 retval = reply->old_user_data;
2125 break;
2126 default:
2127 retval = get_win_data( (char *)wndPtr->wExtra + offset, size );
2128 set_win_data( (char *)wndPtr->wExtra + offset, newval, size );
2129 break;
2133 SERVER_END_REQ;
2134 WIN_ReleasePtr( wndPtr );
2136 if (!ok) return 0;
2138 if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2140 USER_Driver->pSetWindowStyle( hwnd, offset, &style );
2141 SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2144 return retval;
2148 /**********************************************************************
2149 * GetWindowLong (USER.135)
2151 LONG WINAPI GetWindowLong16( HWND16 hwnd, INT16 offset )
2153 WND *wndPtr;
2154 LONG_PTR retvalue;
2155 BOOL is_winproc = (offset == GWLP_WNDPROC);
2157 if (offset >= 0)
2159 if (!(wndPtr = WIN_GetPtr( WIN_Handle32(hwnd) )))
2161 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2162 return 0;
2164 if (wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
2166 if (offset > (int)(wndPtr->cbWndExtra - sizeof(LONG)))
2169 * Some programs try to access last element from 16 bit
2170 * code using illegal offset value. Hopefully this is
2171 * what those programs really expect.
2173 if (wndPtr->cbWndExtra >= 4 && offset == wndPtr->cbWndExtra - sizeof(WORD))
2175 INT offset2 = wndPtr->cbWndExtra - sizeof(LONG);
2176 ERR( "- replaced invalid offset %d with %d\n", offset, offset2 );
2177 offset = offset2;
2179 else
2181 WARN("Invalid offset %d\n", offset );
2182 WIN_ReleasePtr( wndPtr );
2183 SetLastError( ERROR_INVALID_INDEX );
2184 return 0;
2187 is_winproc = ((offset == DWLP_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG));
2188 WIN_ReleasePtr( wndPtr );
2191 retvalue = GetWindowLongA( WIN_Handle32(hwnd), offset );
2192 if (is_winproc) retvalue = (LONG_PTR)WINPROC_GetProc16( (WNDPROC)retvalue, FALSE );
2193 return retvalue;
2197 /**********************************************************************
2198 * GetWindowWord (USER32.@)
2200 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
2202 switch(offset)
2204 case GWLP_ID:
2205 case GWLP_HINSTANCE:
2206 case GWLP_HWNDPARENT:
2207 break;
2208 default:
2209 if (offset < 0)
2211 WARN("Invalid offset %d\n", offset );
2212 SetLastError( ERROR_INVALID_INDEX );
2213 return 0;
2215 break;
2217 return WIN_GetWindowLong( hwnd, offset, sizeof(WORD), FALSE );
2221 /**********************************************************************
2222 * GetWindowLongA (USER32.@)
2224 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2226 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), FALSE );
2230 /**********************************************************************
2231 * GetWindowLongW (USER32.@)
2233 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2235 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), TRUE );
2239 /**********************************************************************
2240 * SetWindowLong (USER.136)
2242 LONG WINAPI SetWindowLong16( HWND16 hwnd, INT16 offset, LONG newval )
2244 WND *wndPtr;
2245 BOOL is_winproc = (offset == GWLP_WNDPROC);
2247 if (offset == DWLP_DLGPROC)
2249 if (!(wndPtr = WIN_GetPtr( WIN_Handle32(hwnd) )))
2251 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2252 return 0;
2254 if (wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
2256 is_winproc = ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
2257 (wndPtr->flags & WIN_ISDIALOG));
2258 WIN_ReleasePtr( wndPtr );
2262 if (is_winproc)
2264 WNDPROC new_proc = WINPROC_AllocProc16( (WNDPROC16)newval );
2265 WNDPROC old_proc = (WNDPROC)SetWindowLongPtrA( WIN_Handle32(hwnd), offset, (LONG_PTR)new_proc );
2266 return (LONG)WINPROC_GetProc16( old_proc, FALSE );
2268 else return SetWindowLongA( WIN_Handle32(hwnd), offset, newval );
2272 /**********************************************************************
2273 * SetWindowWord (USER32.@)
2275 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
2277 switch(offset)
2279 case GWLP_ID:
2280 case GWLP_HINSTANCE:
2281 case GWLP_HWNDPARENT:
2282 break;
2283 default:
2284 if (offset < 0)
2286 WARN("Invalid offset %d\n", offset );
2287 SetLastError( ERROR_INVALID_INDEX );
2288 return 0;
2290 break;
2292 return WIN_SetWindowLong( hwnd, offset, sizeof(WORD), newval, FALSE );
2296 /**********************************************************************
2297 * SetWindowLongA (USER32.@)
2299 * See SetWindowLongW.
2301 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2303 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, FALSE );
2307 /**********************************************************************
2308 * SetWindowLongW (USER32.@) Set window attribute
2310 * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2311 * value in a window's extra memory.
2313 * The _hwnd_ parameter specifies the window. is the handle to a
2314 * window that has extra memory. The _newval_ parameter contains the
2315 * new attribute or extra memory value. If positive, the _offset_
2316 * parameter is the byte-addressed location in the window's extra
2317 * memory to set. If negative, _offset_ specifies the window
2318 * attribute to set, and should be one of the following values:
2320 * GWL_EXSTYLE The window's extended window style
2322 * GWL_STYLE The window's window style.
2324 * GWLP_WNDPROC Pointer to the window's window procedure.
2326 * GWLP_HINSTANCE The window's pplication instance handle.
2328 * GWLP_ID The window's identifier.
2330 * GWLP_USERDATA The window's user-specified data.
2332 * If the window is a dialog box, the _offset_ parameter can be one of
2333 * the following values:
2335 * DWLP_DLGPROC The address of the window's dialog box procedure.
2337 * DWLP_MSGRESULT The return value of a message
2338 * that the dialog box procedure processed.
2340 * DWLP_USER Application specific information.
2342 * RETURNS
2344 * If successful, returns the previous value located at _offset_. Otherwise,
2345 * returns 0.
2347 * NOTES
2349 * Extra memory for a window class is specified by a nonzero cbWndExtra
2350 * parameter of the WNDCLASS structure passed to RegisterClass() at the
2351 * time of class creation.
2353 * Using GWL_WNDPROC to set a new window procedure effectively creates
2354 * a window subclass. Use CallWindowProc() in the new windows procedure
2355 * to pass messages to the superclass's window procedure.
2357 * The user data is reserved for use by the application which created
2358 * the window.
2360 * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2361 * instead, call the EnableWindow() function to change the window's
2362 * disabled state.
2364 * Do not use GWL_HWNDPARENT to reset the window's parent, use
2365 * SetParent() instead.
2367 * Win95:
2368 * When offset is GWL_STYLE and the calling app's ver is 4.0,
2369 * it sends WM_STYLECHANGING before changing the settings
2370 * and WM_STYLECHANGED afterwards.
2371 * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2373 LONG WINAPI SetWindowLongW(
2374 HWND hwnd, /* [in] window to alter */
2375 INT offset, /* [in] offset, in bytes, of location to alter */
2376 LONG newval /* [in] new value of location */
2378 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, TRUE );
2382 /*******************************************************************
2383 * GetWindowTextA (USER32.@)
2385 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2387 WCHAR *buffer;
2389 if (!lpString) return 0;
2391 if (WIN_IsCurrentProcess( hwnd ))
2392 return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2394 /* when window belongs to other process, don't send a message */
2395 if (nMaxCount <= 0) return 0;
2396 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2397 get_server_window_text( hwnd, buffer, nMaxCount );
2398 if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2399 lpString[nMaxCount-1] = 0;
2400 HeapFree( GetProcessHeap(), 0, buffer );
2401 return strlen(lpString);
2405 /*******************************************************************
2406 * InternalGetWindowText (USER32.@)
2408 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2410 WND *win;
2412 if (nMaxCount <= 0) return 0;
2413 if (!(win = WIN_GetPtr( hwnd ))) return 0;
2414 if (win == WND_DESKTOP) lpString[0] = 0;
2415 else if (win != WND_OTHER_PROCESS)
2417 if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2418 else lpString[0] = 0;
2419 WIN_ReleasePtr( win );
2421 else
2423 get_server_window_text( hwnd, lpString, nMaxCount );
2425 return strlenW(lpString);
2429 /*******************************************************************
2430 * GetWindowTextW (USER32.@)
2432 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2434 if (!lpString) return 0;
2436 if (WIN_IsCurrentProcess( hwnd ))
2437 return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2439 /* when window belongs to other process, don't send a message */
2440 if (nMaxCount <= 0) return 0;
2441 get_server_window_text( hwnd, lpString, nMaxCount );
2442 return strlenW(lpString);
2446 /*******************************************************************
2447 * SetWindowTextA (USER32.@)
2448 * SetWindowText (USER32.@)
2450 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2452 if (is_broadcast(hwnd))
2454 SetLastError( ERROR_INVALID_PARAMETER );
2455 return FALSE;
2457 if (!WIN_IsCurrentProcess( hwnd ))
2458 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2459 debugstr_a(lpString), hwnd );
2460 return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2464 /*******************************************************************
2465 * SetWindowTextW (USER32.@)
2467 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2469 if (is_broadcast(hwnd))
2471 SetLastError( ERROR_INVALID_PARAMETER );
2472 return FALSE;
2474 if (!WIN_IsCurrentProcess( hwnd ))
2475 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2476 debugstr_w(lpString), hwnd );
2477 return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2481 /*******************************************************************
2482 * GetWindowTextLengthA (USER32.@)
2484 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2486 return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2489 /*******************************************************************
2490 * GetWindowTextLengthW (USER32.@)
2492 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2494 return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2498 /*******************************************************************
2499 * IsWindow (USER32.@)
2501 BOOL WINAPI IsWindow( HWND hwnd )
2503 WND *ptr;
2504 BOOL ret;
2506 if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2507 if (ptr == WND_DESKTOP) return TRUE;
2509 if (ptr != WND_OTHER_PROCESS)
2511 WIN_ReleasePtr( ptr );
2512 return TRUE;
2515 /* check other processes */
2516 SERVER_START_REQ( get_window_info )
2518 req->handle = hwnd;
2519 ret = !wine_server_call_err( req );
2521 SERVER_END_REQ;
2522 return ret;
2526 /***********************************************************************
2527 * GetWindowThreadProcessId (USER32.@)
2529 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2531 WND *ptr;
2532 DWORD tid = 0;
2534 if (!(ptr = WIN_GetPtr( hwnd )))
2536 SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2537 return 0;
2540 if (ptr != WND_OTHER_PROCESS && ptr != WND_DESKTOP)
2542 /* got a valid window */
2543 tid = ptr->tid;
2544 if (process) *process = GetCurrentProcessId();
2545 WIN_ReleasePtr( ptr );
2546 return tid;
2549 /* check other processes */
2550 SERVER_START_REQ( get_window_info )
2552 req->handle = hwnd;
2553 if (!wine_server_call_err( req ))
2555 tid = (DWORD)reply->tid;
2556 if (process) *process = (DWORD)reply->pid;
2559 SERVER_END_REQ;
2560 return tid;
2564 /*****************************************************************
2565 * GetParent (USER32.@)
2567 HWND WINAPI GetParent( HWND hwnd )
2569 WND *wndPtr;
2570 HWND retvalue = 0;
2572 if (!(wndPtr = WIN_GetPtr( hwnd )))
2574 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2575 return 0;
2577 if (wndPtr == WND_DESKTOP) return 0;
2578 if (wndPtr == WND_OTHER_PROCESS)
2580 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2581 if (style & (WS_POPUP | WS_CHILD))
2583 SERVER_START_REQ( get_window_tree )
2585 req->handle = hwnd;
2586 if (!wine_server_call_err( req ))
2588 if (style & WS_POPUP) retvalue = reply->owner;
2589 else if (style & WS_CHILD) retvalue = reply->parent;
2592 SERVER_END_REQ;
2595 else
2597 if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2598 else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2599 WIN_ReleasePtr( wndPtr );
2601 return retvalue;
2605 /*****************************************************************
2606 * GetAncestor (USER32.@)
2608 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2610 WND *win;
2611 HWND *list, ret = 0;
2613 switch(type)
2615 case GA_PARENT:
2616 if (!(win = WIN_GetPtr( hwnd )))
2618 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2619 return 0;
2621 if (win == WND_DESKTOP) return 0;
2622 if (win != WND_OTHER_PROCESS)
2624 ret = win->parent;
2625 WIN_ReleasePtr( win );
2627 else /* need to query the server */
2629 SERVER_START_REQ( get_window_tree )
2631 req->handle = hwnd;
2632 if (!wine_server_call_err( req )) ret = reply->parent;
2634 SERVER_END_REQ;
2636 break;
2638 case GA_ROOT:
2639 if (!(list = list_window_parents( hwnd ))) return 0;
2641 if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd ); /* top-level window */
2642 else
2644 int count = 2;
2645 while (list[count]) count++;
2646 ret = list[count - 2]; /* get the one before the desktop */
2648 HeapFree( GetProcessHeap(), 0, list );
2649 break;
2651 case GA_ROOTOWNER:
2652 if (is_desktop_window( hwnd )) return 0;
2653 ret = WIN_GetFullHandle( hwnd );
2654 for (;;)
2656 HWND parent = GetParent( ret );
2657 if (!parent) break;
2658 ret = parent;
2660 break;
2662 return ret;
2666 /*****************************************************************
2667 * SetParent (USER32.@)
2669 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2671 HWND full_handle;
2672 HWND old_parent = 0;
2673 BOOL was_visible;
2674 WND *wndPtr;
2675 BOOL ret;
2677 if (is_broadcast(hwnd) || is_broadcast(parent))
2679 SetLastError(ERROR_INVALID_PARAMETER);
2680 return 0;
2683 if (!parent) parent = GetDesktopWindow();
2684 else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
2685 else parent = WIN_GetFullHandle( parent );
2687 if (!IsWindow( parent ))
2689 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2690 return 0;
2693 /* Some applications try to set a child as a parent */
2694 if (IsChild(hwnd, parent))
2696 SetLastError( ERROR_INVALID_PARAMETER );
2697 return 0;
2700 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2701 return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2703 /* Windows hides the window first, then shows it again
2704 * including the WM_SHOWWINDOW messages and all */
2705 was_visible = ShowWindow( hwnd, SW_HIDE );
2707 wndPtr = WIN_GetPtr( hwnd );
2708 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
2710 SERVER_START_REQ( set_parent )
2712 req->handle = hwnd;
2713 req->parent = parent;
2714 if ((ret = !wine_server_call( req )))
2716 old_parent = reply->old_parent;
2717 wndPtr->parent = parent = reply->full_parent;
2721 SERVER_END_REQ;
2722 WIN_ReleasePtr( wndPtr );
2723 if (!ret) return 0;
2725 USER_Driver->pSetParent( full_handle, parent, old_parent );
2727 /* SetParent additionally needs to make hwnd the topmost window
2728 in the x-order and send the expected WM_WINDOWPOSCHANGING and
2729 WM_WINDOWPOSCHANGED notification messages.
2731 SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0,
2732 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | (was_visible ? SWP_SHOWWINDOW : 0) );
2733 /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
2734 * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
2736 return old_parent;
2740 /*******************************************************************
2741 * IsChild (USER32.@)
2743 BOOL WINAPI IsChild( HWND parent, HWND child )
2745 HWND *list = list_window_parents( child );
2746 int i;
2747 BOOL ret;
2749 if (!list) return FALSE;
2750 parent = WIN_GetFullHandle( parent );
2751 for (i = 0; list[i]; i++) if (list[i] == parent) break;
2752 ret = list[i] && list[i+1];
2753 HeapFree( GetProcessHeap(), 0, list );
2754 return ret;
2758 /***********************************************************************
2759 * IsWindowVisible (USER32.@)
2761 BOOL WINAPI IsWindowVisible( HWND hwnd )
2763 HWND *list;
2764 BOOL retval = TRUE;
2765 int i;
2767 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2768 if (!(list = list_window_parents( hwnd ))) return TRUE;
2769 if (list[0])
2771 for (i = 0; list[i+1]; i++)
2772 if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2773 retval = !list[i+1] && (list[i] == GetDesktopWindow()); /* top message window isn't visible */
2775 HeapFree( GetProcessHeap(), 0, list );
2776 return retval;
2780 /***********************************************************************
2781 * WIN_IsWindowDrawable
2783 * hwnd is drawable when it is visible, all parents are not
2784 * minimized, and it is itself not minimized unless we are
2785 * trying to draw its default class icon.
2787 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2789 HWND *list;
2790 BOOL retval = TRUE;
2791 int i;
2792 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2794 if (!(style & WS_VISIBLE)) return FALSE;
2795 if ((style & WS_MINIMIZE) && icon && GetClassLongPtrW( hwnd, GCLP_HICON )) return FALSE;
2797 if (!(list = list_window_parents( hwnd ))) return TRUE;
2798 if (list[0])
2800 for (i = 0; list[i+1]; i++)
2801 if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2802 break;
2803 retval = !list[i+1] && (list[i] == GetDesktopWindow()); /* top message window isn't visible */
2805 HeapFree( GetProcessHeap(), 0, list );
2806 return retval;
2810 /*******************************************************************
2811 * GetTopWindow (USER32.@)
2813 HWND WINAPI GetTopWindow( HWND hwnd )
2815 if (!hwnd) hwnd = GetDesktopWindow();
2816 return GetWindow( hwnd, GW_CHILD );
2820 /*******************************************************************
2821 * GetWindow (USER32.@)
2823 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2825 HWND retval = 0;
2827 if (rel == GW_OWNER) /* this one may be available locally */
2829 WND *wndPtr = WIN_GetPtr( hwnd );
2830 if (!wndPtr)
2832 SetLastError( ERROR_INVALID_HANDLE );
2833 return 0;
2835 if (wndPtr == WND_DESKTOP) return 0;
2836 if (wndPtr != WND_OTHER_PROCESS)
2838 retval = wndPtr->owner;
2839 WIN_ReleasePtr( wndPtr );
2840 return retval;
2842 /* else fall through to server call */
2845 SERVER_START_REQ( get_window_tree )
2847 req->handle = hwnd;
2848 if (!wine_server_call_err( req ))
2850 switch(rel)
2852 case GW_HWNDFIRST:
2853 retval = reply->first_sibling;
2854 break;
2855 case GW_HWNDLAST:
2856 retval = reply->last_sibling;
2857 break;
2858 case GW_HWNDNEXT:
2859 retval = reply->next_sibling;
2860 break;
2861 case GW_HWNDPREV:
2862 retval = reply->prev_sibling;
2863 break;
2864 case GW_OWNER:
2865 retval = reply->owner;
2866 break;
2867 case GW_CHILD:
2868 retval = reply->first_child;
2869 break;
2873 SERVER_END_REQ;
2874 return retval;
2878 /*******************************************************************
2879 * ShowOwnedPopups (USER32.@)
2881 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2883 int count = 0;
2884 WND *pWnd;
2885 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2887 if (!win_array) return TRUE;
2889 while (win_array[count]) count++;
2890 while (--count >= 0)
2892 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2893 if (!(pWnd = WIN_GetPtr( win_array[count] ))) continue;
2894 if (pWnd == WND_OTHER_PROCESS) continue;
2895 if (fShow)
2897 if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2899 WIN_ReleasePtr( pWnd );
2900 /* In Windows, ShowOwnedPopups(TRUE) generates
2901 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
2902 * regardless of the state of the owner
2904 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
2905 continue;
2908 else
2910 if (pWnd->dwStyle & WS_VISIBLE)
2912 WIN_ReleasePtr( pWnd );
2913 /* In Windows, ShowOwnedPopups(FALSE) generates
2914 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
2915 * regardless of the state of the owner
2917 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
2918 continue;
2921 WIN_ReleasePtr( pWnd );
2923 HeapFree( GetProcessHeap(), 0, win_array );
2924 return TRUE;
2928 /*******************************************************************
2929 * GetLastActivePopup (USER32.@)
2931 HWND WINAPI GetLastActivePopup( HWND hwnd )
2933 HWND retval = hwnd;
2935 SERVER_START_REQ( get_window_info )
2937 req->handle = hwnd;
2938 if (!wine_server_call_err( req )) retval = reply->last_active;
2940 SERVER_END_REQ;
2941 return retval;
2945 /*******************************************************************
2946 * WIN_ListChildren
2948 * Build an array of the children of a given window. The array must be
2949 * freed with HeapFree. Returns NULL when no windows are found.
2951 HWND *WIN_ListChildren( HWND hwnd )
2953 if (!hwnd)
2955 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2956 return NULL;
2958 return list_window_children( 0, hwnd, NULL, 0 );
2962 /*******************************************************************
2963 * EnumWindows (USER32.@)
2965 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
2967 HWND *list;
2968 BOOL ret = TRUE;
2969 int i;
2971 USER_CheckNotLock();
2973 /* We have to build a list of all windows first, to avoid */
2974 /* unpleasant side-effects, for instance if the callback */
2975 /* function changes the Z-order of the windows. */
2977 if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
2979 /* Now call the callback function for every window */
2981 for (i = 0; list[i]; i++)
2983 /* Make sure that the window still exists */
2984 if (!IsWindow( list[i] )) continue;
2985 if (!(ret = lpEnumFunc( list[i], lParam ))) break;
2987 HeapFree( GetProcessHeap(), 0, list );
2988 return ret;
2992 /**********************************************************************
2993 * EnumThreadWindows (USER32.@)
2995 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
2997 HWND *list;
2998 int i;
3000 USER_CheckNotLock();
3002 if (!(list = list_window_children( 0, GetDesktopWindow(), NULL, id ))) return TRUE;
3004 /* Now call the callback function for every window */
3006 for (i = 0; list[i]; i++)
3007 if (!func( list[i], lParam )) break;
3008 HeapFree( GetProcessHeap(), 0, list );
3009 return TRUE;
3013 /***********************************************************************
3014 * EnumDesktopWindows (USER32.@)
3016 BOOL WINAPI EnumDesktopWindows( HDESK desktop, WNDENUMPROC func, LPARAM lparam )
3018 HWND *list;
3019 int i;
3021 USER_CheckNotLock();
3023 if (!(list = list_window_children( desktop, 0, NULL, 0 ))) return TRUE;
3025 for (i = 0; list[i]; i++)
3026 if (!func( list[i], lparam )) break;
3027 HeapFree( GetProcessHeap(), 0, list );
3028 return TRUE;
3032 /**********************************************************************
3033 * WIN_EnumChildWindows
3035 * Helper function for EnumChildWindows().
3037 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
3039 HWND *childList;
3040 BOOL ret = FALSE;
3042 for ( ; *list; list++)
3044 /* Make sure that the window still exists */
3045 if (!IsWindow( *list )) continue;
3046 /* Build children list first */
3047 childList = WIN_ListChildren( *list );
3049 ret = func( *list, lParam );
3051 if (childList)
3053 if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
3054 HeapFree( GetProcessHeap(), 0, childList );
3056 if (!ret) return FALSE;
3058 return TRUE;
3062 /**********************************************************************
3063 * EnumChildWindows (USER32.@)
3065 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
3067 HWND *list;
3068 BOOL ret;
3070 USER_CheckNotLock();
3072 if (!(list = WIN_ListChildren( parent ))) return FALSE;
3073 ret = WIN_EnumChildWindows( list, func, lParam );
3074 HeapFree( GetProcessHeap(), 0, list );
3075 return ret;
3079 /*******************************************************************
3080 * AnyPopup (USER.52)
3082 BOOL16 WINAPI AnyPopup16(void)
3084 return AnyPopup();
3088 /*******************************************************************
3089 * AnyPopup (USER32.@)
3091 BOOL WINAPI AnyPopup(void)
3093 int i;
3094 BOOL retvalue;
3095 HWND *list = WIN_ListChildren( GetDesktopWindow() );
3097 if (!list) return FALSE;
3098 for (i = 0; list[i]; i++)
3100 if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
3102 retvalue = (list[i] != 0);
3103 HeapFree( GetProcessHeap(), 0, list );
3104 return retvalue;
3108 /*******************************************************************
3109 * FlashWindow (USER32.@)
3111 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3113 WND *wndPtr;
3115 TRACE("%p\n", hWnd);
3117 if (IsIconic( hWnd ))
3119 RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
3121 wndPtr = WIN_GetPtr(hWnd);
3122 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3123 if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
3125 wndPtr->flags |= WIN_NCACTIVATED;
3127 else
3129 wndPtr->flags &= ~WIN_NCACTIVATED;
3131 WIN_ReleasePtr( wndPtr );
3132 return TRUE;
3134 else
3136 WPARAM wparam;
3138 wndPtr = WIN_GetPtr(hWnd);
3139 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3140 hWnd = wndPtr->hwndSelf; /* make it a full handle */
3142 if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3143 else wparam = (hWnd == GetForegroundWindow());
3145 WIN_ReleasePtr( wndPtr );
3146 SendMessageW( hWnd, WM_NCACTIVATE, wparam, (LPARAM)0 );
3147 return wparam;
3151 /*******************************************************************
3152 * FlashWindowEx (USER32.@)
3154 BOOL WINAPI FlashWindowEx( PFLASHWINFO pfwi )
3156 FIXME("%p\n", pfwi);
3157 return TRUE;
3160 /*******************************************************************
3161 * GetWindowContextHelpId (USER32.@)
3163 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3165 DWORD retval;
3166 WND *wnd = WIN_GetPtr( hwnd );
3167 if (!wnd || wnd == WND_DESKTOP) return 0;
3168 if (wnd == WND_OTHER_PROCESS)
3170 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3171 return 0;
3173 retval = wnd->helpContext;
3174 WIN_ReleasePtr( wnd );
3175 return retval;
3179 /*******************************************************************
3180 * SetWindowContextHelpId (USER32.@)
3182 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3184 WND *wnd = WIN_GetPtr( hwnd );
3185 if (!wnd || wnd == WND_DESKTOP) return FALSE;
3186 if (wnd == WND_OTHER_PROCESS)
3188 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3189 return 0;
3191 wnd->helpContext = id;
3192 WIN_ReleasePtr( wnd );
3193 return TRUE;
3197 /*******************************************************************
3198 * DragDetect (USER32.@)
3200 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3202 MSG msg;
3203 RECT rect;
3204 WORD wDragWidth = GetSystemMetrics(SM_CXDRAG);
3205 WORD wDragHeight= GetSystemMetrics(SM_CYDRAG);
3207 rect.left = pt.x - wDragWidth;
3208 rect.right = pt.x + wDragWidth;
3210 rect.top = pt.y - wDragHeight;
3211 rect.bottom = pt.y + wDragHeight;
3213 SetCapture(hWnd);
3215 while(1)
3217 while (PeekMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ))
3219 if( msg.message == WM_LBUTTONUP )
3221 ReleaseCapture();
3222 return 0;
3224 if( msg.message == WM_MOUSEMOVE )
3226 POINT tmp;
3227 tmp.x = (short)LOWORD(msg.lParam);
3228 tmp.y = (short)HIWORD(msg.lParam);
3229 if( !PtInRect( &rect, tmp ))
3231 ReleaseCapture();
3232 return 1;
3236 WaitMessage();
3238 return 0;
3241 /******************************************************************************
3242 * GetWindowModuleFileNameA (USER32.@)
3244 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR module, UINT size )
3246 WND *win;
3247 HINSTANCE hinst;
3249 TRACE( "%p, %p, %u\n", hwnd, module, size );
3251 win = WIN_GetPtr( hwnd );
3252 if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3254 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3255 return 0;
3257 hinst = win->hInstance;
3258 WIN_ReleasePtr( win );
3260 return GetModuleFileNameA( hinst, module, size );
3263 /******************************************************************************
3264 * GetWindowModuleFileNameW (USER32.@)
3266 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR module, UINT size )
3268 WND *win;
3269 HINSTANCE hinst;
3271 TRACE( "%p, %p, %u\n", hwnd, module, size );
3273 win = WIN_GetPtr( hwnd );
3274 if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3276 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3277 return 0;
3279 hinst = win->hInstance;
3280 WIN_ReleasePtr( win );
3282 return GetModuleFileNameW( hinst, module, size );
3285 /******************************************************************************
3286 * GetWindowInfo (USER32.@)
3288 * Note: tests show that Windows doesn't check cbSize of the structure.
3290 BOOL WINAPI GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3292 if (!pwi) return FALSE;
3293 if (!IsWindow(hwnd)) return FALSE;
3295 GetWindowRect(hwnd, &pwi->rcWindow);
3296 GetClientRect(hwnd, &pwi->rcClient);
3297 /* translate to screen coordinates */
3298 MapWindowPoints(hwnd, 0, (LPPOINT)&pwi->rcClient, 2);
3300 pwi->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
3301 pwi->dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3302 pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3304 pwi->cxWindowBorders = pwi->rcClient.left - pwi->rcWindow.left;
3305 pwi->cyWindowBorders = pwi->rcWindow.bottom - pwi->rcClient.bottom;
3307 pwi->atomWindowType = GetClassLongW( hwnd, GCW_ATOM );
3308 pwi->wCreatorVersion = 0x0400;
3310 return TRUE;
3313 /******************************************************************************
3314 * SwitchDesktop (USER32.@)
3316 * NOTES: Sets the current input or interactive desktop.
3318 BOOL WINAPI SwitchDesktop( HDESK hDesktop)
3320 FIXME("SwitchDesktop(hwnd %p) stub!\n", hDesktop);
3321 return TRUE;
3324 /*****************************************************************************
3325 * SetLayeredWindowAttributes (USER32.@)
3327 BOOL WINAPI SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, DWORD flags )
3329 BOOL ret;
3331 TRACE("(%p,%08x,%d,%x): stub!\n", hwnd, key, alpha, flags);
3333 SERVER_START_REQ( set_window_layered_info )
3335 req->handle = hwnd;
3336 req->color_key = key;
3337 req->alpha = alpha;
3338 req->flags = flags;
3339 ret = !wine_server_call_err( req );
3341 SERVER_END_REQ;
3343 if (ret) USER_Driver->pSetLayeredWindowAttributes( hwnd, key, alpha, flags );
3345 return ret;
3349 /*****************************************************************************
3350 * GetLayeredWindowAttributes (USER32.@)
3352 BOOL WINAPI GetLayeredWindowAttributes( HWND hwnd, COLORREF *key, BYTE *alpha, DWORD *flags )
3354 BOOL ret;
3356 SERVER_START_REQ( get_window_layered_info )
3358 req->handle = hwnd;
3359 if ((ret = !wine_server_call_err( req )))
3361 if (key) *key = reply->color_key;
3362 if (alpha) *alpha = reply->alpha;
3363 if (flags) *flags = reply->flags;
3366 SERVER_END_REQ;
3368 return ret;
3372 /*****************************************************************************
3373 * UpdateLayeredWindowIndirect (USER32.@)
3375 BOOL WINAPI UpdateLayeredWindowIndirect( HWND hwnd, const UPDATELAYEREDWINDOWINFO *info )
3377 BYTE alpha = 0xff;
3379 if (!(info->dwFlags & ULW_EX_NORESIZE) && (info->pptDst || info->psize))
3381 int x = 0, y = 0, cx = 0, cy = 0;
3382 DWORD flags = SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOSENDCHANGING;
3384 if (info->pptDst)
3386 x = info->pptDst->x;
3387 y = info->pptDst->y;
3388 flags &= ~SWP_NOMOVE;
3390 if (info->psize)
3392 cx = info->psize->cx;
3393 cy = info->psize->cy;
3394 flags &= ~SWP_NOSIZE;
3396 TRACE( "moving window %p pos %d,%d %dx%x\n", hwnd, x, y, cx, cy );
3397 SetWindowPos( hwnd, 0, x, y, cx, cy, flags );
3400 if (info->hdcSrc)
3402 RECT rect;
3403 HDC hdc = GetDCEx( hwnd, 0, DCX_CACHE );
3405 if (hdc)
3407 int x = 0, y = 0;
3409 GetClientRect( hwnd, &rect );
3410 if (info->pptSrc)
3412 x = info->pptSrc->x;
3413 y = info->pptSrc->y;
3415 /* FIXME: intersect rect with info->prcDirty */
3416 TRACE( "copying window %p pos %d,%d\n", hwnd, x, y );
3417 BitBlt( hdc, rect.left, rect.top, rect.right, rect.bottom,
3418 info->hdcSrc, rect.left + x, rect.top + y, SRCCOPY );
3419 ReleaseDC( hwnd, hdc );
3423 if (info->pblend && !(info->dwFlags & ULW_OPAQUE)) alpha = info->pblend->SourceConstantAlpha;
3424 TRACE( "setting window %p alpha %u\n", hwnd, alpha );
3425 USER_Driver->pSetLayeredWindowAttributes( hwnd, info->crKey, alpha,
3426 info->dwFlags & (LWA_ALPHA | LWA_COLORKEY) );
3427 return TRUE;
3431 /*****************************************************************************
3432 * UpdateLayeredWindow (USER32.@)
3434 BOOL WINAPI UpdateLayeredWindow( HWND hwnd, HDC hdcDst, POINT *pptDst, SIZE *psize,
3435 HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend,
3436 DWORD dwFlags)
3438 UPDATELAYEREDWINDOWINFO info;
3440 info.cbSize = sizeof(info);
3441 info.hdcDst = hdcDst;
3442 info.pptDst = pptDst;
3443 info.psize = psize;
3444 info.hdcSrc = hdcSrc;
3445 info.pptSrc = pptSrc;
3446 info.crKey = crKey;
3447 info.pblend = pblend;
3448 info.dwFlags = dwFlags;
3449 info.prcDirty = NULL;
3450 return UpdateLayeredWindowIndirect( hwnd, &info );
3453 /* 64bit versions */
3455 #ifdef GetWindowLongPtrW
3456 #undef GetWindowLongPtrW
3457 #endif
3459 #ifdef GetWindowLongPtrA
3460 #undef GetWindowLongPtrA
3461 #endif
3463 #ifdef SetWindowLongPtrW
3464 #undef SetWindowLongPtrW
3465 #endif
3467 #ifdef SetWindowLongPtrA
3468 #undef SetWindowLongPtrA
3469 #endif
3471 /*****************************************************************************
3472 * GetWindowLongPtrW (USER32.@)
3474 LONG_PTR WINAPI GetWindowLongPtrW( HWND hwnd, INT offset )
3476 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), TRUE );
3479 /*****************************************************************************
3480 * GetWindowLongPtrA (USER32.@)
3482 LONG_PTR WINAPI GetWindowLongPtrA( HWND hwnd, INT offset )
3484 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), FALSE );
3487 /*****************************************************************************
3488 * SetWindowLongPtrW (USER32.@)
3490 LONG_PTR WINAPI SetWindowLongPtrW( HWND hwnd, INT offset, LONG_PTR newval )
3492 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, TRUE );
3495 /*****************************************************************************
3496 * SetWindowLongPtrA (USER32.@)
3498 LONG_PTR WINAPI SetWindowLongPtrA( HWND hwnd, INT offset, LONG_PTR newval )
3500 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, FALSE );