push 681ffee5c74d7631ae5db7640b788e4f44d87491
[wine/hacks.git] / dlls / user32 / win.c
blob2fc00c4b7c121c01204252f0bb0d3bb1e945a8b3
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 )) ||
1235 wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
1236 if (!(wndPtr->flags & WIN_NEED_SIZE))
1238 rect = wndPtr->rectClient;
1239 WIN_ReleasePtr( wndPtr );
1240 SendMessageW( hwnd, WM_SIZE, SIZE_RESTORED,
1241 MAKELONG(rect.right-rect.left, rect.bottom-rect.top));
1242 SendMessageW( hwnd, WM_MOVE, 0, MAKELONG( rect.left, rect.top ) );
1244 else WIN_ReleasePtr( wndPtr );
1246 /* Show the window, maximizing or minimizing if needed */
1248 style = WIN_SetStyle( hwnd, 0, WS_MAXIMIZE | WS_MINIMIZE );
1249 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
1251 RECT newPos;
1252 UINT swFlag = (style & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;
1254 swFlag = WINPOS_MinMaximize( hwnd, swFlag, &newPos );
1255 swFlag |= SWP_FRAMECHANGED; /* Frame always gets changed */
1256 if (!(style & WS_VISIBLE) || (style & WS_CHILD) || GetActiveWindow()) swFlag |= SWP_NOACTIVATE;
1257 SetWindowPos( hwnd, 0, newPos.left, newPos.top, newPos.right - newPos.left,
1258 newPos.bottom - newPos.top, swFlag );
1261 /* Notify the parent window only */
1263 send_parent_notify( hwnd, WM_CREATE );
1264 if (!IsWindow( hwnd )) return 0;
1266 if (cs->style & WS_VISIBLE)
1268 if (cs->style & WS_MAXIMIZE)
1269 sw = SW_SHOW;
1270 else if (cs->style & WS_MINIMIZE)
1271 sw = SW_SHOWMINIMIZED;
1273 ShowWindow( hwnd, sw );
1274 if (cs->dwExStyle & WS_EX_MDICHILD)
1276 SendMessageW(cs->hwndParent, WM_MDIREFRESHMENU, 0, 0);
1277 /* ShowWindow won't activate child windows */
1278 SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE );
1282 /* Call WH_SHELL hook */
1284 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1285 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0, TRUE );
1287 TRACE("created window %p\n", hwnd);
1288 return hwnd;
1290 failed:
1291 WIN_DestroyWindow( hwnd );
1292 return 0;
1296 /***********************************************************************
1297 * CreateWindow (USER.41)
1299 HWND16 WINAPI CreateWindow16( LPCSTR className, LPCSTR windowName,
1300 DWORD style, INT16 x, INT16 y, INT16 width,
1301 INT16 height, HWND16 parent, HMENU16 menu,
1302 HINSTANCE16 instance, LPVOID data )
1304 return CreateWindowEx16( 0, className, windowName, style,
1305 x, y, width, height, parent, menu, instance, data );
1309 /***********************************************************************
1310 * CreateWindowEx (USER.452)
1312 HWND16 WINAPI CreateWindowEx16( DWORD exStyle, LPCSTR className,
1313 LPCSTR windowName, DWORD style, INT16 x,
1314 INT16 y, INT16 width, INT16 height,
1315 HWND16 parent, HMENU16 menu,
1316 HINSTANCE16 instance, LPVOID data )
1318 CREATESTRUCTA cs;
1319 char buffer[256];
1321 /* Fix the coordinates */
1323 cs.x = (x == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)x;
1324 cs.y = (y == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)y;
1325 cs.cx = (width == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)width;
1326 cs.cy = (height == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)height;
1328 /* Create the window */
1330 cs.lpCreateParams = data;
1331 cs.hInstance = HINSTANCE_32(instance);
1332 cs.hMenu = HMENU_32(menu);
1333 cs.hwndParent = WIN_Handle32( parent );
1334 cs.style = style;
1335 cs.lpszName = windowName;
1336 cs.lpszClass = className;
1337 cs.dwExStyle = exStyle;
1339 if (!IS_INTRESOURCE(className))
1341 WCHAR bufferW[256];
1343 if (!MultiByteToWideChar( CP_ACP, 0, className, -1, bufferW, sizeof(bufferW)/sizeof(WCHAR) ))
1344 return 0;
1345 return HWND_16( WIN_CreateWindowEx( &cs, bufferW, 0 ));
1347 else
1349 if (!GlobalGetAtomNameA( LOWORD(className), buffer, sizeof(buffer) ))
1351 ERR( "bad atom %x\n", LOWORD(className));
1352 return 0;
1354 cs.lpszClass = buffer;
1355 return HWND_16( WIN_CreateWindowEx( &cs, (LPCWSTR)className, 0 ));
1360 /***********************************************************************
1361 * CreateWindowExA (USER32.@)
1363 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1364 LPCSTR windowName, DWORD style, INT x,
1365 INT y, INT width, INT height,
1366 HWND parent, HMENU menu,
1367 HINSTANCE instance, LPVOID data )
1369 CREATESTRUCTA cs;
1371 cs.lpCreateParams = data;
1372 cs.hInstance = instance;
1373 cs.hMenu = menu;
1374 cs.hwndParent = parent;
1375 cs.x = x;
1376 cs.y = y;
1377 cs.cx = width;
1378 cs.cy = height;
1379 cs.style = style;
1380 cs.lpszName = windowName;
1381 cs.lpszClass = className;
1382 cs.dwExStyle = exStyle;
1384 if (!IS_INTRESOURCE(className))
1386 WCHAR bufferW[256];
1387 if (!MultiByteToWideChar( CP_ACP, 0, className, -1, bufferW, sizeof(bufferW)/sizeof(WCHAR) ))
1388 return 0;
1389 return WIN_CreateWindowEx( &cs, bufferW, WIN_ISWIN32 );
1391 return WIN_CreateWindowEx( &cs, (LPCWSTR)className, WIN_ISWIN32 );
1395 /***********************************************************************
1396 * CreateWindowExW (USER32.@)
1398 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1399 LPCWSTR windowName, DWORD style, INT x,
1400 INT y, INT width, INT height,
1401 HWND parent, HMENU menu,
1402 HINSTANCE instance, LPVOID data )
1404 CREATESTRUCTW cs;
1406 cs.lpCreateParams = data;
1407 cs.hInstance = instance;
1408 cs.hMenu = menu;
1409 cs.hwndParent = parent;
1410 cs.x = x;
1411 cs.y = y;
1412 cs.cx = width;
1413 cs.cy = height;
1414 cs.style = style;
1415 cs.lpszName = windowName;
1416 cs.lpszClass = className;
1417 cs.dwExStyle = exStyle;
1419 /* Note: we rely on the fact that CREATESTRUCTA and */
1420 /* CREATESTRUCTW have the same layout. */
1421 return WIN_CreateWindowEx( (CREATESTRUCTA *)&cs, className, WIN_ISWIN32 | WIN_ISUNICODE );
1425 /***********************************************************************
1426 * WIN_SendDestroyMsg
1428 static void WIN_SendDestroyMsg( HWND hwnd )
1430 GUITHREADINFO info;
1432 if (GetGUIThreadInfo( GetCurrentThreadId(), &info ))
1434 if (hwnd == info.hwndCaret) DestroyCaret();
1435 if (hwnd == info.hwndActive) WINPOS_ActivateOtherWindow( hwnd );
1439 * Send the WM_DESTROY to the window.
1441 SendMessageW( hwnd, WM_DESTROY, 0, 0);
1444 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1445 * make sure that the window still exists when we come back.
1447 if (IsWindow(hwnd))
1449 HWND* pWndArray;
1450 int i;
1452 if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1454 for (i = 0; pWndArray[i]; i++)
1456 if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1458 HeapFree( GetProcessHeap(), 0, pWndArray );
1460 else
1461 WARN("\tdestroyed itself while in WM_DESTROY!\n");
1465 /***********************************************************************
1466 * DestroyWindow (USER32.@)
1468 BOOL WINAPI DestroyWindow( HWND hwnd )
1470 BOOL is_child;
1472 if (!(hwnd = WIN_IsCurrentThread( hwnd )) || is_desktop_window( hwnd ))
1474 SetLastError( ERROR_ACCESS_DENIED );
1475 return FALSE;
1478 TRACE("(%p)\n", hwnd);
1480 /* Call hooks */
1482 if (HOOK_CallHooks( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0, TRUE )) return FALSE;
1484 if (MENU_IsMenuActive() == hwnd)
1485 EndMenu();
1487 is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;
1489 if (is_child)
1491 if (!USER_IsExitingThread( GetCurrentThreadId() ))
1492 send_parent_notify( hwnd, WM_DESTROY );
1494 else if (!GetWindow( hwnd, GW_OWNER ))
1496 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
1497 /* FIXME: clean up palette - see "Internals" p.352 */
1500 if (!IsWindow(hwnd)) return TRUE;
1502 /* Hide the window */
1503 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)
1505 /* Only child windows receive WM_SHOWWINDOW in DestroyWindow() */
1506 if (is_child)
1507 ShowWindow( hwnd, SW_HIDE );
1508 else
1509 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE |
1510 SWP_NOZORDER | SWP_NOACTIVATE | SWP_HIDEWINDOW );
1513 if (!IsWindow(hwnd)) return TRUE;
1515 /* Recursively destroy owned windows */
1517 if (!is_child)
1519 for (;;)
1521 int i, got_one = 0;
1522 HWND *list = WIN_ListChildren( GetDesktopWindow() );
1523 if (list)
1525 for (i = 0; list[i]; i++)
1527 if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1528 if (WIN_IsCurrentThread( list[i] ))
1530 DestroyWindow( list[i] );
1531 got_one = 1;
1532 continue;
1534 WIN_SetOwner( list[i], 0 );
1536 HeapFree( GetProcessHeap(), 0, list );
1538 if (!got_one) break;
1542 /* Send destroy messages */
1544 WIN_SendDestroyMsg( hwnd );
1545 if (!IsWindow( hwnd )) return TRUE;
1547 if (GetClipboardOwner() == hwnd)
1548 CLIPBOARD_ReleaseOwner();
1550 /* Destroy the window storage */
1552 WIN_DestroyWindow( hwnd );
1553 return TRUE;
1557 /***********************************************************************
1558 * CloseWindow (USER32.@)
1560 BOOL WINAPI CloseWindow( HWND hwnd )
1562 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1563 ShowWindow( hwnd, SW_MINIMIZE );
1564 return TRUE;
1568 /***********************************************************************
1569 * OpenIcon (USER32.@)
1571 BOOL WINAPI OpenIcon( HWND hwnd )
1573 if (!IsIconic( hwnd )) return FALSE;
1574 ShowWindow( hwnd, SW_SHOWNORMAL );
1575 return TRUE;
1579 /***********************************************************************
1580 * FindWindowExW (USER32.@)
1582 HWND WINAPI FindWindowExW( HWND parent, HWND child, LPCWSTR className, LPCWSTR title )
1584 HWND *list = NULL;
1585 HWND retvalue = 0;
1586 int i = 0, len = 0;
1587 WCHAR *buffer = NULL;
1589 if (!parent && child) parent = GetDesktopWindow();
1590 else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
1592 if (title)
1594 len = strlenW(title) + 1; /* one extra char to check for chars beyond the end */
1595 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1598 if (!(list = list_window_children( 0, parent, className, 0 ))) goto done;
1600 if (child)
1602 child = WIN_GetFullHandle( child );
1603 while (list[i] && list[i] != child) i++;
1604 if (!list[i]) goto done;
1605 i++; /* start from next window */
1608 if (title)
1610 while (list[i])
1612 if (GetWindowTextW( list[i], buffer, len + 1 ) && !strcmpiW( buffer, title )) break;
1613 i++;
1616 retvalue = list[i];
1618 done:
1619 HeapFree( GetProcessHeap(), 0, list );
1620 HeapFree( GetProcessHeap(), 0, buffer );
1621 return retvalue;
1626 /***********************************************************************
1627 * FindWindowA (USER32.@)
1629 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1631 HWND ret = FindWindowExA( 0, 0, className, title );
1632 if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1633 return ret;
1637 /***********************************************************************
1638 * FindWindowExA (USER32.@)
1640 HWND WINAPI FindWindowExA( HWND parent, HWND child, LPCSTR className, LPCSTR title )
1642 LPWSTR titleW = NULL;
1643 HWND hwnd = 0;
1645 if (title)
1647 DWORD len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
1648 if (!(titleW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
1649 MultiByteToWideChar( CP_ACP, 0, title, -1, titleW, len );
1652 if (!IS_INTRESOURCE(className))
1654 WCHAR classW[256];
1655 if (MultiByteToWideChar( CP_ACP, 0, className, -1, classW, sizeof(classW)/sizeof(WCHAR) ))
1656 hwnd = FindWindowExW( parent, child, classW, titleW );
1658 else
1660 hwnd = FindWindowExW( parent, child, (LPCWSTR)className, titleW );
1663 HeapFree( GetProcessHeap(), 0, titleW );
1664 return hwnd;
1668 /***********************************************************************
1669 * FindWindowW (USER32.@)
1671 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
1673 return FindWindowExW( 0, 0, className, title );
1677 /**********************************************************************
1678 * GetDesktopWindow (USER32.@)
1680 HWND WINAPI GetDesktopWindow(void)
1682 struct user_thread_info *thread_info = get_user_thread_info();
1684 if (thread_info->top_window) return thread_info->top_window;
1686 SERVER_START_REQ( get_desktop_window )
1688 req->force = 0;
1689 if (!wine_server_call( req ))
1691 thread_info->top_window = reply->top_window;
1692 thread_info->msg_window = reply->msg_window;
1695 SERVER_END_REQ;
1697 if (!thread_info->top_window)
1699 USEROBJECTFLAGS flags;
1700 if (!GetUserObjectInformationW( GetProcessWindowStation(), UOI_FLAGS, &flags,
1701 sizeof(flags), NULL ) || (flags.dwFlags & WSF_VISIBLE))
1703 static const WCHAR command_line[] = {'\\','e','x','p','l','o','r','e','r','.','e','x','e',' ','/','d','e','s','k','t','o','p',0};
1704 STARTUPINFOW si;
1705 PROCESS_INFORMATION pi;
1706 WCHAR cmdline[MAX_PATH + sizeof(command_line)/sizeof(WCHAR)];
1708 memset( &si, 0, sizeof(si) );
1709 si.cb = sizeof(si);
1710 si.dwFlags = STARTF_USESTDHANDLES;
1711 si.hStdInput = 0;
1712 si.hStdOutput = 0;
1713 si.hStdError = GetStdHandle( STD_ERROR_HANDLE );
1715 GetSystemDirectoryW( cmdline, MAX_PATH );
1716 lstrcatW( cmdline, command_line );
1717 if (CreateProcessW( NULL, cmdline, NULL, NULL, FALSE, DETACHED_PROCESS,
1718 NULL, NULL, &si, &pi ))
1720 TRACE( "started explorer pid %04x tid %04x\n", pi.dwProcessId, pi.dwThreadId );
1721 WaitForInputIdle( pi.hProcess, 10000 );
1722 CloseHandle( pi.hThread );
1723 CloseHandle( pi.hProcess );
1725 else WARN( "failed to start explorer, err %d\n", GetLastError() );
1727 else TRACE( "not starting explorer since winstation is not visible\n" );
1729 SERVER_START_REQ( get_desktop_window )
1731 req->force = 1;
1732 if (!wine_server_call( req ))
1734 thread_info->top_window = reply->top_window;
1735 thread_info->msg_window = reply->msg_window;
1738 SERVER_END_REQ;
1741 if (!thread_info->top_window || !USER_Driver->pCreateDesktopWindow( thread_info->top_window ))
1742 ERR( "failed to create desktop window\n" );
1744 return thread_info->top_window;
1748 /*******************************************************************
1749 * EnableWindow (USER32.@)
1751 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
1753 BOOL retvalue;
1754 HWND full_handle;
1756 if (is_broadcast(hwnd))
1758 SetLastError( ERROR_INVALID_PARAMETER );
1759 return FALSE;
1762 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
1763 return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
1765 hwnd = full_handle;
1767 TRACE("( %p, %d )\n", hwnd, enable);
1769 retvalue = !IsWindowEnabled( hwnd );
1771 if (enable && retvalue)
1773 WIN_SetStyle( hwnd, 0, WS_DISABLED );
1774 SendMessageW( hwnd, WM_ENABLE, TRUE, 0 );
1776 else if (!enable && !retvalue)
1778 HWND capture_wnd;
1780 SendMessageW( hwnd, WM_CANCELMODE, 0, 0);
1782 WIN_SetStyle( hwnd, WS_DISABLED, 0 );
1784 if (hwnd == GetFocus())
1785 SetFocus( 0 ); /* A disabled window can't have the focus */
1787 capture_wnd = GetCapture();
1788 if (hwnd == capture_wnd || IsChild(hwnd, capture_wnd))
1789 ReleaseCapture(); /* A disabled window can't capture the mouse */
1791 SendMessageW( hwnd, WM_ENABLE, FALSE, 0 );
1793 return retvalue;
1797 /***********************************************************************
1798 * IsWindowEnabled (USER32.@)
1800 BOOL WINAPI IsWindowEnabled(HWND hWnd)
1802 return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
1806 /***********************************************************************
1807 * IsWindowUnicode (USER32.@)
1809 BOOL WINAPI IsWindowUnicode( HWND hwnd )
1811 WND * wndPtr;
1812 BOOL retvalue = FALSE;
1814 if (!(wndPtr = WIN_GetPtr(hwnd))) return FALSE;
1816 if (wndPtr == WND_DESKTOP) return TRUE;
1818 if (wndPtr != WND_OTHER_PROCESS)
1820 retvalue = (wndPtr->flags & WIN_ISUNICODE) != 0;
1821 WIN_ReleasePtr( wndPtr );
1823 else
1825 SERVER_START_REQ( get_window_info )
1827 req->handle = hwnd;
1828 if (!wine_server_call_err( req )) retvalue = reply->is_unicode;
1830 SERVER_END_REQ;
1832 return retvalue;
1836 /**********************************************************************
1837 * WIN_GetWindowLong
1839 * Helper function for GetWindowLong().
1841 static LONG_PTR WIN_GetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicode )
1843 LONG_PTR retvalue = 0;
1844 WND *wndPtr;
1846 if (offset == GWLP_HWNDPARENT)
1848 HWND parent = GetAncestor( hwnd, GA_PARENT );
1849 if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
1850 return (ULONG_PTR)parent;
1853 if (!(wndPtr = WIN_GetPtr( hwnd )))
1855 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1856 return 0;
1859 if (wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP)
1861 if (offset == GWLP_WNDPROC)
1863 SetLastError( ERROR_ACCESS_DENIED );
1864 return 0;
1866 SERVER_START_REQ( set_window_info )
1868 req->handle = hwnd;
1869 req->flags = 0; /* don't set anything, just retrieve */
1870 req->extra_offset = (offset >= 0) ? offset : -1;
1871 req->extra_size = (offset >= 0) ? size : 0;
1872 if (!wine_server_call_err( req ))
1874 switch(offset)
1876 case GWL_STYLE: retvalue = reply->old_style; break;
1877 case GWL_EXSTYLE: retvalue = reply->old_ex_style; break;
1878 case GWLP_ID: retvalue = reply->old_id; break;
1879 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)reply->old_instance; break;
1880 case GWLP_USERDATA: retvalue = reply->old_user_data; break;
1881 default:
1882 if (offset >= 0) retvalue = get_win_data( &reply->old_extra_value, size );
1883 else SetLastError( ERROR_INVALID_INDEX );
1884 break;
1888 SERVER_END_REQ;
1889 return retvalue;
1892 /* now we have a valid wndPtr */
1894 if (offset >= 0)
1896 if (offset > (int)(wndPtr->cbWndExtra - size))
1898 WARN("Invalid offset %d\n", offset );
1899 WIN_ReleasePtr( wndPtr );
1900 SetLastError( ERROR_INVALID_INDEX );
1901 return 0;
1903 retvalue = get_win_data( (char *)wndPtr->wExtra + offset, size );
1905 /* Special case for dialog window procedure */
1906 if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && (wndPtr->flags & WIN_ISDIALOG))
1907 retvalue = (LONG_PTR)WINPROC_GetProc( (WNDPROC)retvalue, unicode );
1908 WIN_ReleasePtr( wndPtr );
1909 return retvalue;
1912 switch(offset)
1914 case GWLP_USERDATA: retvalue = wndPtr->userdata; break;
1915 case GWL_STYLE: retvalue = wndPtr->dwStyle; break;
1916 case GWL_EXSTYLE: retvalue = wndPtr->dwExStyle; break;
1917 case GWLP_ID: retvalue = wndPtr->wIDmenu; break;
1918 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hInstance; break;
1919 case GWLP_WNDPROC:
1920 /* This looks like a hack only for the edit control (see tests). This makes these controls
1921 * more tolerant to A/W mismatches. The lack of W->A->W conversion for such a mismatch suggests
1922 * that the hack is in GetWindowLongPtr[AW], not in winprocs.
1924 if (wndPtr->winproc == EDIT_winproc_handle && (!unicode != !(wndPtr->flags & WIN_ISUNICODE)))
1925 retvalue = (ULONG_PTR)wndPtr->winproc;
1926 else
1927 retvalue = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, unicode );
1928 break;
1929 default:
1930 WARN("Unknown offset %d\n", offset );
1931 SetLastError( ERROR_INVALID_INDEX );
1932 break;
1934 WIN_ReleasePtr(wndPtr);
1935 return retvalue;
1939 /**********************************************************************
1940 * WIN_SetWindowLong
1942 * Helper function for SetWindowLong().
1944 * 0 is the failure code. However, in the case of failure SetLastError
1945 * must be set to distinguish between a 0 return value and a failure.
1947 LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, UINT size, LONG_PTR newval, BOOL unicode )
1949 STYLESTRUCT style;
1950 BOOL ok;
1951 LONG_PTR retval = 0;
1952 WND *wndPtr;
1954 TRACE( "%p %d %lx %c\n", hwnd, offset, newval, unicode ? 'W' : 'A' );
1956 if (is_broadcast(hwnd))
1958 SetLastError( ERROR_INVALID_PARAMETER );
1959 return FALSE;
1962 if (!(wndPtr = WIN_GetPtr( hwnd )))
1964 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1965 return 0;
1967 if (wndPtr == WND_DESKTOP)
1969 /* can't change anything on the desktop window */
1970 SetLastError( ERROR_ACCESS_DENIED );
1971 return 0;
1973 if (wndPtr == WND_OTHER_PROCESS)
1975 if (offset == GWLP_WNDPROC)
1977 SetLastError( ERROR_ACCESS_DENIED );
1978 return 0;
1980 if (offset > 32767 || offset < -32767)
1982 SetLastError( ERROR_INVALID_INDEX );
1983 return 0;
1985 return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, MAKEWPARAM( offset, size ), newval );
1988 /* first some special cases */
1989 switch( offset )
1991 case GWL_STYLE:
1992 case GWL_EXSTYLE:
1993 style.styleOld =
1994 offset == GWL_STYLE ? wndPtr->dwStyle : wndPtr->dwExStyle;
1995 style.styleNew = newval;
1996 WIN_ReleasePtr( wndPtr );
1997 SendMessageW( hwnd, WM_STYLECHANGING, offset, (LPARAM)&style );
1998 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
1999 newval = style.styleNew;
2000 break;
2001 case GWLP_HWNDPARENT:
2002 if (wndPtr->parent == GetDesktopWindow())
2004 WIN_ReleasePtr( wndPtr );
2005 return (ULONG_PTR)WIN_SetOwner( hwnd, (HWND)newval );
2007 else
2009 WIN_ReleasePtr( wndPtr );
2010 return (ULONG_PTR)SetParent( hwnd, (HWND)newval );
2012 case GWLP_WNDPROC:
2014 WNDPROC proc;
2015 UINT old_flags = wndPtr->flags;
2016 retval = WIN_GetWindowLong( hwnd, offset, size, unicode );
2017 if (unicode) proc = WINPROC_AllocProc( NULL, (WNDPROC)newval );
2018 else proc = WINPROC_AllocProc( (WNDPROC)newval, NULL );
2019 if (proc) wndPtr->winproc = proc;
2020 if (WINPROC_IsUnicode( proc, unicode )) wndPtr->flags |= WIN_ISUNICODE;
2021 else wndPtr->flags &= ~WIN_ISUNICODE;
2022 if (!((old_flags ^ wndPtr->flags) & WIN_ISUNICODE))
2024 WIN_ReleasePtr( wndPtr );
2025 return retval;
2027 /* update is_unicode flag on the server side */
2028 break;
2030 case GWLP_ID:
2031 case GWLP_HINSTANCE:
2032 case GWLP_USERDATA:
2033 break;
2034 case DWLP_DLGPROC:
2035 if ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
2036 (size == sizeof(LONG_PTR)) && (wndPtr->flags & WIN_ISDIALOG))
2038 WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWLP_DLGPROC);
2039 retval = (ULONG_PTR)WINPROC_GetProc( *ptr, unicode );
2040 if (unicode) *ptr = WINPROC_AllocProc( NULL, (WNDPROC)newval );
2041 else *ptr = WINPROC_AllocProc( (WNDPROC)newval, NULL );
2042 WIN_ReleasePtr( wndPtr );
2043 return retval;
2045 /* fall through */
2046 default:
2047 if (offset < 0 || offset > (int)(wndPtr->cbWndExtra - size))
2049 WARN("Invalid offset %d\n", offset );
2050 WIN_ReleasePtr( wndPtr );
2051 SetLastError( ERROR_INVALID_INDEX );
2052 return 0;
2054 else if (get_win_data( (char *)wndPtr->wExtra + offset, size ) == newval)
2056 /* already set to the same value */
2057 WIN_ReleasePtr( wndPtr );
2058 return newval;
2060 break;
2063 SERVER_START_REQ( set_window_info )
2065 req->handle = hwnd;
2066 req->extra_offset = -1;
2067 switch(offset)
2069 case GWL_STYLE:
2070 req->flags = SET_WIN_STYLE;
2071 req->style = newval;
2072 break;
2073 case GWL_EXSTYLE:
2074 req->flags = SET_WIN_EXSTYLE;
2075 /* WS_EX_TOPMOST can only be changed through SetWindowPos */
2076 newval = (newval & ~WS_EX_TOPMOST) | (wndPtr->dwExStyle & WS_EX_TOPMOST);
2077 req->ex_style = newval;
2078 break;
2079 case GWLP_ID:
2080 req->flags = SET_WIN_ID;
2081 req->id = newval;
2082 break;
2083 case GWLP_HINSTANCE:
2084 req->flags = SET_WIN_INSTANCE;
2085 req->instance = (void *)newval;
2086 break;
2087 case GWLP_WNDPROC:
2088 req->flags = SET_WIN_UNICODE;
2089 req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
2090 break;
2091 case GWLP_USERDATA:
2092 req->flags = SET_WIN_USERDATA;
2093 req->user_data = newval;
2094 break;
2095 default:
2096 req->flags = SET_WIN_EXTRA;
2097 req->extra_offset = offset;
2098 req->extra_size = size;
2099 set_win_data( &req->extra_value, newval, size );
2101 if ((ok = !wine_server_call_err( req )))
2103 switch(offset)
2105 case GWL_STYLE:
2106 wndPtr->dwStyle = newval;
2107 retval = reply->old_style;
2108 break;
2109 case GWL_EXSTYLE:
2110 wndPtr->dwExStyle = newval;
2111 retval = reply->old_ex_style;
2112 break;
2113 case GWLP_ID:
2114 wndPtr->wIDmenu = newval;
2115 retval = reply->old_id;
2116 break;
2117 case GWLP_HINSTANCE:
2118 wndPtr->hInstance = (HINSTANCE)newval;
2119 retval = (ULONG_PTR)reply->old_instance;
2120 break;
2121 case GWLP_WNDPROC:
2122 break;
2123 case GWLP_USERDATA:
2124 wndPtr->userdata = newval;
2125 retval = reply->old_user_data;
2126 break;
2127 default:
2128 retval = get_win_data( (char *)wndPtr->wExtra + offset, size );
2129 set_win_data( (char *)wndPtr->wExtra + offset, newval, size );
2130 break;
2134 SERVER_END_REQ;
2135 WIN_ReleasePtr( wndPtr );
2137 if (!ok) return 0;
2139 if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2141 USER_Driver->pSetWindowStyle( hwnd, offset, &style );
2142 SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2145 return retval;
2149 /**********************************************************************
2150 * GetWindowLong (USER.135)
2152 LONG WINAPI GetWindowLong16( HWND16 hwnd, INT16 offset )
2154 WND *wndPtr;
2155 LONG_PTR retvalue;
2156 BOOL is_winproc = (offset == GWLP_WNDPROC);
2158 if (offset >= 0)
2160 if (!(wndPtr = WIN_GetPtr( WIN_Handle32(hwnd) )))
2162 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2163 return 0;
2165 if (wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
2167 if (offset > (int)(wndPtr->cbWndExtra - sizeof(LONG)))
2170 * Some programs try to access last element from 16 bit
2171 * code using illegal offset value. Hopefully this is
2172 * what those programs really expect.
2174 if (wndPtr->cbWndExtra >= 4 && offset == wndPtr->cbWndExtra - sizeof(WORD))
2176 INT offset2 = wndPtr->cbWndExtra - sizeof(LONG);
2177 ERR( "- replaced invalid offset %d with %d\n", offset, offset2 );
2178 offset = offset2;
2180 else
2182 WARN("Invalid offset %d\n", offset );
2183 WIN_ReleasePtr( wndPtr );
2184 SetLastError( ERROR_INVALID_INDEX );
2185 return 0;
2188 is_winproc = ((offset == DWLP_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG));
2189 WIN_ReleasePtr( wndPtr );
2192 retvalue = GetWindowLongA( WIN_Handle32(hwnd), offset );
2193 if (is_winproc) retvalue = (LONG_PTR)WINPROC_GetProc16( (WNDPROC)retvalue, FALSE );
2194 return retvalue;
2198 /**********************************************************************
2199 * GetWindowWord (USER32.@)
2201 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
2203 switch(offset)
2205 case GWLP_ID:
2206 case GWLP_HINSTANCE:
2207 case GWLP_HWNDPARENT:
2208 break;
2209 default:
2210 if (offset < 0)
2212 WARN("Invalid offset %d\n", offset );
2213 SetLastError( ERROR_INVALID_INDEX );
2214 return 0;
2216 break;
2218 return WIN_GetWindowLong( hwnd, offset, sizeof(WORD), FALSE );
2222 /**********************************************************************
2223 * GetWindowLongA (USER32.@)
2225 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2227 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), FALSE );
2231 /**********************************************************************
2232 * GetWindowLongW (USER32.@)
2234 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2236 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), TRUE );
2240 /**********************************************************************
2241 * SetWindowLong (USER.136)
2243 LONG WINAPI SetWindowLong16( HWND16 hwnd, INT16 offset, LONG newval )
2245 WND *wndPtr;
2246 BOOL is_winproc = (offset == GWLP_WNDPROC);
2248 if (offset == DWLP_DLGPROC)
2250 if (!(wndPtr = WIN_GetPtr( WIN_Handle32(hwnd) )))
2252 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2253 return 0;
2255 if (wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
2257 is_winproc = ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
2258 (wndPtr->flags & WIN_ISDIALOG));
2259 WIN_ReleasePtr( wndPtr );
2263 if (is_winproc)
2265 WNDPROC new_proc = WINPROC_AllocProc16( (WNDPROC16)newval );
2266 WNDPROC old_proc = (WNDPROC)SetWindowLongPtrA( WIN_Handle32(hwnd), offset, (LONG_PTR)new_proc );
2267 return (LONG)WINPROC_GetProc16( old_proc, FALSE );
2269 else return SetWindowLongA( WIN_Handle32(hwnd), offset, newval );
2273 /**********************************************************************
2274 * SetWindowWord (USER32.@)
2276 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
2278 switch(offset)
2280 case GWLP_ID:
2281 case GWLP_HINSTANCE:
2282 case GWLP_HWNDPARENT:
2283 break;
2284 default:
2285 if (offset < 0)
2287 WARN("Invalid offset %d\n", offset );
2288 SetLastError( ERROR_INVALID_INDEX );
2289 return 0;
2291 break;
2293 return WIN_SetWindowLong( hwnd, offset, sizeof(WORD), newval, FALSE );
2297 /**********************************************************************
2298 * SetWindowLongA (USER32.@)
2300 * See SetWindowLongW.
2302 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2304 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, FALSE );
2308 /**********************************************************************
2309 * SetWindowLongW (USER32.@) Set window attribute
2311 * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2312 * value in a window's extra memory.
2314 * The _hwnd_ parameter specifies the window. is the handle to a
2315 * window that has extra memory. The _newval_ parameter contains the
2316 * new attribute or extra memory value. If positive, the _offset_
2317 * parameter is the byte-addressed location in the window's extra
2318 * memory to set. If negative, _offset_ specifies the window
2319 * attribute to set, and should be one of the following values:
2321 * GWL_EXSTYLE The window's extended window style
2323 * GWL_STYLE The window's window style.
2325 * GWLP_WNDPROC Pointer to the window's window procedure.
2327 * GWLP_HINSTANCE The window's pplication instance handle.
2329 * GWLP_ID The window's identifier.
2331 * GWLP_USERDATA The window's user-specified data.
2333 * If the window is a dialog box, the _offset_ parameter can be one of
2334 * the following values:
2336 * DWLP_DLGPROC The address of the window's dialog box procedure.
2338 * DWLP_MSGRESULT The return value of a message
2339 * that the dialog box procedure processed.
2341 * DWLP_USER Application specific information.
2343 * RETURNS
2345 * If successful, returns the previous value located at _offset_. Otherwise,
2346 * returns 0.
2348 * NOTES
2350 * Extra memory for a window class is specified by a nonzero cbWndExtra
2351 * parameter of the WNDCLASS structure passed to RegisterClass() at the
2352 * time of class creation.
2354 * Using GWL_WNDPROC to set a new window procedure effectively creates
2355 * a window subclass. Use CallWindowProc() in the new windows procedure
2356 * to pass messages to the superclass's window procedure.
2358 * The user data is reserved for use by the application which created
2359 * the window.
2361 * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2362 * instead, call the EnableWindow() function to change the window's
2363 * disabled state.
2365 * Do not use GWL_HWNDPARENT to reset the window's parent, use
2366 * SetParent() instead.
2368 * Win95:
2369 * When offset is GWL_STYLE and the calling app's ver is 4.0,
2370 * it sends WM_STYLECHANGING before changing the settings
2371 * and WM_STYLECHANGED afterwards.
2372 * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2374 LONG WINAPI SetWindowLongW(
2375 HWND hwnd, /* [in] window to alter */
2376 INT offset, /* [in] offset, in bytes, of location to alter */
2377 LONG newval /* [in] new value of location */
2379 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, TRUE );
2383 /*******************************************************************
2384 * GetWindowTextA (USER32.@)
2386 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2388 WCHAR *buffer;
2390 if (!lpString) return 0;
2392 if (WIN_IsCurrentProcess( hwnd ))
2393 return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2395 /* when window belongs to other process, don't send a message */
2396 if (nMaxCount <= 0) return 0;
2397 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2398 get_server_window_text( hwnd, buffer, nMaxCount );
2399 if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2400 lpString[nMaxCount-1] = 0;
2401 HeapFree( GetProcessHeap(), 0, buffer );
2402 return strlen(lpString);
2406 /*******************************************************************
2407 * InternalGetWindowText (USER32.@)
2409 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2411 WND *win;
2413 if (nMaxCount <= 0) return 0;
2414 if (!(win = WIN_GetPtr( hwnd ))) return 0;
2415 if (win == WND_DESKTOP) lpString[0] = 0;
2416 else if (win != WND_OTHER_PROCESS)
2418 if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2419 else lpString[0] = 0;
2420 WIN_ReleasePtr( win );
2422 else
2424 get_server_window_text( hwnd, lpString, nMaxCount );
2426 return strlenW(lpString);
2430 /*******************************************************************
2431 * GetWindowTextW (USER32.@)
2433 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2435 if (!lpString) return 0;
2437 if (WIN_IsCurrentProcess( hwnd ))
2438 return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2440 /* when window belongs to other process, don't send a message */
2441 if (nMaxCount <= 0) return 0;
2442 get_server_window_text( hwnd, lpString, nMaxCount );
2443 return strlenW(lpString);
2447 /*******************************************************************
2448 * SetWindowTextA (USER32.@)
2449 * SetWindowText (USER32.@)
2451 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2453 if (is_broadcast(hwnd))
2455 SetLastError( ERROR_INVALID_PARAMETER );
2456 return FALSE;
2458 if (!WIN_IsCurrentProcess( hwnd ))
2459 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2460 debugstr_a(lpString), hwnd );
2461 return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2465 /*******************************************************************
2466 * SetWindowTextW (USER32.@)
2468 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2470 if (is_broadcast(hwnd))
2472 SetLastError( ERROR_INVALID_PARAMETER );
2473 return FALSE;
2475 if (!WIN_IsCurrentProcess( hwnd ))
2476 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2477 debugstr_w(lpString), hwnd );
2478 return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2482 /*******************************************************************
2483 * GetWindowTextLengthA (USER32.@)
2485 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2487 return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2490 /*******************************************************************
2491 * GetWindowTextLengthW (USER32.@)
2493 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2495 return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2499 /*******************************************************************
2500 * IsWindow (USER32.@)
2502 BOOL WINAPI IsWindow( HWND hwnd )
2504 WND *ptr;
2505 BOOL ret;
2507 if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2508 if (ptr == WND_DESKTOP) return TRUE;
2510 if (ptr != WND_OTHER_PROCESS)
2512 WIN_ReleasePtr( ptr );
2513 return TRUE;
2516 /* check other processes */
2517 SERVER_START_REQ( get_window_info )
2519 req->handle = hwnd;
2520 ret = !wine_server_call_err( req );
2522 SERVER_END_REQ;
2523 return ret;
2527 /***********************************************************************
2528 * GetWindowThreadProcessId (USER32.@)
2530 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2532 WND *ptr;
2533 DWORD tid = 0;
2535 if (!(ptr = WIN_GetPtr( hwnd )))
2537 SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2538 return 0;
2541 if (ptr != WND_OTHER_PROCESS && ptr != WND_DESKTOP)
2543 /* got a valid window */
2544 tid = ptr->tid;
2545 if (process) *process = GetCurrentProcessId();
2546 WIN_ReleasePtr( ptr );
2547 return tid;
2550 /* check other processes */
2551 SERVER_START_REQ( get_window_info )
2553 req->handle = hwnd;
2554 if (!wine_server_call_err( req ))
2556 tid = (DWORD)reply->tid;
2557 if (process) *process = (DWORD)reply->pid;
2560 SERVER_END_REQ;
2561 return tid;
2565 /*****************************************************************
2566 * GetParent (USER32.@)
2568 HWND WINAPI GetParent( HWND hwnd )
2570 WND *wndPtr;
2571 HWND retvalue = 0;
2573 if (!(wndPtr = WIN_GetPtr( hwnd )))
2575 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2576 return 0;
2578 if (wndPtr == WND_DESKTOP) return 0;
2579 if (wndPtr == WND_OTHER_PROCESS)
2581 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2582 if (style & (WS_POPUP | WS_CHILD))
2584 SERVER_START_REQ( get_window_tree )
2586 req->handle = hwnd;
2587 if (!wine_server_call_err( req ))
2589 if (style & WS_POPUP) retvalue = reply->owner;
2590 else if (style & WS_CHILD) retvalue = reply->parent;
2593 SERVER_END_REQ;
2596 else
2598 if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2599 else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2600 WIN_ReleasePtr( wndPtr );
2602 return retvalue;
2606 /*****************************************************************
2607 * GetAncestor (USER32.@)
2609 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2611 WND *win;
2612 HWND *list, ret = 0;
2614 switch(type)
2616 case GA_PARENT:
2617 if (!(win = WIN_GetPtr( hwnd )))
2619 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2620 return 0;
2622 if (win == WND_DESKTOP) return 0;
2623 if (win != WND_OTHER_PROCESS)
2625 ret = win->parent;
2626 WIN_ReleasePtr( win );
2628 else /* need to query the server */
2630 SERVER_START_REQ( get_window_tree )
2632 req->handle = hwnd;
2633 if (!wine_server_call_err( req )) ret = reply->parent;
2635 SERVER_END_REQ;
2637 break;
2639 case GA_ROOT:
2640 if (!(list = list_window_parents( hwnd ))) return 0;
2642 if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd ); /* top-level window */
2643 else
2645 int count = 2;
2646 while (list[count]) count++;
2647 ret = list[count - 2]; /* get the one before the desktop */
2649 HeapFree( GetProcessHeap(), 0, list );
2650 break;
2652 case GA_ROOTOWNER:
2653 if (is_desktop_window( hwnd )) return 0;
2654 ret = WIN_GetFullHandle( hwnd );
2655 for (;;)
2657 HWND parent = GetParent( ret );
2658 if (!parent) break;
2659 ret = parent;
2661 break;
2663 return ret;
2667 /*****************************************************************
2668 * SetParent (USER32.@)
2670 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2672 HWND full_handle;
2673 HWND old_parent = 0;
2674 BOOL was_visible;
2675 WND *wndPtr;
2676 BOOL ret;
2678 if (is_broadcast(hwnd) || is_broadcast(parent))
2680 SetLastError(ERROR_INVALID_PARAMETER);
2681 return 0;
2684 if (!parent) parent = GetDesktopWindow();
2685 else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
2686 else parent = WIN_GetFullHandle( parent );
2688 if (!IsWindow( parent ))
2690 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2691 return 0;
2694 /* Some applications try to set a child as a parent */
2695 if (IsChild(hwnd, parent))
2697 SetLastError( ERROR_INVALID_PARAMETER );
2698 return 0;
2701 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2702 return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2704 /* Windows hides the window first, then shows it again
2705 * including the WM_SHOWWINDOW messages and all */
2706 was_visible = ShowWindow( hwnd, SW_HIDE );
2708 wndPtr = WIN_GetPtr( hwnd );
2709 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
2711 SERVER_START_REQ( set_parent )
2713 req->handle = hwnd;
2714 req->parent = parent;
2715 if ((ret = !wine_server_call( req )))
2717 old_parent = reply->old_parent;
2718 wndPtr->parent = parent = reply->full_parent;
2722 SERVER_END_REQ;
2723 WIN_ReleasePtr( wndPtr );
2724 if (!ret) return 0;
2726 USER_Driver->pSetParent( full_handle, parent, old_parent );
2728 /* SetParent additionally needs to make hwnd the topmost window
2729 in the x-order and send the expected WM_WINDOWPOSCHANGING and
2730 WM_WINDOWPOSCHANGED notification messages.
2732 SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0,
2733 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | (was_visible ? SWP_SHOWWINDOW : 0) );
2734 /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
2735 * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
2737 return old_parent;
2741 /*******************************************************************
2742 * IsChild (USER32.@)
2744 BOOL WINAPI IsChild( HWND parent, HWND child )
2746 HWND *list = list_window_parents( child );
2747 int i;
2748 BOOL ret;
2750 if (!list) return FALSE;
2751 parent = WIN_GetFullHandle( parent );
2752 for (i = 0; list[i]; i++) if (list[i] == parent) break;
2753 ret = list[i] && list[i+1];
2754 HeapFree( GetProcessHeap(), 0, list );
2755 return ret;
2759 /***********************************************************************
2760 * IsWindowVisible (USER32.@)
2762 BOOL WINAPI IsWindowVisible( HWND hwnd )
2764 HWND *list;
2765 BOOL retval = TRUE;
2766 int i;
2768 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2769 if (!(list = list_window_parents( hwnd ))) return TRUE;
2770 if (list[0])
2772 for (i = 0; list[i+1]; i++)
2773 if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2774 retval = !list[i+1] && (list[i] == GetDesktopWindow()); /* top message window isn't visible */
2776 HeapFree( GetProcessHeap(), 0, list );
2777 return retval;
2781 /***********************************************************************
2782 * WIN_IsWindowDrawable
2784 * hwnd is drawable when it is visible, all parents are not
2785 * minimized, and it is itself not minimized unless we are
2786 * trying to draw its default class icon.
2788 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2790 HWND *list;
2791 BOOL retval = TRUE;
2792 int i;
2793 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2795 if (!(style & WS_VISIBLE)) return FALSE;
2796 if ((style & WS_MINIMIZE) && icon && GetClassLongPtrW( hwnd, GCLP_HICON )) return FALSE;
2798 if (!(list = list_window_parents( hwnd ))) return TRUE;
2799 if (list[0])
2801 for (i = 0; list[i+1]; i++)
2802 if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2803 break;
2804 retval = !list[i+1] && (list[i] == GetDesktopWindow()); /* top message window isn't visible */
2806 HeapFree( GetProcessHeap(), 0, list );
2807 return retval;
2811 /*******************************************************************
2812 * GetTopWindow (USER32.@)
2814 HWND WINAPI GetTopWindow( HWND hwnd )
2816 if (!hwnd) hwnd = GetDesktopWindow();
2817 return GetWindow( hwnd, GW_CHILD );
2821 /*******************************************************************
2822 * GetWindow (USER32.@)
2824 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2826 HWND retval = 0;
2828 if (rel == GW_OWNER) /* this one may be available locally */
2830 WND *wndPtr = WIN_GetPtr( hwnd );
2831 if (!wndPtr)
2833 SetLastError( ERROR_INVALID_HANDLE );
2834 return 0;
2836 if (wndPtr == WND_DESKTOP) return 0;
2837 if (wndPtr != WND_OTHER_PROCESS)
2839 retval = wndPtr->owner;
2840 WIN_ReleasePtr( wndPtr );
2841 return retval;
2843 /* else fall through to server call */
2846 SERVER_START_REQ( get_window_tree )
2848 req->handle = hwnd;
2849 if (!wine_server_call_err( req ))
2851 switch(rel)
2853 case GW_HWNDFIRST:
2854 retval = reply->first_sibling;
2855 break;
2856 case GW_HWNDLAST:
2857 retval = reply->last_sibling;
2858 break;
2859 case GW_HWNDNEXT:
2860 retval = reply->next_sibling;
2861 break;
2862 case GW_HWNDPREV:
2863 retval = reply->prev_sibling;
2864 break;
2865 case GW_OWNER:
2866 retval = reply->owner;
2867 break;
2868 case GW_CHILD:
2869 retval = reply->first_child;
2870 break;
2874 SERVER_END_REQ;
2875 return retval;
2879 /*******************************************************************
2880 * ShowOwnedPopups (USER32.@)
2882 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2884 int count = 0;
2885 WND *pWnd;
2886 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2888 if (!win_array) return TRUE;
2890 while (win_array[count]) count++;
2891 while (--count >= 0)
2893 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2894 if (!(pWnd = WIN_GetPtr( win_array[count] ))) continue;
2895 if (pWnd == WND_OTHER_PROCESS) continue;
2896 if (fShow)
2898 if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2900 WIN_ReleasePtr( pWnd );
2901 /* In Windows, ShowOwnedPopups(TRUE) generates
2902 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
2903 * regardless of the state of the owner
2905 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
2906 continue;
2909 else
2911 if (pWnd->dwStyle & WS_VISIBLE)
2913 WIN_ReleasePtr( pWnd );
2914 /* In Windows, ShowOwnedPopups(FALSE) generates
2915 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
2916 * regardless of the state of the owner
2918 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
2919 continue;
2922 WIN_ReleasePtr( pWnd );
2924 HeapFree( GetProcessHeap(), 0, win_array );
2925 return TRUE;
2929 /*******************************************************************
2930 * GetLastActivePopup (USER32.@)
2932 HWND WINAPI GetLastActivePopup( HWND hwnd )
2934 HWND retval = hwnd;
2936 SERVER_START_REQ( get_window_info )
2938 req->handle = hwnd;
2939 if (!wine_server_call_err( req )) retval = reply->last_active;
2941 SERVER_END_REQ;
2942 return retval;
2946 /*******************************************************************
2947 * WIN_ListChildren
2949 * Build an array of the children of a given window. The array must be
2950 * freed with HeapFree. Returns NULL when no windows are found.
2952 HWND *WIN_ListChildren( HWND hwnd )
2954 if (!hwnd)
2956 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2957 return NULL;
2959 return list_window_children( 0, hwnd, NULL, 0 );
2963 /*******************************************************************
2964 * EnumWindows (USER32.@)
2966 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
2968 HWND *list;
2969 BOOL ret = TRUE;
2970 int i;
2972 USER_CheckNotLock();
2974 /* We have to build a list of all windows first, to avoid */
2975 /* unpleasant side-effects, for instance if the callback */
2976 /* function changes the Z-order of the windows. */
2978 if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
2980 /* Now call the callback function for every window */
2982 for (i = 0; list[i]; i++)
2984 /* Make sure that the window still exists */
2985 if (!IsWindow( list[i] )) continue;
2986 if (!(ret = lpEnumFunc( list[i], lParam ))) break;
2988 HeapFree( GetProcessHeap(), 0, list );
2989 return ret;
2993 /**********************************************************************
2994 * EnumThreadWindows (USER32.@)
2996 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
2998 HWND *list;
2999 int i;
3001 USER_CheckNotLock();
3003 if (!(list = list_window_children( 0, GetDesktopWindow(), NULL, id ))) return TRUE;
3005 /* Now call the callback function for every window */
3007 for (i = 0; list[i]; i++)
3008 if (!func( list[i], lParam )) break;
3009 HeapFree( GetProcessHeap(), 0, list );
3010 return TRUE;
3014 /***********************************************************************
3015 * EnumDesktopWindows (USER32.@)
3017 BOOL WINAPI EnumDesktopWindows( HDESK desktop, WNDENUMPROC func, LPARAM lparam )
3019 HWND *list;
3020 int i;
3022 USER_CheckNotLock();
3024 if (!(list = list_window_children( desktop, 0, NULL, 0 ))) return TRUE;
3026 for (i = 0; list[i]; i++)
3027 if (!func( list[i], lparam )) break;
3028 HeapFree( GetProcessHeap(), 0, list );
3029 return TRUE;
3033 /**********************************************************************
3034 * WIN_EnumChildWindows
3036 * Helper function for EnumChildWindows().
3038 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
3040 HWND *childList;
3041 BOOL ret = FALSE;
3043 for ( ; *list; list++)
3045 /* Make sure that the window still exists */
3046 if (!IsWindow( *list )) continue;
3047 /* Build children list first */
3048 childList = WIN_ListChildren( *list );
3050 ret = func( *list, lParam );
3052 if (childList)
3054 if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
3055 HeapFree( GetProcessHeap(), 0, childList );
3057 if (!ret) return FALSE;
3059 return TRUE;
3063 /**********************************************************************
3064 * EnumChildWindows (USER32.@)
3066 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
3068 HWND *list;
3069 BOOL ret;
3071 USER_CheckNotLock();
3073 if (!(list = WIN_ListChildren( parent ))) return FALSE;
3074 ret = WIN_EnumChildWindows( list, func, lParam );
3075 HeapFree( GetProcessHeap(), 0, list );
3076 return ret;
3080 /*******************************************************************
3081 * AnyPopup (USER.52)
3083 BOOL16 WINAPI AnyPopup16(void)
3085 return AnyPopup();
3089 /*******************************************************************
3090 * AnyPopup (USER32.@)
3092 BOOL WINAPI AnyPopup(void)
3094 int i;
3095 BOOL retvalue;
3096 HWND *list = WIN_ListChildren( GetDesktopWindow() );
3098 if (!list) return FALSE;
3099 for (i = 0; list[i]; i++)
3101 if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
3103 retvalue = (list[i] != 0);
3104 HeapFree( GetProcessHeap(), 0, list );
3105 return retvalue;
3109 /*******************************************************************
3110 * FlashWindow (USER32.@)
3112 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3114 WND *wndPtr;
3116 TRACE("%p\n", hWnd);
3118 if (IsIconic( hWnd ))
3120 RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
3122 wndPtr = WIN_GetPtr(hWnd);
3123 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3124 if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
3126 wndPtr->flags |= WIN_NCACTIVATED;
3128 else
3130 wndPtr->flags &= ~WIN_NCACTIVATED;
3132 WIN_ReleasePtr( wndPtr );
3133 return TRUE;
3135 else
3137 WPARAM wparam;
3139 wndPtr = WIN_GetPtr(hWnd);
3140 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3141 hWnd = wndPtr->hwndSelf; /* make it a full handle */
3143 if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3144 else wparam = (hWnd == GetForegroundWindow());
3146 WIN_ReleasePtr( wndPtr );
3147 SendMessageW( hWnd, WM_NCACTIVATE, wparam, 0 );
3148 return wparam;
3152 /*******************************************************************
3153 * FlashWindowEx (USER32.@)
3155 BOOL WINAPI FlashWindowEx( PFLASHWINFO pfwi )
3157 FIXME("%p\n", pfwi);
3158 return TRUE;
3161 /*******************************************************************
3162 * GetWindowContextHelpId (USER32.@)
3164 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3166 DWORD retval;
3167 WND *wnd = WIN_GetPtr( hwnd );
3168 if (!wnd || wnd == WND_DESKTOP) return 0;
3169 if (wnd == WND_OTHER_PROCESS)
3171 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3172 return 0;
3174 retval = wnd->helpContext;
3175 WIN_ReleasePtr( wnd );
3176 return retval;
3180 /*******************************************************************
3181 * SetWindowContextHelpId (USER32.@)
3183 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3185 WND *wnd = WIN_GetPtr( hwnd );
3186 if (!wnd || wnd == WND_DESKTOP) return FALSE;
3187 if (wnd == WND_OTHER_PROCESS)
3189 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3190 return 0;
3192 wnd->helpContext = id;
3193 WIN_ReleasePtr( wnd );
3194 return TRUE;
3198 /*******************************************************************
3199 * DragDetect (USER32.@)
3201 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3203 MSG msg;
3204 RECT rect;
3205 WORD wDragWidth = GetSystemMetrics(SM_CXDRAG);
3206 WORD wDragHeight= GetSystemMetrics(SM_CYDRAG);
3208 rect.left = pt.x - wDragWidth;
3209 rect.right = pt.x + wDragWidth;
3211 rect.top = pt.y - wDragHeight;
3212 rect.bottom = pt.y + wDragHeight;
3214 SetCapture(hWnd);
3216 while(1)
3218 while (PeekMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ))
3220 if( msg.message == WM_LBUTTONUP )
3222 ReleaseCapture();
3223 return 0;
3225 if( msg.message == WM_MOUSEMOVE )
3227 POINT tmp;
3228 tmp.x = (short)LOWORD(msg.lParam);
3229 tmp.y = (short)HIWORD(msg.lParam);
3230 if( !PtInRect( &rect, tmp ))
3232 ReleaseCapture();
3233 return 1;
3237 WaitMessage();
3239 return 0;
3242 /******************************************************************************
3243 * GetWindowModuleFileNameA (USER32.@)
3245 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR module, UINT size )
3247 WND *win;
3248 HINSTANCE hinst;
3250 TRACE( "%p, %p, %u\n", hwnd, module, size );
3252 win = WIN_GetPtr( hwnd );
3253 if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3255 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3256 return 0;
3258 hinst = win->hInstance;
3259 WIN_ReleasePtr( win );
3261 return GetModuleFileNameA( hinst, module, size );
3264 /******************************************************************************
3265 * GetWindowModuleFileNameW (USER32.@)
3267 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR module, UINT size )
3269 WND *win;
3270 HINSTANCE hinst;
3272 TRACE( "%p, %p, %u\n", hwnd, module, size );
3274 win = WIN_GetPtr( hwnd );
3275 if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3277 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3278 return 0;
3280 hinst = win->hInstance;
3281 WIN_ReleasePtr( win );
3283 return GetModuleFileNameW( hinst, module, size );
3286 /******************************************************************************
3287 * GetWindowInfo (USER32.@)
3289 * Note: tests show that Windows doesn't check cbSize of the structure.
3291 BOOL WINAPI GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3293 if (!pwi) return FALSE;
3294 if (!IsWindow(hwnd)) return FALSE;
3296 GetWindowRect(hwnd, &pwi->rcWindow);
3297 GetClientRect(hwnd, &pwi->rcClient);
3298 /* translate to screen coordinates */
3299 MapWindowPoints(hwnd, 0, (LPPOINT)&pwi->rcClient, 2);
3301 pwi->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
3302 pwi->dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3303 pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3305 pwi->cxWindowBorders = pwi->rcClient.left - pwi->rcWindow.left;
3306 pwi->cyWindowBorders = pwi->rcWindow.bottom - pwi->rcClient.bottom;
3308 pwi->atomWindowType = GetClassLongW( hwnd, GCW_ATOM );
3309 pwi->wCreatorVersion = 0x0400;
3311 return TRUE;
3314 /******************************************************************************
3315 * SwitchDesktop (USER32.@)
3317 * NOTES: Sets the current input or interactive desktop.
3319 BOOL WINAPI SwitchDesktop( HDESK hDesktop)
3321 FIXME("SwitchDesktop(hwnd %p) stub!\n", hDesktop);
3322 return TRUE;
3325 /*****************************************************************************
3326 * SetLayeredWindowAttributes (USER32.@)
3328 BOOL WINAPI SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, DWORD flags )
3330 BOOL ret;
3332 TRACE("(%p,%08x,%d,%x): stub!\n", hwnd, key, alpha, flags);
3334 SERVER_START_REQ( set_window_layered_info )
3336 req->handle = hwnd;
3337 req->color_key = key;
3338 req->alpha = alpha;
3339 req->flags = flags;
3340 ret = !wine_server_call_err( req );
3342 SERVER_END_REQ;
3344 if (ret) USER_Driver->pSetLayeredWindowAttributes( hwnd, key, alpha, flags );
3346 return ret;
3350 /*****************************************************************************
3351 * GetLayeredWindowAttributes (USER32.@)
3353 BOOL WINAPI GetLayeredWindowAttributes( HWND hwnd, COLORREF *key, BYTE *alpha, DWORD *flags )
3355 BOOL ret;
3357 SERVER_START_REQ( get_window_layered_info )
3359 req->handle = hwnd;
3360 if ((ret = !wine_server_call_err( req )))
3362 if (key) *key = reply->color_key;
3363 if (alpha) *alpha = reply->alpha;
3364 if (flags) *flags = reply->flags;
3367 SERVER_END_REQ;
3369 return ret;
3373 /*****************************************************************************
3374 * UpdateLayeredWindowIndirect (USER32.@)
3376 BOOL WINAPI UpdateLayeredWindowIndirect( HWND hwnd, const UPDATELAYEREDWINDOWINFO *info )
3378 BYTE alpha = 0xff;
3380 if (!(info->dwFlags & ULW_EX_NORESIZE) && (info->pptDst || info->psize))
3382 int x = 0, y = 0, cx = 0, cy = 0;
3383 DWORD flags = SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOSENDCHANGING;
3385 if (info->pptDst)
3387 x = info->pptDst->x;
3388 y = info->pptDst->y;
3389 flags &= ~SWP_NOMOVE;
3391 if (info->psize)
3393 cx = info->psize->cx;
3394 cy = info->psize->cy;
3395 flags &= ~SWP_NOSIZE;
3397 TRACE( "moving window %p pos %d,%d %dx%x\n", hwnd, x, y, cx, cy );
3398 SetWindowPos( hwnd, 0, x, y, cx, cy, flags );
3401 if (info->hdcSrc)
3403 RECT rect;
3404 HDC hdc = GetDCEx( hwnd, 0, DCX_CACHE );
3406 if (hdc)
3408 int x = 0, y = 0;
3410 GetClientRect( hwnd, &rect );
3411 if (info->pptSrc)
3413 x = info->pptSrc->x;
3414 y = info->pptSrc->y;
3416 /* FIXME: intersect rect with info->prcDirty */
3417 TRACE( "copying window %p pos %d,%d\n", hwnd, x, y );
3418 BitBlt( hdc, rect.left, rect.top, rect.right, rect.bottom,
3419 info->hdcSrc, rect.left + x, rect.top + y, SRCCOPY );
3420 ReleaseDC( hwnd, hdc );
3424 if (info->pblend && !(info->dwFlags & ULW_OPAQUE)) alpha = info->pblend->SourceConstantAlpha;
3425 TRACE( "setting window %p alpha %u\n", hwnd, alpha );
3426 USER_Driver->pSetLayeredWindowAttributes( hwnd, info->crKey, alpha,
3427 info->dwFlags & (LWA_ALPHA | LWA_COLORKEY) );
3428 return TRUE;
3432 /*****************************************************************************
3433 * UpdateLayeredWindow (USER32.@)
3435 BOOL WINAPI UpdateLayeredWindow( HWND hwnd, HDC hdcDst, POINT *pptDst, SIZE *psize,
3436 HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend,
3437 DWORD dwFlags)
3439 UPDATELAYEREDWINDOWINFO info;
3441 info.cbSize = sizeof(info);
3442 info.hdcDst = hdcDst;
3443 info.pptDst = pptDst;
3444 info.psize = psize;
3445 info.hdcSrc = hdcSrc;
3446 info.pptSrc = pptSrc;
3447 info.crKey = crKey;
3448 info.pblend = pblend;
3449 info.dwFlags = dwFlags;
3450 info.prcDirty = NULL;
3451 return UpdateLayeredWindowIndirect( hwnd, &info );
3454 /* 64bit versions */
3456 #ifdef GetWindowLongPtrW
3457 #undef GetWindowLongPtrW
3458 #endif
3460 #ifdef GetWindowLongPtrA
3461 #undef GetWindowLongPtrA
3462 #endif
3464 #ifdef SetWindowLongPtrW
3465 #undef SetWindowLongPtrW
3466 #endif
3468 #ifdef SetWindowLongPtrA
3469 #undef SetWindowLongPtrA
3470 #endif
3472 /*****************************************************************************
3473 * GetWindowLongPtrW (USER32.@)
3475 LONG_PTR WINAPI GetWindowLongPtrW( HWND hwnd, INT offset )
3477 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), TRUE );
3480 /*****************************************************************************
3481 * GetWindowLongPtrA (USER32.@)
3483 LONG_PTR WINAPI GetWindowLongPtrA( HWND hwnd, INT offset )
3485 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), FALSE );
3488 /*****************************************************************************
3489 * SetWindowLongPtrW (USER32.@)
3491 LONG_PTR WINAPI SetWindowLongPtrW( HWND hwnd, INT offset, LONG_PTR newval )
3493 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, TRUE );
3496 /*****************************************************************************
3497 * SetWindowLongPtrA (USER32.@)
3499 LONG_PTR WINAPI SetWindowLongPtrA( HWND hwnd, INT offset, LONG_PTR newval )
3501 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, FALSE );