server: Also return the top-level message window in the get_desktop_window request.
[wine/wine-gecko.git] / dlls / user32 / win.c
bloba924fe3e50e867a50dc61ccdd714fbaf07182968
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 * WIN_GetPtr
363 * Return a pointer to the WND structure if local to the process,
364 * or WND_OTHER_PROCESS if handle may be valid in other process.
365 * If ret value is a valid pointer, it must be released with WIN_ReleasePtr.
367 WND *WIN_GetPtr( HWND hwnd )
369 WND * ptr;
370 WORD index = USER_HANDLE_TO_INDEX(hwnd);
372 if (index >= NB_USER_HANDLES) return NULL;
374 USER_Lock();
375 if ((ptr = user_handles[index]))
377 if (ptr->dwMagic == WND_MAGIC &&
378 (hwnd == ptr->hwndSelf || !HIWORD(hwnd) || HIWORD(hwnd) == 0xffff))
379 return ptr;
380 ptr = NULL;
382 else if (index == USER_HANDLE_TO_INDEX(GetDesktopWindow()))
384 if (hwnd == GetDesktopWindow() || !HIWORD(hwnd) || HIWORD(hwnd) == 0xffff) ptr = WND_DESKTOP;
385 else ptr = NULL;
387 else ptr = WND_OTHER_PROCESS;
388 USER_Unlock();
389 return ptr;
393 /***********************************************************************
394 * WIN_IsCurrentProcess
396 * Check whether a given window belongs to the current process (and return the full handle).
398 HWND WIN_IsCurrentProcess( HWND hwnd )
400 WND *ptr;
401 HWND ret;
403 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
404 ret = ptr->hwndSelf;
405 WIN_ReleasePtr( ptr );
406 return ret;
410 /***********************************************************************
411 * WIN_IsCurrentThread
413 * Check whether a given window belongs to the current thread (and return the full handle).
415 HWND WIN_IsCurrentThread( HWND hwnd )
417 WND *ptr;
418 HWND ret = 0;
420 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
421 if (ptr->tid == GetCurrentThreadId()) ret = ptr->hwndSelf;
422 WIN_ReleasePtr( ptr );
423 return ret;
427 /***********************************************************************
428 * WIN_Handle32
430 * Convert a 16-bit window handle to a full 32-bit handle.
432 HWND WIN_Handle32( HWND16 hwnd16 )
434 WND *ptr;
435 HWND hwnd = (HWND)(ULONG_PTR)hwnd16;
437 if (hwnd16 <= 1 || hwnd16 == 0xffff) return hwnd;
438 /* do sign extension for -2 and -3 */
439 if (hwnd16 >= (HWND16)-3) return (HWND)(LONG_PTR)(INT16)hwnd16;
441 if (!(ptr = WIN_GetPtr( hwnd ))) return hwnd;
443 if (ptr == WND_DESKTOP) return GetDesktopWindow();
445 if (ptr != WND_OTHER_PROCESS)
447 hwnd = ptr->hwndSelf;
448 WIN_ReleasePtr( ptr );
450 else /* may belong to another process */
452 SERVER_START_REQ( get_window_info )
454 req->handle = hwnd;
455 if (!wine_server_call_err( req )) hwnd = reply->full_handle;
457 SERVER_END_REQ;
459 return hwnd;
463 /***********************************************************************
464 * WIN_SetOwner
466 * Change the owner of a window.
468 HWND WIN_SetOwner( HWND hwnd, HWND owner )
470 WND *win = WIN_GetPtr( hwnd );
471 HWND ret = 0;
473 if (!win || win == WND_DESKTOP) return 0;
474 if (win == WND_OTHER_PROCESS)
476 if (IsWindow(hwnd)) ERR( "cannot set owner %p on other process window %p\n", owner, hwnd );
477 return 0;
479 SERVER_START_REQ( set_window_owner )
481 req->handle = hwnd;
482 req->owner = owner;
483 if (!wine_server_call( req ))
485 win->owner = reply->full_owner;
486 ret = reply->prev_owner;
489 SERVER_END_REQ;
490 WIN_ReleasePtr( win );
491 return ret;
495 /***********************************************************************
496 * WIN_SetStyle
498 * Change the style of a window.
500 ULONG WIN_SetStyle( HWND hwnd, ULONG set_bits, ULONG clear_bits )
502 BOOL ok;
503 ULONG new_style, old_style = 0;
504 WND *win = WIN_GetPtr( hwnd );
506 if (!win || win == WND_DESKTOP) return 0;
507 if (win == WND_OTHER_PROCESS)
509 if (IsWindow(hwnd))
510 ERR( "cannot set style %x/%x on other process window %p\n",
511 set_bits, clear_bits, hwnd );
512 return 0;
514 new_style = (win->dwStyle | set_bits) & ~clear_bits;
515 if (new_style == win->dwStyle)
517 WIN_ReleasePtr( win );
518 return new_style;
520 SERVER_START_REQ( set_window_info )
522 req->handle = hwnd;
523 req->flags = SET_WIN_STYLE;
524 req->style = new_style;
525 req->extra_offset = -1;
526 if ((ok = !wine_server_call( req )))
528 old_style = reply->old_style;
529 win->dwStyle = new_style;
532 SERVER_END_REQ;
533 WIN_ReleasePtr( win );
534 if (ok)
536 USER_Driver->pSetWindowStyle( hwnd, old_style );
537 if ((old_style ^ new_style) & WS_VISIBLE) invalidate_dce( hwnd, NULL );
539 return old_style;
543 /***********************************************************************
544 * WIN_GetRectangles
546 * Get the window and client rectangles.
548 BOOL WIN_GetRectangles( HWND hwnd, RECT *rectWindow, RECT *rectClient )
550 WND *win = WIN_GetPtr( hwnd );
551 BOOL ret = TRUE;
553 if (!win) return FALSE;
554 if (win == WND_DESKTOP)
556 RECT rect;
557 rect.left = rect.top = 0;
558 rect.right = GetSystemMetrics(SM_CXSCREEN);
559 rect.bottom = GetSystemMetrics(SM_CYSCREEN);
560 if (rectWindow) *rectWindow = rect;
561 if (rectClient) *rectClient = rect;
563 else if (win == WND_OTHER_PROCESS)
565 SERVER_START_REQ( get_window_rectangles )
567 req->handle = hwnd;
568 if ((ret = !wine_server_call( req )))
570 if (rectWindow)
572 rectWindow->left = reply->window.left;
573 rectWindow->top = reply->window.top;
574 rectWindow->right = reply->window.right;
575 rectWindow->bottom = reply->window.bottom;
577 if (rectClient)
579 rectClient->left = reply->client.left;
580 rectClient->top = reply->client.top;
581 rectClient->right = reply->client.right;
582 rectClient->bottom = reply->client.bottom;
586 SERVER_END_REQ;
588 else
590 if (rectWindow) *rectWindow = win->rectWindow;
591 if (rectClient) *rectClient = win->rectClient;
592 WIN_ReleasePtr( win );
594 return ret;
598 /***********************************************************************
599 * WIN_DestroyWindow
601 * Destroy storage associated to a window. "Internals" p.358
603 LRESULT WIN_DestroyWindow( HWND hwnd )
605 WND *wndPtr;
606 HWND *list;
607 HMENU menu = 0, sys_menu;
608 HWND icon_title;
610 TRACE("%p\n", hwnd );
612 /* free child windows */
613 if ((list = WIN_ListChildren( hwnd )))
615 int i;
616 for (i = 0; list[i]; i++)
618 if (WIN_IsCurrentThread( list[i] )) WIN_DestroyWindow( list[i] );
619 else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
621 HeapFree( GetProcessHeap(), 0, list );
624 /* Unlink now so we won't bother with the children later on */
625 SERVER_START_REQ( set_parent )
627 req->handle = hwnd;
628 req->parent = 0;
629 wine_server_call( req );
631 SERVER_END_REQ;
634 * Send the WM_NCDESTROY to the window being destroyed.
636 SendMessageW( hwnd, WM_NCDESTROY, 0, 0 );
638 /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
640 /* free resources associated with the window */
642 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
643 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
644 menu = (HMENU)wndPtr->wIDmenu;
645 sys_menu = wndPtr->hSysMenu;
646 free_dce( wndPtr->dce, hwnd );
647 wndPtr->dce = NULL;
648 icon_title = wndPtr->icon_title;
649 WIN_ReleasePtr( wndPtr );
651 if (icon_title) DestroyWindow( icon_title );
652 if (menu) DestroyMenu( menu );
653 if (sys_menu) DestroyMenu( sys_menu );
655 USER_Driver->pDestroyWindow( hwnd );
657 free_window_handle( hwnd );
658 return 0;
661 /***********************************************************************
662 * WIN_DestroyThreadWindows
664 * Destroy all children of 'wnd' owned by the current thread.
666 void WIN_DestroyThreadWindows( HWND hwnd )
668 HWND *list;
669 int i;
671 if (!(list = WIN_ListChildren( hwnd ))) return;
672 for (i = 0; list[i]; i++)
674 if (WIN_IsCurrentThread( list[i] ))
675 DestroyWindow( list[i] );
676 else
677 WIN_DestroyThreadWindows( list[i] );
679 HeapFree( GetProcessHeap(), 0, list );
683 /***********************************************************************
684 * WIN_FixCoordinates
686 * Fix the coordinates - Helper for WIN_CreateWindowEx.
687 * returns default show mode in sw.
689 static void WIN_FixCoordinates( CREATESTRUCTA *cs, INT *sw)
691 #define IS_DEFAULT(x) ((x) == CW_USEDEFAULT || (x) == CW_USEDEFAULT16)
692 POINT pos[2];
694 if (cs->dwExStyle & WS_EX_MDICHILD)
696 UINT id = 0;
698 MDI_CalcDefaultChildPos(cs->hwndParent, -1, pos, 0, &id);
699 if (!(cs->style & WS_POPUP)) cs->hMenu = ULongToHandle(id);
701 TRACE("MDI child id %04x\n", id);
704 if (cs->style & (WS_CHILD | WS_POPUP))
706 if (cs->dwExStyle & WS_EX_MDICHILD)
708 if (IS_DEFAULT(cs->x))
710 cs->x = pos[0].x;
711 cs->y = pos[0].y;
713 if (IS_DEFAULT(cs->cx) || !cs->cx) cs->cx = pos[1].x;
714 if (IS_DEFAULT(cs->cy) || !cs->cy) cs->cy = pos[1].y;
716 else
718 if (IS_DEFAULT(cs->x)) cs->x = cs->y = 0;
719 if (IS_DEFAULT(cs->cx)) cs->cx = cs->cy = 0;
722 else /* overlapped window */
724 HMONITOR monitor;
725 MONITORINFO mon_info;
726 STARTUPINFOW info;
728 if (!IS_DEFAULT(cs->x) && !IS_DEFAULT(cs->cx) && !IS_DEFAULT(cs->cy)) return;
730 monitor = MonitorFromWindow( cs->hwndParent, MONITOR_DEFAULTTOPRIMARY );
731 mon_info.cbSize = sizeof(mon_info);
732 GetMonitorInfoW( monitor, &mon_info );
733 GetStartupInfoW( &info );
735 if (IS_DEFAULT(cs->x))
737 if (!IS_DEFAULT(cs->y)) *sw = cs->y;
738 cs->x = (info.dwFlags & STARTF_USEPOSITION) ? info.dwX : mon_info.rcWork.left;
739 cs->y = (info.dwFlags & STARTF_USEPOSITION) ? info.dwY : mon_info.rcWork.top;
742 if (IS_DEFAULT(cs->cx))
744 if (info.dwFlags & STARTF_USESIZE)
746 cs->cx = info.dwXSize;
747 cs->cy = info.dwYSize;
749 else
751 cs->cx = (mon_info.rcWork.right - mon_info.rcWork.left) * 3 / 4 - cs->x;
752 cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
755 /* neither x nor cx are default. Check the y values .
756 * In the trace we see Outlook and Outlook Express using
757 * cy set to CW_USEDEFAULT when opening the address book.
759 else if (IS_DEFAULT(cs->cy))
761 FIXME("Strange use of CW_USEDEFAULT in nHeight\n");
762 cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
765 #undef IS_DEFAULT
768 /***********************************************************************
769 * dump_window_styles
771 static void dump_window_styles( DWORD style, DWORD exstyle )
773 TRACE( "style:" );
774 if(style & WS_POPUP) TRACE(" WS_POPUP");
775 if(style & WS_CHILD) TRACE(" WS_CHILD");
776 if(style & WS_MINIMIZE) TRACE(" WS_MINIMIZE");
777 if(style & WS_VISIBLE) TRACE(" WS_VISIBLE");
778 if(style & WS_DISABLED) TRACE(" WS_DISABLED");
779 if(style & WS_CLIPSIBLINGS) TRACE(" WS_CLIPSIBLINGS");
780 if(style & WS_CLIPCHILDREN) TRACE(" WS_CLIPCHILDREN");
781 if(style & WS_MAXIMIZE) TRACE(" WS_MAXIMIZE");
782 if((style & WS_CAPTION) == WS_CAPTION) TRACE(" WS_CAPTION");
783 else
785 if(style & WS_BORDER) TRACE(" WS_BORDER");
786 if(style & WS_DLGFRAME) TRACE(" WS_DLGFRAME");
788 if(style & WS_VSCROLL) TRACE(" WS_VSCROLL");
789 if(style & WS_HSCROLL) TRACE(" WS_HSCROLL");
790 if(style & WS_SYSMENU) TRACE(" WS_SYSMENU");
791 if(style & WS_THICKFRAME) TRACE(" WS_THICKFRAME");
792 if (style & WS_CHILD)
794 if(style & WS_GROUP) TRACE(" WS_GROUP");
795 if(style & WS_TABSTOP) TRACE(" WS_TABSTOP");
797 else
799 if(style & WS_MINIMIZEBOX) TRACE(" WS_MINIMIZEBOX");
800 if(style & WS_MAXIMIZEBOX) TRACE(" WS_MAXIMIZEBOX");
803 /* FIXME: Add dumping of BS_/ES_/SBS_/LBS_/CBS_/DS_/etc. styles */
804 #define DUMPED_STYLES \
805 (WS_POPUP | \
806 WS_CHILD | \
807 WS_MINIMIZE | \
808 WS_VISIBLE | \
809 WS_DISABLED | \
810 WS_CLIPSIBLINGS | \
811 WS_CLIPCHILDREN | \
812 WS_MAXIMIZE | \
813 WS_BORDER | \
814 WS_DLGFRAME | \
815 WS_VSCROLL | \
816 WS_HSCROLL | \
817 WS_SYSMENU | \
818 WS_THICKFRAME | \
819 WS_GROUP | \
820 WS_TABSTOP | \
821 WS_MINIMIZEBOX | \
822 WS_MAXIMIZEBOX)
824 if(style & ~DUMPED_STYLES) TRACE(" %08lx", style & ~DUMPED_STYLES);
825 TRACE("\n");
826 #undef DUMPED_STYLES
828 TRACE( "exstyle:" );
829 if(exstyle & WS_EX_DLGMODALFRAME) TRACE(" WS_EX_DLGMODALFRAME");
830 if(exstyle & WS_EX_DRAGDETECT) TRACE(" WS_EX_DRAGDETECT");
831 if(exstyle & WS_EX_NOPARENTNOTIFY) TRACE(" WS_EX_NOPARENTNOTIFY");
832 if(exstyle & WS_EX_TOPMOST) TRACE(" WS_EX_TOPMOST");
833 if(exstyle & WS_EX_ACCEPTFILES) TRACE(" WS_EX_ACCEPTFILES");
834 if(exstyle & WS_EX_TRANSPARENT) TRACE(" WS_EX_TRANSPARENT");
835 if(exstyle & WS_EX_MDICHILD) TRACE(" WS_EX_MDICHILD");
836 if(exstyle & WS_EX_TOOLWINDOW) TRACE(" WS_EX_TOOLWINDOW");
837 if(exstyle & WS_EX_WINDOWEDGE) TRACE(" WS_EX_WINDOWEDGE");
838 if(exstyle & WS_EX_CLIENTEDGE) TRACE(" WS_EX_CLIENTEDGE");
839 if(exstyle & WS_EX_CONTEXTHELP) TRACE(" WS_EX_CONTEXTHELP");
840 if(exstyle & WS_EX_RIGHT) TRACE(" WS_EX_RIGHT");
841 if(exstyle & WS_EX_RTLREADING) TRACE(" WS_EX_RTLREADING");
842 if(exstyle & WS_EX_LEFTSCROLLBAR) TRACE(" WS_EX_LEFTSCROLLBAR");
843 if(exstyle & WS_EX_CONTROLPARENT) TRACE(" WS_EX_CONTROLPARENT");
844 if(exstyle & WS_EX_STATICEDGE) TRACE(" WS_EX_STATICEDGE");
845 if(exstyle & WS_EX_APPWINDOW) TRACE(" WS_EX_APPWINDOW");
846 if(exstyle & WS_EX_LAYERED) TRACE(" WS_EX_LAYERED");
848 #define DUMPED_EX_STYLES \
849 (WS_EX_DLGMODALFRAME | \
850 WS_EX_DRAGDETECT | \
851 WS_EX_NOPARENTNOTIFY | \
852 WS_EX_TOPMOST | \
853 WS_EX_ACCEPTFILES | \
854 WS_EX_TRANSPARENT | \
855 WS_EX_MDICHILD | \
856 WS_EX_TOOLWINDOW | \
857 WS_EX_WINDOWEDGE | \
858 WS_EX_CLIENTEDGE | \
859 WS_EX_CONTEXTHELP | \
860 WS_EX_RIGHT | \
861 WS_EX_RTLREADING | \
862 WS_EX_LEFTSCROLLBAR | \
863 WS_EX_CONTROLPARENT | \
864 WS_EX_STATICEDGE | \
865 WS_EX_APPWINDOW | \
866 WS_EX_LAYERED)
868 if(exstyle & ~DUMPED_EX_STYLES) TRACE(" %08lx", exstyle & ~DUMPED_EX_STYLES);
869 TRACE("\n");
870 #undef DUMPED_EX_STYLES
874 /***********************************************************************
875 * WIN_CreateWindowEx
877 * Implementation of CreateWindowEx().
879 static HWND WIN_CreateWindowEx( CREATESTRUCTA *cs, LPCWSTR className, UINT flags )
881 INT cx, cy, style, sw = SW_SHOW;
882 LRESULT result;
883 RECT rect;
884 WND *wndPtr;
885 HWND hwnd, parent, owner, top_child = 0;
886 BOOL unicode = (flags & WIN_ISUNICODE) != 0;
887 MDICREATESTRUCTA mdi_cs;
888 CBT_CREATEWNDA cbtc;
889 CREATESTRUCTA cbcs;
891 TRACE("%s %s ex=%08x style=%08x %d,%d %dx%d parent=%p menu=%p inst=%p params=%p\n",
892 unicode ? debugstr_w((LPCWSTR)cs->lpszName) : debugstr_a(cs->lpszName),
893 debugstr_w(className),
894 cs->dwExStyle, cs->style, cs->x, cs->y, cs->cx, cs->cy,
895 cs->hwndParent, cs->hMenu, cs->hInstance, cs->lpCreateParams );
896 if(TRACE_ON(win)) dump_window_styles( cs->style, cs->dwExStyle );
898 /* Fix the styles for MDI children */
899 if (cs->dwExStyle & WS_EX_MDICHILD)
901 UINT flags = 0;
903 wndPtr = WIN_GetPtr(cs->hwndParent);
904 if (wndPtr && wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
906 flags = wndPtr->flags;
907 WIN_ReleasePtr(wndPtr);
910 if (!(flags & WIN_ISMDICLIENT))
912 WARN("WS_EX_MDICHILD, but parent %p is not MDIClient\n", cs->hwndParent);
913 return 0;
916 /* cs->lpCreateParams of WM_[NC]CREATE is different for MDI children.
917 * MDICREATESTRUCT members have the originally passed values.
919 * Note: we rely on the fact that MDICREATESTRUCTA and MDICREATESTRUCTW
920 * have the same layout.
922 mdi_cs.szClass = cs->lpszClass;
923 mdi_cs.szTitle = cs->lpszName;
924 mdi_cs.hOwner = cs->hInstance;
925 mdi_cs.x = cs->x;
926 mdi_cs.y = cs->y;
927 mdi_cs.cx = cs->cx;
928 mdi_cs.cy = cs->cy;
929 mdi_cs.style = cs->style;
930 mdi_cs.lParam = (LPARAM)cs->lpCreateParams;
932 cs->lpCreateParams = (LPVOID)&mdi_cs;
934 if (GetWindowLongW(cs->hwndParent, GWL_STYLE) & MDIS_ALLCHILDSTYLES)
936 if (cs->style & WS_POPUP)
938 TRACE("WS_POPUP with MDIS_ALLCHILDSTYLES is not allowed\n");
939 return 0;
941 cs->style |= WS_CHILD | WS_CLIPSIBLINGS;
943 else
945 cs->style &= ~WS_POPUP;
946 cs->style |= WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION |
947 WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
950 top_child = GetWindow(cs->hwndParent, GW_CHILD);
952 if (top_child)
954 /* Restore current maximized child */
955 if((cs->style & WS_VISIBLE) && IsZoomed(top_child))
957 TRACE("Restoring current maximized child %p\n", top_child);
958 SendMessageW( top_child, WM_SETREDRAW, FALSE, 0 );
959 ShowWindow( top_child, SW_SHOWNORMAL );
960 SendMessageW( top_child, WM_SETREDRAW, TRUE, 0 );
965 /* Find the parent window */
967 parent = cs->hwndParent;
968 owner = 0;
970 if (cs->hwndParent == HWND_MESSAGE)
972 /* native ole32.OleInitialize uses HWND_MESSAGE to create the
973 * message window (style: WS_POPUP|WS_DISABLED)
975 FIXME("Parent is HWND_MESSAGE\n");
976 parent = GetDesktopWindow();
978 else if (cs->hwndParent)
980 if ((cs->style & (WS_CHILD|WS_POPUP)) != WS_CHILD)
982 parent = GetDesktopWindow();
983 owner = cs->hwndParent;
986 else
988 static const WCHAR messageW[] = {'M','e','s','s','a','g','e',0};
990 if ((cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
992 WARN("No parent for child window\n" );
993 SetLastError(ERROR_TLW_WITH_WSCHILD);
994 return 0; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
996 /* are we creating the desktop or HWND_MESSAGE parent itself? */
997 if (className != (LPCWSTR)DESKTOP_CLASS_ATOM &&
998 (IS_INTRESOURCE(className) || strcmpiW( className, messageW )))
999 parent = GetDesktopWindow();
1002 WIN_FixCoordinates(cs, &sw); /* fix default coordinates */
1004 if ((cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
1005 ((!(cs->dwExStyle & WS_EX_STATICEDGE)) &&
1006 (cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
1007 cs->dwExStyle |= WS_EX_WINDOWEDGE;
1008 else
1009 cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
1011 /* Create the window structure */
1013 if (!(wndPtr = create_window_handle( parent, owner, className, cs->hInstance, unicode )))
1014 return 0;
1015 hwnd = wndPtr->hwndSelf;
1017 /* Fill the window structure */
1019 wndPtr->tid = GetCurrentThreadId();
1020 wndPtr->hInstance = cs->hInstance;
1021 wndPtr->text = NULL;
1022 wndPtr->dwStyle = cs->style & ~WS_VISIBLE;
1023 wndPtr->dwExStyle = cs->dwExStyle;
1024 wndPtr->wIDmenu = 0;
1025 wndPtr->helpContext = 0;
1026 wndPtr->pVScroll = NULL;
1027 wndPtr->pHScroll = NULL;
1028 wndPtr->userdata = 0;
1029 wndPtr->hIcon = 0;
1030 wndPtr->hIconSmall = 0;
1031 wndPtr->hSysMenu = 0;
1032 wndPtr->flags |= (flags & WIN_ISWIN32);
1034 if (wndPtr->dwStyle & WS_SYSMENU) SetSystemMenu( hwnd, 0 );
1037 * Correct the window styles.
1039 * It affects only the style loaded into the WIN structure.
1042 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1044 wndPtr->dwStyle |= WS_CLIPSIBLINGS;
1045 if (!(wndPtr->dwStyle & WS_POPUP))
1046 wndPtr->dwStyle |= WS_CAPTION;
1050 * WS_EX_WINDOWEDGE appears to be enforced based on the other styles, so
1051 * why does the user get to set it?
1054 if ((wndPtr->dwExStyle & WS_EX_DLGMODALFRAME) ||
1055 (wndPtr->dwStyle & (WS_DLGFRAME | WS_THICKFRAME)))
1056 wndPtr->dwExStyle |= WS_EX_WINDOWEDGE;
1057 else
1058 wndPtr->dwExStyle &= ~WS_EX_WINDOWEDGE;
1060 if (!(wndPtr->dwStyle & (WS_CHILD | WS_POPUP)))
1061 wndPtr->flags |= WIN_NEED_SIZE;
1063 SERVER_START_REQ( set_window_info )
1065 req->handle = hwnd;
1066 req->flags = SET_WIN_STYLE | SET_WIN_EXSTYLE | SET_WIN_INSTANCE | SET_WIN_UNICODE;
1067 req->style = wndPtr->dwStyle;
1068 req->ex_style = wndPtr->dwExStyle;
1069 req->instance = (void *)wndPtr->hInstance;
1070 req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
1071 req->extra_offset = -1;
1072 wine_server_call( req );
1074 SERVER_END_REQ;
1076 /* Set the window menu */
1078 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1080 if (cs->hMenu)
1082 if (!MENU_SetMenu(hwnd, cs->hMenu))
1084 WIN_ReleasePtr( wndPtr );
1085 free_window_handle( hwnd );
1086 return 0;
1089 else
1091 LPCSTR menuName = (LPCSTR)GetClassLongPtrA( hwnd, GCLP_MENUNAME );
1092 if (menuName)
1094 if (!cs->hInstance || HIWORD(cs->hInstance))
1095 cs->hMenu = LoadMenuA(cs->hInstance,menuName);
1096 else
1097 cs->hMenu = HMENU_32(LoadMenu16(HINSTANCE_16(cs->hInstance),menuName));
1099 if (cs->hMenu) MENU_SetMenu( hwnd, cs->hMenu );
1103 else SetWindowLongPtrW( hwnd, GWLP_ID, (ULONG_PTR)cs->hMenu );
1105 /* call the WH_CBT hook */
1107 /* the window style passed to the hook must be the real window style,
1108 * rather than just the window style that the caller to CreateWindowEx
1109 * passed in, so we have to copy the original CREATESTRUCT and get the
1110 * the real style. */
1111 cbcs = *cs;
1112 cbcs.style = wndPtr->dwStyle;
1113 cbtc.lpcs = &cbcs;
1114 cbtc.hwndInsertAfter = HWND_TOP;
1115 WIN_ReleasePtr( wndPtr );
1116 if (HOOK_CallHooks( WH_CBT, HCBT_CREATEWND, (WPARAM)hwnd, (LPARAM)&cbtc, unicode )) goto failed;
1118 /* send the WM_GETMINMAXINFO message and fix the size if needed */
1120 cx = cs->cx;
1121 cy = cs->cy;
1122 if ((cs->style & WS_THICKFRAME) || !(cs->style & (WS_POPUP | WS_CHILD)))
1124 POINT maxSize, maxPos, minTrack, maxTrack;
1125 WINPOS_GetMinMaxInfo( hwnd, &maxSize, &maxPos, &minTrack, &maxTrack);
1126 if (maxTrack.x < cx) cx = maxTrack.x;
1127 if (maxTrack.y < cy) cy = maxTrack.y;
1130 if (cx < 0) cx = 0;
1131 if (cy < 0) cy = 0;
1132 SetRect( &rect, cs->x, cs->y, cs->x + cx, cs->y + cy );
1133 /* check for wraparound */
1134 if (cs->x + cx < cs->x) rect.right = 0x7fffffff;
1135 if (cs->y + cy < cs->y) rect.bottom = 0x7fffffff;
1136 if (!set_window_pos( hwnd, 0, SWP_NOZORDER | SWP_NOACTIVATE, &rect, &rect, NULL )) goto failed;
1138 /* send WM_NCCREATE */
1140 TRACE( "hwnd %p cs %d,%d %dx%d\n", hwnd, cs->x, cs->y, cx, cy );
1141 if (unicode)
1142 result = SendMessageW( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1143 else
1144 result = SendMessageA( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1145 if (!result)
1147 WARN( "%p: aborted by WM_NCCREATE\n", hwnd );
1148 goto failed;
1151 /* send WM_NCCALCSIZE */
1153 if ((wndPtr = WIN_GetPtr(hwnd)))
1155 /* yes, even if the CBT hook was called with HWND_TOP */
1156 POINT pt;
1157 HWND insert_after = (wndPtr->dwStyle & WS_CHILD) ? HWND_BOTTOM : HWND_TOP;
1158 RECT window_rect = wndPtr->rectWindow;
1159 RECT client_rect = window_rect;
1160 WIN_ReleasePtr( wndPtr );
1162 /* the rectangle is in screen coords for WM_NCCALCSIZE when wparam is FALSE */
1163 pt.x = pt.y = 0;
1164 MapWindowPoints( parent, 0, &pt, 1 );
1165 OffsetRect( &client_rect, pt.x, pt.y );
1166 SendMessageW( hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&client_rect );
1167 OffsetRect( &client_rect, -pt.x, -pt.y );
1168 set_window_pos( hwnd, insert_after, SWP_NOACTIVATE, &window_rect, &client_rect, NULL );
1170 else return 0;
1172 /* send WM_CREATE */
1174 if (unicode)
1175 result = SendMessageW( hwnd, WM_CREATE, 0, (LPARAM)cs );
1176 else
1177 result = SendMessageA( hwnd, WM_CREATE, 0, (LPARAM)cs );
1178 if (result == -1) goto failed;
1180 /* call the driver */
1182 if (!USER_Driver->pCreateWindow( hwnd )) goto failed;
1184 NotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_WINDOW, 0);
1186 /* send the size messages */
1188 if (!(wndPtr = WIN_GetPtr(hwnd))) return 0;
1189 if (!(wndPtr->flags & WIN_NEED_SIZE))
1191 rect = wndPtr->rectClient;
1192 WIN_ReleasePtr( wndPtr );
1193 SendMessageW( hwnd, WM_SIZE, SIZE_RESTORED,
1194 MAKELONG(rect.right-rect.left, rect.bottom-rect.top));
1195 SendMessageW( hwnd, WM_MOVE, 0, MAKELONG( rect.left, rect.top ) );
1197 else WIN_ReleasePtr( wndPtr );
1199 /* Show the window, maximizing or minimizing if needed */
1201 style = WIN_SetStyle( hwnd, 0, WS_MAXIMIZE | WS_MINIMIZE );
1202 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
1204 RECT newPos;
1205 UINT swFlag = (style & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;
1207 swFlag = WINPOS_MinMaximize( hwnd, swFlag, &newPos );
1208 swFlag |= SWP_FRAMECHANGED; /* Frame always gets changed */
1209 if (!(style & WS_VISIBLE) || (style & WS_CHILD) || GetActiveWindow()) swFlag |= SWP_NOACTIVATE;
1210 SetWindowPos( hwnd, 0, newPos.left, newPos.top, newPos.right, newPos.bottom, swFlag );
1213 /* Notify the parent window only */
1215 send_parent_notify( hwnd, WM_CREATE );
1216 if (!IsWindow( hwnd )) return 0;
1218 if (cs->style & WS_VISIBLE)
1220 if (cs->style & WS_MAXIMIZE)
1221 sw = SW_SHOW;
1222 else if (cs->style & WS_MINIMIZE)
1223 sw = SW_SHOWMINIMIZED;
1225 ShowWindow( hwnd, sw );
1226 if (cs->dwExStyle & WS_EX_MDICHILD)
1228 SendMessageW(cs->hwndParent, WM_MDIREFRESHMENU, 0, 0);
1229 /* ShowWindow won't activate child windows */
1230 SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE );
1234 /* Call WH_SHELL hook */
1236 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1237 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0, TRUE );
1239 TRACE("created window %p\n", hwnd);
1240 return hwnd;
1242 failed:
1243 WIN_DestroyWindow( hwnd );
1244 return 0;
1248 /***********************************************************************
1249 * CreateWindow (USER.41)
1251 HWND16 WINAPI CreateWindow16( LPCSTR className, LPCSTR windowName,
1252 DWORD style, INT16 x, INT16 y, INT16 width,
1253 INT16 height, HWND16 parent, HMENU16 menu,
1254 HINSTANCE16 instance, LPVOID data )
1256 return CreateWindowEx16( 0, className, windowName, style,
1257 x, y, width, height, parent, menu, instance, data );
1261 /***********************************************************************
1262 * CreateWindowEx (USER.452)
1264 HWND16 WINAPI CreateWindowEx16( DWORD exStyle, LPCSTR className,
1265 LPCSTR windowName, DWORD style, INT16 x,
1266 INT16 y, INT16 width, INT16 height,
1267 HWND16 parent, HMENU16 menu,
1268 HINSTANCE16 instance, LPVOID data )
1270 CREATESTRUCTA cs;
1271 char buffer[256];
1273 /* Fix the coordinates */
1275 cs.x = (x == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)x;
1276 cs.y = (y == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)y;
1277 cs.cx = (width == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)width;
1278 cs.cy = (height == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)height;
1280 /* Create the window */
1282 cs.lpCreateParams = data;
1283 cs.hInstance = HINSTANCE_32(instance);
1284 cs.hMenu = HMENU_32(menu);
1285 cs.hwndParent = WIN_Handle32( parent );
1286 cs.style = style;
1287 cs.lpszName = windowName;
1288 cs.lpszClass = className;
1289 cs.dwExStyle = exStyle;
1291 if (!IS_INTRESOURCE(className))
1293 WCHAR bufferW[256];
1295 if (!MultiByteToWideChar( CP_ACP, 0, className, -1, bufferW, sizeof(bufferW)/sizeof(WCHAR) ))
1296 return 0;
1297 return HWND_16( WIN_CreateWindowEx( &cs, bufferW, 0 ));
1299 else
1301 if (!GlobalGetAtomNameA( LOWORD(className), buffer, sizeof(buffer) ))
1303 ERR( "bad atom %x\n", LOWORD(className));
1304 return 0;
1306 cs.lpszClass = buffer;
1307 return HWND_16( WIN_CreateWindowEx( &cs, (LPCWSTR)className, 0 ));
1312 /***********************************************************************
1313 * CreateWindowExA (USER32.@)
1315 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1316 LPCSTR windowName, DWORD style, INT x,
1317 INT y, INT width, INT height,
1318 HWND parent, HMENU menu,
1319 HINSTANCE instance, LPVOID data )
1321 CREATESTRUCTA cs;
1323 cs.lpCreateParams = data;
1324 cs.hInstance = instance;
1325 cs.hMenu = menu;
1326 cs.hwndParent = parent;
1327 cs.x = x;
1328 cs.y = y;
1329 cs.cx = width;
1330 cs.cy = height;
1331 cs.style = style;
1332 cs.lpszName = windowName;
1333 cs.lpszClass = className;
1334 cs.dwExStyle = exStyle;
1336 if (!IS_INTRESOURCE(className))
1338 WCHAR bufferW[256];
1339 if (!MultiByteToWideChar( CP_ACP, 0, className, -1, bufferW, sizeof(bufferW)/sizeof(WCHAR) ))
1340 return 0;
1341 return WIN_CreateWindowEx( &cs, bufferW, WIN_ISWIN32 );
1343 return WIN_CreateWindowEx( &cs, (LPCWSTR)className, WIN_ISWIN32 );
1347 /***********************************************************************
1348 * CreateWindowExW (USER32.@)
1350 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1351 LPCWSTR windowName, DWORD style, INT x,
1352 INT y, INT width, INT height,
1353 HWND parent, HMENU menu,
1354 HINSTANCE instance, LPVOID data )
1356 CREATESTRUCTW cs;
1358 cs.lpCreateParams = data;
1359 cs.hInstance = instance;
1360 cs.hMenu = menu;
1361 cs.hwndParent = parent;
1362 cs.x = x;
1363 cs.y = y;
1364 cs.cx = width;
1365 cs.cy = height;
1366 cs.style = style;
1367 cs.lpszName = windowName;
1368 cs.lpszClass = className;
1369 cs.dwExStyle = exStyle;
1371 /* Note: we rely on the fact that CREATESTRUCTA and */
1372 /* CREATESTRUCTW have the same layout. */
1373 return WIN_CreateWindowEx( (CREATESTRUCTA *)&cs, className, WIN_ISWIN32 | WIN_ISUNICODE );
1377 /***********************************************************************
1378 * WIN_SendDestroyMsg
1380 static void WIN_SendDestroyMsg( HWND hwnd )
1382 GUITHREADINFO info;
1384 if (GetGUIThreadInfo( GetCurrentThreadId(), &info ))
1386 if (hwnd == info.hwndCaret) DestroyCaret();
1387 if (hwnd == info.hwndActive) WINPOS_ActivateOtherWindow( hwnd );
1391 * Send the WM_DESTROY to the window.
1393 SendMessageW( hwnd, WM_DESTROY, 0, 0);
1396 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1397 * make sure that the window still exists when we come back.
1399 if (IsWindow(hwnd))
1401 HWND* pWndArray;
1402 int i;
1404 if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1406 for (i = 0; pWndArray[i]; i++)
1408 if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1410 HeapFree( GetProcessHeap(), 0, pWndArray );
1412 else
1413 WARN("\tdestroyed itself while in WM_DESTROY!\n");
1417 /***********************************************************************
1418 * DestroyWindow (USER32.@)
1420 BOOL WINAPI DestroyWindow( HWND hwnd )
1422 BOOL is_child;
1424 if (!(hwnd = WIN_IsCurrentThread( hwnd )) || (hwnd == GetDesktopWindow()))
1426 SetLastError( ERROR_ACCESS_DENIED );
1427 return FALSE;
1430 TRACE("(%p)\n", hwnd);
1432 /* Call hooks */
1434 if (HOOK_CallHooks( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0, TRUE )) return FALSE;
1436 if (MENU_IsMenuActive() == hwnd)
1437 EndMenu();
1439 is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;
1441 if (is_child)
1443 if (!USER_IsExitingThread( GetCurrentThreadId() ))
1444 send_parent_notify( hwnd, WM_DESTROY );
1446 else if (!GetWindow( hwnd, GW_OWNER ))
1448 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
1449 /* FIXME: clean up palette - see "Internals" p.352 */
1452 if (!IsWindow(hwnd)) return TRUE;
1454 /* Hide the window */
1455 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)
1457 /* Only child windows receive WM_SHOWWINDOW in DestroyWindow() */
1458 if (is_child)
1459 ShowWindow( hwnd, SW_HIDE );
1460 else
1461 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE |
1462 SWP_NOZORDER | SWP_NOACTIVATE | SWP_HIDEWINDOW );
1465 if (!IsWindow(hwnd)) return TRUE;
1467 /* Recursively destroy owned windows */
1469 if (!is_child)
1471 for (;;)
1473 int i, got_one = 0;
1474 HWND *list = WIN_ListChildren( GetDesktopWindow() );
1475 if (list)
1477 for (i = 0; list[i]; i++)
1479 if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1480 if (WIN_IsCurrentThread( list[i] ))
1482 DestroyWindow( list[i] );
1483 got_one = 1;
1484 continue;
1486 WIN_SetOwner( list[i], 0 );
1488 HeapFree( GetProcessHeap(), 0, list );
1490 if (!got_one) break;
1494 /* Send destroy messages */
1496 WIN_SendDestroyMsg( hwnd );
1497 if (!IsWindow( hwnd )) return TRUE;
1499 if (GetClipboardOwner() == hwnd)
1500 CLIPBOARD_ReleaseOwner();
1502 /* Destroy the window storage */
1504 WIN_DestroyWindow( hwnd );
1505 return TRUE;
1509 /***********************************************************************
1510 * CloseWindow (USER32.@)
1512 BOOL WINAPI CloseWindow( HWND hwnd )
1514 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1515 ShowWindow( hwnd, SW_MINIMIZE );
1516 return TRUE;
1520 /***********************************************************************
1521 * OpenIcon (USER32.@)
1523 BOOL WINAPI OpenIcon( HWND hwnd )
1525 if (!IsIconic( hwnd )) return FALSE;
1526 ShowWindow( hwnd, SW_SHOWNORMAL );
1527 return TRUE;
1531 /***********************************************************************
1532 * FindWindowExW (USER32.@)
1534 HWND WINAPI FindWindowExW( HWND parent, HWND child, LPCWSTR className, LPCWSTR title )
1536 HWND *list = NULL;
1537 HWND retvalue = 0;
1538 int i = 0, len = 0;
1539 WCHAR *buffer = NULL;
1541 if (!parent) parent = GetDesktopWindow();
1542 if (title)
1544 len = strlenW(title) + 1; /* one extra char to check for chars beyond the end */
1545 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1548 if (!(list = list_window_children( 0, parent, className, 0 ))) goto done;
1550 if (child)
1552 child = WIN_GetFullHandle( child );
1553 while (list[i] && list[i] != child) i++;
1554 if (!list[i]) goto done;
1555 i++; /* start from next window */
1558 if (title)
1560 while (list[i])
1562 if (GetWindowTextW( list[i], buffer, len + 1 ) && !strcmpiW( buffer, title )) break;
1563 i++;
1566 retvalue = list[i];
1568 done:
1569 HeapFree( GetProcessHeap(), 0, list );
1570 HeapFree( GetProcessHeap(), 0, buffer );
1571 return retvalue;
1576 /***********************************************************************
1577 * FindWindowA (USER32.@)
1579 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1581 HWND ret = FindWindowExA( 0, 0, className, title );
1582 if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1583 return ret;
1587 /***********************************************************************
1588 * FindWindowExA (USER32.@)
1590 HWND WINAPI FindWindowExA( HWND parent, HWND child, LPCSTR className, LPCSTR title )
1592 LPWSTR titleW = NULL;
1593 HWND hwnd = 0;
1595 if (title)
1597 DWORD len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
1598 if (!(titleW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
1599 MultiByteToWideChar( CP_ACP, 0, title, -1, titleW, len );
1602 if (!IS_INTRESOURCE(className))
1604 WCHAR classW[256];
1605 if (MultiByteToWideChar( CP_ACP, 0, className, -1, classW, sizeof(classW)/sizeof(WCHAR) ))
1606 hwnd = FindWindowExW( parent, child, classW, titleW );
1608 else
1610 hwnd = FindWindowExW( parent, child, (LPCWSTR)className, titleW );
1613 HeapFree( GetProcessHeap(), 0, titleW );
1614 return hwnd;
1618 /***********************************************************************
1619 * FindWindowW (USER32.@)
1621 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
1623 return FindWindowExW( 0, 0, className, title );
1627 /**********************************************************************
1628 * GetDesktopWindow (USER32.@)
1630 HWND WINAPI GetDesktopWindow(void)
1632 struct user_thread_info *thread_info = get_user_thread_info();
1634 if (thread_info->top_window) return thread_info->top_window;
1636 SERVER_START_REQ( get_desktop_window )
1638 req->force = 0;
1639 if (!wine_server_call( req ))
1641 thread_info->top_window = reply->top_window;
1642 thread_info->msg_window = reply->msg_window;
1645 SERVER_END_REQ;
1647 if (!thread_info->top_window)
1649 USEROBJECTFLAGS flags;
1650 if (!GetUserObjectInformationW( GetProcessWindowStation(), UOI_FLAGS, &flags,
1651 sizeof(flags), NULL ) || (flags.dwFlags & WSF_VISIBLE))
1653 static const WCHAR command_line[] = {'\\','e','x','p','l','o','r','e','r','.','e','x','e',' ','/','d','e','s','k','t','o','p',0};
1654 STARTUPINFOW si;
1655 PROCESS_INFORMATION pi;
1656 WCHAR cmdline[MAX_PATH + sizeof(command_line)/sizeof(WCHAR)];
1658 memset( &si, 0, sizeof(si) );
1659 si.cb = sizeof(si);
1660 si.dwFlags = STARTF_USESTDHANDLES;
1661 si.hStdInput = 0;
1662 si.hStdOutput = 0;
1663 si.hStdError = GetStdHandle( STD_ERROR_HANDLE );
1665 GetSystemDirectoryW( cmdline, MAX_PATH );
1666 lstrcatW( cmdline, command_line );
1667 if (CreateProcessW( NULL, cmdline, NULL, NULL, FALSE, DETACHED_PROCESS,
1668 NULL, NULL, &si, &pi ))
1670 TRACE( "started explorer pid %04x tid %04x\n", pi.dwProcessId, pi.dwThreadId );
1671 WaitForInputIdle( pi.hProcess, 10000 );
1672 CloseHandle( pi.hThread );
1673 CloseHandle( pi.hProcess );
1675 else WARN( "failed to start explorer, err %d\n", GetLastError() );
1677 else TRACE( "not starting explorer since winstation is not visible\n" );
1679 SERVER_START_REQ( get_desktop_window )
1681 req->force = 1;
1682 if (!wine_server_call( req ))
1684 thread_info->top_window = reply->top_window;
1685 thread_info->msg_window = reply->msg_window;
1688 SERVER_END_REQ;
1691 if (!thread_info->top_window || !USER_Driver->pCreateDesktopWindow( thread_info->top_window ))
1692 ERR( "failed to create desktop window\n" );
1694 return thread_info->top_window;
1698 /*******************************************************************
1699 * EnableWindow (USER32.@)
1701 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
1703 BOOL retvalue;
1704 HWND full_handle;
1706 if (is_broadcast(hwnd))
1708 SetLastError( ERROR_INVALID_PARAMETER );
1709 return FALSE;
1712 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
1713 return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
1715 hwnd = full_handle;
1717 TRACE("( %p, %d )\n", hwnd, enable);
1719 retvalue = !IsWindowEnabled( hwnd );
1721 if (enable && retvalue)
1723 WIN_SetStyle( hwnd, 0, WS_DISABLED );
1724 SendMessageW( hwnd, WM_ENABLE, TRUE, 0 );
1726 else if (!enable && !retvalue)
1728 HWND capture_wnd;
1730 SendMessageW( hwnd, WM_CANCELMODE, 0, 0);
1732 WIN_SetStyle( hwnd, WS_DISABLED, 0 );
1734 if (hwnd == GetFocus())
1735 SetFocus( 0 ); /* A disabled window can't have the focus */
1737 capture_wnd = GetCapture();
1738 if (hwnd == capture_wnd || IsChild(hwnd, capture_wnd))
1739 ReleaseCapture(); /* A disabled window can't capture the mouse */
1741 SendMessageW( hwnd, WM_ENABLE, FALSE, 0 );
1743 return retvalue;
1747 /***********************************************************************
1748 * IsWindowEnabled (USER32.@)
1750 BOOL WINAPI IsWindowEnabled(HWND hWnd)
1752 return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
1756 /***********************************************************************
1757 * IsWindowUnicode (USER32.@)
1759 BOOL WINAPI IsWindowUnicode( HWND hwnd )
1761 WND * wndPtr;
1762 BOOL retvalue = FALSE;
1764 if (!(wndPtr = WIN_GetPtr(hwnd))) return FALSE;
1766 if (wndPtr == WND_DESKTOP) return TRUE;
1768 if (wndPtr != WND_OTHER_PROCESS)
1770 retvalue = (wndPtr->flags & WIN_ISUNICODE) != 0;
1771 WIN_ReleasePtr( wndPtr );
1773 else
1775 SERVER_START_REQ( get_window_info )
1777 req->handle = hwnd;
1778 if (!wine_server_call_err( req )) retvalue = reply->is_unicode;
1780 SERVER_END_REQ;
1782 return retvalue;
1786 /**********************************************************************
1787 * WIN_GetWindowLong
1789 * Helper function for GetWindowLong().
1791 static LONG_PTR WIN_GetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicode )
1793 LONG_PTR retvalue = 0;
1794 WND *wndPtr;
1796 if (offset == GWLP_HWNDPARENT)
1798 HWND parent = GetAncestor( hwnd, GA_PARENT );
1799 if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
1800 return (ULONG_PTR)parent;
1803 if (!(wndPtr = WIN_GetPtr( hwnd )))
1805 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1806 return 0;
1809 if (wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP)
1811 if (offset == GWLP_WNDPROC)
1813 SetLastError( ERROR_ACCESS_DENIED );
1814 return 0;
1816 SERVER_START_REQ( set_window_info )
1818 req->handle = hwnd;
1819 req->flags = 0; /* don't set anything, just retrieve */
1820 req->extra_offset = (offset >= 0) ? offset : -1;
1821 req->extra_size = (offset >= 0) ? size : 0;
1822 if (!wine_server_call_err( req ))
1824 switch(offset)
1826 case GWL_STYLE: retvalue = reply->old_style; break;
1827 case GWL_EXSTYLE: retvalue = reply->old_ex_style; break;
1828 case GWLP_ID: retvalue = reply->old_id; break;
1829 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)reply->old_instance; break;
1830 case GWLP_USERDATA: retvalue = reply->old_user_data; break;
1831 default:
1832 if (offset >= 0) retvalue = get_win_data( &reply->old_extra_value, size );
1833 else SetLastError( ERROR_INVALID_INDEX );
1834 break;
1838 SERVER_END_REQ;
1839 return retvalue;
1842 /* now we have a valid wndPtr */
1844 if (offset >= 0)
1846 if (offset > (int)(wndPtr->cbWndExtra - size))
1848 WARN("Invalid offset %d\n", offset );
1849 WIN_ReleasePtr( wndPtr );
1850 SetLastError( ERROR_INVALID_INDEX );
1851 return 0;
1853 retvalue = get_win_data( (char *)wndPtr->wExtra + offset, size );
1855 /* Special case for dialog window procedure */
1856 if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && (wndPtr->flags & WIN_ISDIALOG))
1857 retvalue = (LONG_PTR)WINPROC_GetProc( (WNDPROC)retvalue, unicode );
1858 WIN_ReleasePtr( wndPtr );
1859 return retvalue;
1862 switch(offset)
1864 case GWLP_USERDATA: retvalue = wndPtr->userdata; break;
1865 case GWL_STYLE: retvalue = wndPtr->dwStyle; break;
1866 case GWL_EXSTYLE: retvalue = wndPtr->dwExStyle; break;
1867 case GWLP_ID: retvalue = wndPtr->wIDmenu; break;
1868 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hInstance; break;
1869 case GWLP_WNDPROC:
1870 /* This looks like a hack only for the edit control (see tests). This makes these controls
1871 * more tolerant to A/W mismatches. The lack of W->A->W conversion for such a mismatch suggests
1872 * that the hack is in GetWindowLongPtr[AW], not in winprocs.
1874 if (wndPtr->winproc == EDIT_winproc_handle && (!unicode != !(wndPtr->flags & WIN_ISUNICODE)))
1875 retvalue = (ULONG_PTR)wndPtr->winproc;
1876 else
1877 retvalue = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, unicode );
1878 break;
1879 default:
1880 WARN("Unknown offset %d\n", offset );
1881 SetLastError( ERROR_INVALID_INDEX );
1882 break;
1884 WIN_ReleasePtr(wndPtr);
1885 return retvalue;
1889 /**********************************************************************
1890 * WIN_SetWindowLong
1892 * Helper function for SetWindowLong().
1894 * 0 is the failure code. However, in the case of failure SetLastError
1895 * must be set to distinguish between a 0 return value and a failure.
1897 LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, UINT size, LONG_PTR newval, BOOL unicode )
1899 STYLESTRUCT style;
1900 BOOL ok;
1901 LONG_PTR retval = 0;
1902 WND *wndPtr;
1904 TRACE( "%p %d %lx %c\n", hwnd, offset, newval, unicode ? 'W' : 'A' );
1906 if (is_broadcast(hwnd))
1908 SetLastError( ERROR_INVALID_PARAMETER );
1909 return FALSE;
1912 if (!(wndPtr = WIN_GetPtr( hwnd )))
1914 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1915 return 0;
1917 if (wndPtr == WND_DESKTOP)
1919 /* can't change anything on the desktop window */
1920 SetLastError( ERROR_ACCESS_DENIED );
1921 return 0;
1923 if (wndPtr == WND_OTHER_PROCESS)
1925 if (offset == GWLP_WNDPROC)
1927 SetLastError( ERROR_ACCESS_DENIED );
1928 return 0;
1930 if (offset > 32767 || offset < -32767)
1932 SetLastError( ERROR_INVALID_INDEX );
1933 return 0;
1935 return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, MAKEWPARAM( offset, size ), newval );
1938 /* first some special cases */
1939 switch( offset )
1941 case GWL_STYLE:
1942 case GWL_EXSTYLE:
1943 style.styleOld =
1944 offset == GWL_STYLE ? wndPtr->dwStyle : wndPtr->dwExStyle;
1945 style.styleNew = newval;
1946 WIN_ReleasePtr( wndPtr );
1947 SendMessageW( hwnd, WM_STYLECHANGING, offset, (LPARAM)&style );
1948 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
1949 newval = style.styleNew;
1950 break;
1951 case GWLP_HWNDPARENT:
1952 if (wndPtr->parent == GetDesktopWindow())
1954 WIN_ReleasePtr( wndPtr );
1955 return (ULONG_PTR)WIN_SetOwner( hwnd, (HWND)newval );
1957 else
1959 WIN_ReleasePtr( wndPtr );
1960 return (ULONG_PTR)SetParent( hwnd, (HWND)newval );
1962 case GWLP_WNDPROC:
1964 WNDPROC proc;
1965 UINT old_flags = wndPtr->flags;
1966 retval = WIN_GetWindowLong( hwnd, offset, size, unicode );
1967 if (unicode) proc = WINPROC_AllocProc( NULL, (WNDPROC)newval );
1968 else proc = WINPROC_AllocProc( (WNDPROC)newval, NULL );
1969 if (proc) wndPtr->winproc = proc;
1970 if (WINPROC_IsUnicode( proc, unicode )) wndPtr->flags |= WIN_ISUNICODE;
1971 else wndPtr->flags &= ~WIN_ISUNICODE;
1972 if (!((old_flags ^ wndPtr->flags) & WIN_ISUNICODE))
1974 WIN_ReleasePtr( wndPtr );
1975 return retval;
1977 /* update is_unicode flag on the server side */
1978 break;
1980 case GWLP_ID:
1981 case GWLP_HINSTANCE:
1982 case GWLP_USERDATA:
1983 break;
1984 case DWLP_DLGPROC:
1985 if ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
1986 (size == sizeof(LONG_PTR)) && (wndPtr->flags & WIN_ISDIALOG))
1988 WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWLP_DLGPROC);
1989 retval = (ULONG_PTR)WINPROC_GetProc( *ptr, unicode );
1990 if (unicode) *ptr = WINPROC_AllocProc( NULL, (WNDPROC)newval );
1991 else *ptr = WINPROC_AllocProc( (WNDPROC)newval, NULL );
1992 WIN_ReleasePtr( wndPtr );
1993 return retval;
1995 /* fall through */
1996 default:
1997 if (offset < 0 || offset > (int)(wndPtr->cbWndExtra - size))
1999 WARN("Invalid offset %d\n", offset );
2000 WIN_ReleasePtr( wndPtr );
2001 SetLastError( ERROR_INVALID_INDEX );
2002 return 0;
2004 else if (get_win_data( (char *)wndPtr->wExtra + offset, size ) == newval)
2006 /* already set to the same value */
2007 WIN_ReleasePtr( wndPtr );
2008 return newval;
2010 break;
2013 SERVER_START_REQ( set_window_info )
2015 req->handle = hwnd;
2016 req->extra_offset = -1;
2017 switch(offset)
2019 case GWL_STYLE:
2020 req->flags = SET_WIN_STYLE;
2021 req->style = newval;
2022 break;
2023 case GWL_EXSTYLE:
2024 req->flags = SET_WIN_EXSTYLE;
2025 /* WS_EX_TOPMOST can only be changed through SetWindowPos */
2026 newval = (newval & ~WS_EX_TOPMOST) | (wndPtr->dwExStyle & WS_EX_TOPMOST);
2027 req->ex_style = newval;
2028 break;
2029 case GWLP_ID:
2030 req->flags = SET_WIN_ID;
2031 req->id = newval;
2032 break;
2033 case GWLP_HINSTANCE:
2034 req->flags = SET_WIN_INSTANCE;
2035 req->instance = (void *)newval;
2036 break;
2037 case GWLP_WNDPROC:
2038 req->flags = SET_WIN_UNICODE;
2039 req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
2040 break;
2041 case GWLP_USERDATA:
2042 req->flags = SET_WIN_USERDATA;
2043 req->user_data = newval;
2044 break;
2045 default:
2046 req->flags = SET_WIN_EXTRA;
2047 req->extra_offset = offset;
2048 req->extra_size = size;
2049 set_win_data( &req->extra_value, newval, size );
2051 if ((ok = !wine_server_call_err( req )))
2053 switch(offset)
2055 case GWL_STYLE:
2056 wndPtr->dwStyle = newval;
2057 retval = reply->old_style;
2058 break;
2059 case GWL_EXSTYLE:
2060 wndPtr->dwExStyle = newval;
2061 retval = reply->old_ex_style;
2062 break;
2063 case GWLP_ID:
2064 wndPtr->wIDmenu = newval;
2065 retval = reply->old_id;
2066 break;
2067 case GWLP_HINSTANCE:
2068 wndPtr->hInstance = (HINSTANCE)newval;
2069 retval = (ULONG_PTR)reply->old_instance;
2070 break;
2071 case GWLP_WNDPROC:
2072 break;
2073 case GWLP_USERDATA:
2074 wndPtr->userdata = newval;
2075 retval = reply->old_user_data;
2076 break;
2077 default:
2078 retval = get_win_data( (char *)wndPtr->wExtra + offset, size );
2079 set_win_data( (char *)wndPtr->wExtra + offset, newval, size );
2080 break;
2084 SERVER_END_REQ;
2085 WIN_ReleasePtr( wndPtr );
2087 if (!ok) return 0;
2089 if (offset == GWL_STYLE) USER_Driver->pSetWindowStyle( hwnd, retval );
2091 if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2092 SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2094 return retval;
2098 /**********************************************************************
2099 * GetWindowLong (USER.135)
2101 LONG WINAPI GetWindowLong16( HWND16 hwnd, INT16 offset )
2103 WND *wndPtr;
2104 LONG_PTR retvalue;
2105 BOOL is_winproc = (offset == GWLP_WNDPROC);
2107 if (offset >= 0)
2109 if (!(wndPtr = WIN_GetPtr( WIN_Handle32(hwnd) )))
2111 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2112 return 0;
2114 if (wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
2116 if (offset > (int)(wndPtr->cbWndExtra - sizeof(LONG)))
2119 * Some programs try to access last element from 16 bit
2120 * code using illegal offset value. Hopefully this is
2121 * what those programs really expect.
2123 if (wndPtr->cbWndExtra >= 4 && offset == wndPtr->cbWndExtra - sizeof(WORD))
2125 INT offset2 = wndPtr->cbWndExtra - sizeof(LONG);
2126 ERR( "- replaced invalid offset %d with %d\n", offset, offset2 );
2127 offset = offset2;
2129 else
2131 WARN("Invalid offset %d\n", offset );
2132 WIN_ReleasePtr( wndPtr );
2133 SetLastError( ERROR_INVALID_INDEX );
2134 return 0;
2137 is_winproc = ((offset == DWLP_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG));
2138 WIN_ReleasePtr( wndPtr );
2141 retvalue = GetWindowLongA( WIN_Handle32(hwnd), offset );
2142 if (is_winproc) retvalue = (LONG_PTR)WINPROC_GetProc16( (WNDPROC)retvalue, FALSE );
2143 return retvalue;
2147 /**********************************************************************
2148 * GetWindowWord (USER32.@)
2150 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
2152 switch(offset)
2154 case GWLP_ID:
2155 case GWLP_HINSTANCE:
2156 case GWLP_HWNDPARENT:
2157 break;
2158 default:
2159 if (offset < 0)
2161 WARN("Invalid offset %d\n", offset );
2162 SetLastError( ERROR_INVALID_INDEX );
2163 return 0;
2165 break;
2167 return WIN_GetWindowLong( hwnd, offset, sizeof(WORD), FALSE );
2171 /**********************************************************************
2172 * GetWindowLongA (USER32.@)
2174 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2176 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), FALSE );
2180 /**********************************************************************
2181 * GetWindowLongW (USER32.@)
2183 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2185 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), TRUE );
2189 /**********************************************************************
2190 * SetWindowLong (USER.136)
2192 LONG WINAPI SetWindowLong16( HWND16 hwnd, INT16 offset, LONG newval )
2194 WND *wndPtr;
2195 BOOL is_winproc = (offset == GWLP_WNDPROC);
2197 if (offset == DWLP_DLGPROC)
2199 if (!(wndPtr = WIN_GetPtr( WIN_Handle32(hwnd) )))
2201 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2202 return 0;
2204 if (wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
2206 is_winproc = ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
2207 (wndPtr->flags & WIN_ISDIALOG));
2208 WIN_ReleasePtr( wndPtr );
2212 if (is_winproc)
2214 WNDPROC new_proc = WINPROC_AllocProc16( (WNDPROC16)newval );
2215 WNDPROC old_proc = (WNDPROC)SetWindowLongPtrA( WIN_Handle32(hwnd), offset, (LONG_PTR)new_proc );
2216 return (LONG)WINPROC_GetProc16( old_proc, FALSE );
2218 else return SetWindowLongA( WIN_Handle32(hwnd), offset, newval );
2222 /**********************************************************************
2223 * SetWindowWord (USER32.@)
2225 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
2227 switch(offset)
2229 case GWLP_ID:
2230 case GWLP_HINSTANCE:
2231 case GWLP_HWNDPARENT:
2232 break;
2233 default:
2234 if (offset < 0)
2236 WARN("Invalid offset %d\n", offset );
2237 SetLastError( ERROR_INVALID_INDEX );
2238 return 0;
2240 break;
2242 return WIN_SetWindowLong( hwnd, offset, sizeof(WORD), newval, FALSE );
2246 /**********************************************************************
2247 * SetWindowLongA (USER32.@)
2249 * See SetWindowLongW.
2251 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2253 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, FALSE );
2257 /**********************************************************************
2258 * SetWindowLongW (USER32.@) Set window attribute
2260 * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2261 * value in a window's extra memory.
2263 * The _hwnd_ parameter specifies the window. is the handle to a
2264 * window that has extra memory. The _newval_ parameter contains the
2265 * new attribute or extra memory value. If positive, the _offset_
2266 * parameter is the byte-addressed location in the window's extra
2267 * memory to set. If negative, _offset_ specifies the window
2268 * attribute to set, and should be one of the following values:
2270 * GWL_EXSTYLE The window's extended window style
2272 * GWL_STYLE The window's window style.
2274 * GWLP_WNDPROC Pointer to the window's window procedure.
2276 * GWLP_HINSTANCE The window's pplication instance handle.
2278 * GWLP_ID The window's identifier.
2280 * GWLP_USERDATA The window's user-specified data.
2282 * If the window is a dialog box, the _offset_ parameter can be one of
2283 * the following values:
2285 * DWLP_DLGPROC The address of the window's dialog box procedure.
2287 * DWLP_MSGRESULT The return value of a message
2288 * that the dialog box procedure processed.
2290 * DWLP_USER Application specific information.
2292 * RETURNS
2294 * If successful, returns the previous value located at _offset_. Otherwise,
2295 * returns 0.
2297 * NOTES
2299 * Extra memory for a window class is specified by a nonzero cbWndExtra
2300 * parameter of the WNDCLASS structure passed to RegisterClass() at the
2301 * time of class creation.
2303 * Using GWL_WNDPROC to set a new window procedure effectively creates
2304 * a window subclass. Use CallWindowProc() in the new windows procedure
2305 * to pass messages to the superclass's window procedure.
2307 * The user data is reserved for use by the application which created
2308 * the window.
2310 * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2311 * instead, call the EnableWindow() function to change the window's
2312 * disabled state.
2314 * Do not use GWL_HWNDPARENT to reset the window's parent, use
2315 * SetParent() instead.
2317 * Win95:
2318 * When offset is GWL_STYLE and the calling app's ver is 4.0,
2319 * it sends WM_STYLECHANGING before changing the settings
2320 * and WM_STYLECHANGED afterwards.
2321 * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2323 LONG WINAPI SetWindowLongW(
2324 HWND hwnd, /* [in] window to alter */
2325 INT offset, /* [in] offset, in bytes, of location to alter */
2326 LONG newval /* [in] new value of location */
2328 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, TRUE );
2332 /*******************************************************************
2333 * GetWindowTextA (USER32.@)
2335 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2337 WCHAR *buffer;
2339 if (!lpString) return 0;
2341 if (WIN_IsCurrentProcess( hwnd ))
2342 return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2344 /* when window belongs to other process, don't send a message */
2345 if (nMaxCount <= 0) return 0;
2346 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2347 get_server_window_text( hwnd, buffer, nMaxCount );
2348 if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2349 lpString[nMaxCount-1] = 0;
2350 HeapFree( GetProcessHeap(), 0, buffer );
2351 return strlen(lpString);
2355 /*******************************************************************
2356 * InternalGetWindowText (USER32.@)
2358 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2360 WND *win;
2362 if (nMaxCount <= 0) return 0;
2363 if (!(win = WIN_GetPtr( hwnd ))) return 0;
2364 if (win == WND_DESKTOP) lpString[0] = 0;
2365 else if (win != WND_OTHER_PROCESS)
2367 if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2368 else lpString[0] = 0;
2369 WIN_ReleasePtr( win );
2371 else
2373 get_server_window_text( hwnd, lpString, nMaxCount );
2375 return strlenW(lpString);
2379 /*******************************************************************
2380 * GetWindowTextW (USER32.@)
2382 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2384 if (!lpString) return 0;
2386 if (WIN_IsCurrentProcess( hwnd ))
2387 return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2389 /* when window belongs to other process, don't send a message */
2390 if (nMaxCount <= 0) return 0;
2391 get_server_window_text( hwnd, lpString, nMaxCount );
2392 return strlenW(lpString);
2396 /*******************************************************************
2397 * SetWindowTextA (USER32.@)
2398 * SetWindowText (USER32.@)
2400 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2402 if (is_broadcast(hwnd))
2404 SetLastError( ERROR_INVALID_PARAMETER );
2405 return FALSE;
2407 if (!WIN_IsCurrentProcess( hwnd ))
2408 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2409 debugstr_a(lpString), hwnd );
2410 return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2414 /*******************************************************************
2415 * SetWindowTextW (USER32.@)
2417 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2419 if (is_broadcast(hwnd))
2421 SetLastError( ERROR_INVALID_PARAMETER );
2422 return FALSE;
2424 if (!WIN_IsCurrentProcess( hwnd ))
2425 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2426 debugstr_w(lpString), hwnd );
2427 return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2431 /*******************************************************************
2432 * GetWindowTextLengthA (USER32.@)
2434 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2436 return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2439 /*******************************************************************
2440 * GetWindowTextLengthW (USER32.@)
2442 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2444 return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2448 /*******************************************************************
2449 * IsWindow (USER32.@)
2451 BOOL WINAPI IsWindow( HWND hwnd )
2453 WND *ptr;
2454 BOOL ret;
2456 if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2457 if (ptr == WND_DESKTOP) return TRUE;
2459 if (ptr != WND_OTHER_PROCESS)
2461 WIN_ReleasePtr( ptr );
2462 return TRUE;
2465 /* check other processes */
2466 SERVER_START_REQ( get_window_info )
2468 req->handle = hwnd;
2469 ret = !wine_server_call_err( req );
2471 SERVER_END_REQ;
2472 return ret;
2476 /***********************************************************************
2477 * GetWindowThreadProcessId (USER32.@)
2479 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2481 WND *ptr;
2482 DWORD tid = 0;
2484 if (!(ptr = WIN_GetPtr( hwnd )))
2486 SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2487 return 0;
2490 if (ptr != WND_OTHER_PROCESS && ptr != WND_DESKTOP)
2492 /* got a valid window */
2493 tid = ptr->tid;
2494 if (process) *process = GetCurrentProcessId();
2495 WIN_ReleasePtr( ptr );
2496 return tid;
2499 /* check other processes */
2500 SERVER_START_REQ( get_window_info )
2502 req->handle = hwnd;
2503 if (!wine_server_call_err( req ))
2505 tid = (DWORD)reply->tid;
2506 if (process) *process = (DWORD)reply->pid;
2509 SERVER_END_REQ;
2510 return tid;
2514 /*****************************************************************
2515 * GetParent (USER32.@)
2517 HWND WINAPI GetParent( HWND hwnd )
2519 WND *wndPtr;
2520 HWND retvalue = 0;
2522 if (!(wndPtr = WIN_GetPtr( hwnd )))
2524 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2525 return 0;
2527 if (wndPtr == WND_DESKTOP) return 0;
2528 if (wndPtr == WND_OTHER_PROCESS)
2530 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2531 if (style & (WS_POPUP | WS_CHILD))
2533 SERVER_START_REQ( get_window_tree )
2535 req->handle = hwnd;
2536 if (!wine_server_call_err( req ))
2538 if (style & WS_POPUP) retvalue = reply->owner;
2539 else if (style & WS_CHILD) retvalue = reply->parent;
2542 SERVER_END_REQ;
2545 else
2547 if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2548 else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2549 WIN_ReleasePtr( wndPtr );
2551 return retvalue;
2555 /*****************************************************************
2556 * GetAncestor (USER32.@)
2558 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2560 WND *win;
2561 HWND *list, ret = 0;
2563 switch(type)
2565 case GA_PARENT:
2566 if (!(win = WIN_GetPtr( hwnd )))
2568 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2569 return 0;
2571 if (win == WND_DESKTOP) return 0;
2572 if (win != WND_OTHER_PROCESS)
2574 ret = win->parent;
2575 WIN_ReleasePtr( win );
2577 else /* need to query the server */
2579 SERVER_START_REQ( get_window_tree )
2581 req->handle = hwnd;
2582 if (!wine_server_call_err( req )) ret = reply->parent;
2584 SERVER_END_REQ;
2586 break;
2588 case GA_ROOT:
2589 if (!(list = list_window_parents( hwnd ))) return 0;
2591 if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd ); /* top-level window */
2592 else
2594 int count = 2;
2595 while (list[count]) count++;
2596 ret = list[count - 2]; /* get the one before the desktop */
2598 HeapFree( GetProcessHeap(), 0, list );
2599 break;
2601 case GA_ROOTOWNER:
2602 if ((ret = WIN_GetFullHandle( hwnd )) == GetDesktopWindow()) return 0;
2603 for (;;)
2605 HWND parent = GetParent( ret );
2606 if (!parent) break;
2607 ret = parent;
2609 break;
2611 return ret;
2615 /*****************************************************************
2616 * SetParent (USER32.@)
2618 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2620 HWND full_handle;
2621 HWND old_parent = 0;
2622 BOOL was_visible;
2623 WND *wndPtr;
2624 BOOL ret;
2626 if (is_broadcast(hwnd) || is_broadcast(parent))
2628 SetLastError(ERROR_INVALID_PARAMETER);
2629 return 0;
2632 if (!parent) parent = GetDesktopWindow();
2633 else parent = WIN_GetFullHandle( parent );
2635 if (!IsWindow( parent ))
2637 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2638 return 0;
2641 /* Some applications try to set a child as a parent */
2642 if (IsChild(hwnd, parent))
2644 SetLastError( ERROR_INVALID_PARAMETER );
2645 return 0;
2648 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2649 return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2651 /* Windows hides the window first, then shows it again
2652 * including the WM_SHOWWINDOW messages and all */
2653 was_visible = ShowWindow( hwnd, SW_HIDE );
2655 wndPtr = WIN_GetPtr( hwnd );
2656 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
2658 SERVER_START_REQ( set_parent )
2660 req->handle = hwnd;
2661 req->parent = parent;
2662 if ((ret = !wine_server_call( req )))
2664 old_parent = reply->old_parent;
2665 wndPtr->parent = parent = reply->full_parent;
2669 SERVER_END_REQ;
2670 WIN_ReleasePtr( wndPtr );
2671 if (!ret) return 0;
2673 USER_Driver->pSetParent( full_handle, parent, old_parent );
2675 /* SetParent additionally needs to make hwnd the topmost window
2676 in the x-order and send the expected WM_WINDOWPOSCHANGING and
2677 WM_WINDOWPOSCHANGED notification messages.
2679 SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0,
2680 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | (was_visible ? SWP_SHOWWINDOW : 0) );
2681 /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
2682 * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
2684 return old_parent;
2688 /*******************************************************************
2689 * IsChild (USER32.@)
2691 BOOL WINAPI IsChild( HWND parent, HWND child )
2693 HWND *list = list_window_parents( child );
2694 int i;
2695 BOOL ret;
2697 if (!list) return FALSE;
2698 parent = WIN_GetFullHandle( parent );
2699 for (i = 0; list[i]; i++) if (list[i] == parent) break;
2700 ret = list[i] && list[i+1];
2701 HeapFree( GetProcessHeap(), 0, list );
2702 return ret;
2706 /***********************************************************************
2707 * IsWindowVisible (USER32.@)
2709 BOOL WINAPI IsWindowVisible( HWND hwnd )
2711 HWND *list;
2712 BOOL retval = TRUE;
2713 int i;
2715 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2716 if (!(list = list_window_parents( hwnd ))) return TRUE;
2717 if (list[0] && list[1]) /* desktop window is considered always visible so we don't check it */
2719 for (i = 0; list[i+1]; i++)
2720 if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2721 retval = !list[i+1];
2723 HeapFree( GetProcessHeap(), 0, list );
2724 return retval;
2728 /***********************************************************************
2729 * WIN_IsWindowDrawable
2731 * hwnd is drawable when it is visible, all parents are not
2732 * minimized, and it is itself not minimized unless we are
2733 * trying to draw its default class icon.
2735 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2737 HWND *list;
2738 BOOL retval = TRUE;
2739 int i;
2740 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2742 if (!(style & WS_VISIBLE)) return FALSE;
2743 if ((style & WS_MINIMIZE) && icon && GetClassLongPtrW( hwnd, GCLP_HICON )) return FALSE;
2745 if (!(list = list_window_parents( hwnd ))) return TRUE;
2746 if (list[0] && list[1]) /* desktop window is considered always visible so we don't check it */
2748 for (i = 0; list[i+1]; i++)
2749 if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2750 break;
2751 retval = !list[i+1];
2753 HeapFree( GetProcessHeap(), 0, list );
2754 return retval;
2758 /*******************************************************************
2759 * GetTopWindow (USER32.@)
2761 HWND WINAPI GetTopWindow( HWND hwnd )
2763 if (!hwnd) hwnd = GetDesktopWindow();
2764 return GetWindow( hwnd, GW_CHILD );
2768 /*******************************************************************
2769 * GetWindow (USER32.@)
2771 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2773 HWND retval = 0;
2775 if (rel == GW_OWNER) /* this one may be available locally */
2777 WND *wndPtr = WIN_GetPtr( hwnd );
2778 if (!wndPtr)
2780 SetLastError( ERROR_INVALID_HANDLE );
2781 return 0;
2783 if (wndPtr == WND_DESKTOP) return 0;
2784 if (wndPtr != WND_OTHER_PROCESS)
2786 retval = wndPtr->owner;
2787 WIN_ReleasePtr( wndPtr );
2788 return retval;
2790 /* else fall through to server call */
2793 SERVER_START_REQ( get_window_tree )
2795 req->handle = hwnd;
2796 if (!wine_server_call_err( req ))
2798 switch(rel)
2800 case GW_HWNDFIRST:
2801 retval = reply->first_sibling;
2802 break;
2803 case GW_HWNDLAST:
2804 retval = reply->last_sibling;
2805 break;
2806 case GW_HWNDNEXT:
2807 retval = reply->next_sibling;
2808 break;
2809 case GW_HWNDPREV:
2810 retval = reply->prev_sibling;
2811 break;
2812 case GW_OWNER:
2813 retval = reply->owner;
2814 break;
2815 case GW_CHILD:
2816 retval = reply->first_child;
2817 break;
2821 SERVER_END_REQ;
2822 return retval;
2826 /*******************************************************************
2827 * ShowOwnedPopups (USER32.@)
2829 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2831 int count = 0;
2832 WND *pWnd;
2833 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2835 if (!win_array) return TRUE;
2837 while (win_array[count]) count++;
2838 while (--count >= 0)
2840 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2841 if (!(pWnd = WIN_GetPtr( win_array[count] ))) continue;
2842 if (pWnd == WND_OTHER_PROCESS) continue;
2843 if (fShow)
2845 if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2847 WIN_ReleasePtr( pWnd );
2848 /* In Windows, ShowOwnedPopups(TRUE) generates
2849 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
2850 * regardless of the state of the owner
2852 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
2853 continue;
2856 else
2858 if (pWnd->dwStyle & WS_VISIBLE)
2860 WIN_ReleasePtr( pWnd );
2861 /* In Windows, ShowOwnedPopups(FALSE) generates
2862 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
2863 * regardless of the state of the owner
2865 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
2866 continue;
2869 WIN_ReleasePtr( pWnd );
2871 HeapFree( GetProcessHeap(), 0, win_array );
2872 return TRUE;
2876 /*******************************************************************
2877 * GetLastActivePopup (USER32.@)
2879 HWND WINAPI GetLastActivePopup( HWND hwnd )
2881 HWND retval = hwnd;
2883 SERVER_START_REQ( get_window_info )
2885 req->handle = hwnd;
2886 if (!wine_server_call_err( req )) retval = reply->last_active;
2888 SERVER_END_REQ;
2889 return retval;
2893 /*******************************************************************
2894 * WIN_ListChildren
2896 * Build an array of the children of a given window. The array must be
2897 * freed with HeapFree. Returns NULL when no windows are found.
2899 HWND *WIN_ListChildren( HWND hwnd )
2901 return list_window_children( 0, hwnd, NULL, 0 );
2905 /*******************************************************************
2906 * EnumWindows (USER32.@)
2908 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
2910 HWND *list;
2911 BOOL ret = TRUE;
2912 int i;
2914 USER_CheckNotLock();
2916 /* We have to build a list of all windows first, to avoid */
2917 /* unpleasant side-effects, for instance if the callback */
2918 /* function changes the Z-order of the windows. */
2920 if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
2922 /* Now call the callback function for every window */
2924 for (i = 0; list[i]; i++)
2926 /* Make sure that the window still exists */
2927 if (!IsWindow( list[i] )) continue;
2928 if (!(ret = lpEnumFunc( list[i], lParam ))) break;
2930 HeapFree( GetProcessHeap(), 0, list );
2931 return ret;
2935 /**********************************************************************
2936 * EnumThreadWindows (USER32.@)
2938 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
2940 HWND *list;
2941 int i;
2943 USER_CheckNotLock();
2945 if (!(list = list_window_children( 0, GetDesktopWindow(), NULL, id ))) return TRUE;
2947 /* Now call the callback function for every window */
2949 for (i = 0; list[i]; i++)
2950 if (!func( list[i], lParam )) break;
2951 HeapFree( GetProcessHeap(), 0, list );
2952 return TRUE;
2956 /***********************************************************************
2957 * EnumDesktopWindows (USER32.@)
2959 BOOL WINAPI EnumDesktopWindows( HDESK desktop, WNDENUMPROC func, LPARAM lparam )
2961 HWND *list;
2962 int i;
2964 USER_CheckNotLock();
2966 if (!(list = list_window_children( desktop, 0, NULL, 0 ))) return TRUE;
2968 for (i = 0; list[i]; i++)
2969 if (!func( list[i], lparam )) break;
2970 HeapFree( GetProcessHeap(), 0, list );
2971 return TRUE;
2975 /**********************************************************************
2976 * WIN_EnumChildWindows
2978 * Helper function for EnumChildWindows().
2980 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
2982 HWND *childList;
2983 BOOL ret = FALSE;
2985 for ( ; *list; list++)
2987 /* Make sure that the window still exists */
2988 if (!IsWindow( *list )) continue;
2989 /* Build children list first */
2990 childList = WIN_ListChildren( *list );
2992 ret = func( *list, lParam );
2994 if (childList)
2996 if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
2997 HeapFree( GetProcessHeap(), 0, childList );
2999 if (!ret) return FALSE;
3001 return TRUE;
3005 /**********************************************************************
3006 * EnumChildWindows (USER32.@)
3008 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
3010 HWND *list;
3011 BOOL ret;
3013 USER_CheckNotLock();
3015 if (!(list = WIN_ListChildren( parent ))) return FALSE;
3016 ret = WIN_EnumChildWindows( list, func, lParam );
3017 HeapFree( GetProcessHeap(), 0, list );
3018 return ret;
3022 /*******************************************************************
3023 * AnyPopup (USER.52)
3025 BOOL16 WINAPI AnyPopup16(void)
3027 return AnyPopup();
3031 /*******************************************************************
3032 * AnyPopup (USER32.@)
3034 BOOL WINAPI AnyPopup(void)
3036 int i;
3037 BOOL retvalue;
3038 HWND *list = WIN_ListChildren( GetDesktopWindow() );
3040 if (!list) return FALSE;
3041 for (i = 0; list[i]; i++)
3043 if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
3045 retvalue = (list[i] != 0);
3046 HeapFree( GetProcessHeap(), 0, list );
3047 return retvalue;
3051 /*******************************************************************
3052 * FlashWindow (USER32.@)
3054 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3056 WND *wndPtr;
3058 TRACE("%p\n", hWnd);
3060 if (IsIconic( hWnd ))
3062 RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
3064 wndPtr = WIN_GetPtr(hWnd);
3065 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3066 if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
3068 wndPtr->flags |= WIN_NCACTIVATED;
3070 else
3072 wndPtr->flags &= ~WIN_NCACTIVATED;
3074 WIN_ReleasePtr( wndPtr );
3075 return TRUE;
3077 else
3079 WPARAM wparam;
3081 wndPtr = WIN_GetPtr(hWnd);
3082 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3083 hWnd = wndPtr->hwndSelf; /* make it a full handle */
3085 if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3086 else wparam = (hWnd == GetForegroundWindow());
3088 WIN_ReleasePtr( wndPtr );
3089 SendMessageW( hWnd, WM_NCACTIVATE, wparam, (LPARAM)0 );
3090 return wparam;
3094 /*******************************************************************
3095 * FlashWindowEx (USER32.@)
3097 BOOL WINAPI FlashWindowEx( PFLASHWINFO pfwi )
3099 FIXME("%p\n", pfwi);
3100 return TRUE;
3103 /*******************************************************************
3104 * GetWindowContextHelpId (USER32.@)
3106 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3108 DWORD retval;
3109 WND *wnd = WIN_GetPtr( hwnd );
3110 if (!wnd || wnd == WND_DESKTOP) return 0;
3111 if (wnd == WND_OTHER_PROCESS)
3113 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3114 return 0;
3116 retval = wnd->helpContext;
3117 WIN_ReleasePtr( wnd );
3118 return retval;
3122 /*******************************************************************
3123 * SetWindowContextHelpId (USER32.@)
3125 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3127 WND *wnd = WIN_GetPtr( hwnd );
3128 if (!wnd || wnd == WND_DESKTOP) return FALSE;
3129 if (wnd == WND_OTHER_PROCESS)
3131 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3132 return 0;
3134 wnd->helpContext = id;
3135 WIN_ReleasePtr( wnd );
3136 return TRUE;
3140 /*******************************************************************
3141 * DragDetect (USER32.@)
3143 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3145 MSG msg;
3146 RECT rect;
3147 WORD wDragWidth = GetSystemMetrics(SM_CXDRAG);
3148 WORD wDragHeight= GetSystemMetrics(SM_CYDRAG);
3150 rect.left = pt.x - wDragWidth;
3151 rect.right = pt.x + wDragWidth;
3153 rect.top = pt.y - wDragHeight;
3154 rect.bottom = pt.y + wDragHeight;
3156 SetCapture(hWnd);
3158 while(1)
3160 while (PeekMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ))
3162 if( msg.message == WM_LBUTTONUP )
3164 ReleaseCapture();
3165 return 0;
3167 if( msg.message == WM_MOUSEMOVE )
3169 POINT tmp;
3170 tmp.x = (short)LOWORD(msg.lParam);
3171 tmp.y = (short)HIWORD(msg.lParam);
3172 if( !PtInRect( &rect, tmp ))
3174 ReleaseCapture();
3175 return 1;
3179 WaitMessage();
3181 return 0;
3184 /******************************************************************************
3185 * GetWindowModuleFileNameA (USER32.@)
3187 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR module, UINT size )
3189 WND *win;
3190 HINSTANCE hinst;
3192 TRACE( "%p, %p, %u\n", hwnd, module, size );
3194 win = WIN_GetPtr( hwnd );
3195 if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3197 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3198 return 0;
3200 hinst = win->hInstance;
3201 WIN_ReleasePtr( win );
3203 return GetModuleFileNameA( hinst, module, size );
3206 /******************************************************************************
3207 * GetWindowModuleFileNameW (USER32.@)
3209 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR module, UINT size )
3211 WND *win;
3212 HINSTANCE hinst;
3214 TRACE( "%p, %p, %u\n", hwnd, module, size );
3216 win = WIN_GetPtr( hwnd );
3217 if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3219 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3220 return 0;
3222 hinst = win->hInstance;
3223 WIN_ReleasePtr( win );
3225 return GetModuleFileNameW( hinst, module, size );
3228 /******************************************************************************
3229 * GetWindowInfo (USER32.@)
3231 * Note: tests show that Windows doesn't check cbSize of the structure.
3233 BOOL WINAPI GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3235 if (!pwi) return FALSE;
3236 if (!IsWindow(hwnd)) return FALSE;
3238 GetWindowRect(hwnd, &pwi->rcWindow);
3239 GetClientRect(hwnd, &pwi->rcClient);
3240 /* translate to screen coordinates */
3241 MapWindowPoints(hwnd, 0, (LPPOINT)&pwi->rcClient, 2);
3243 pwi->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
3244 pwi->dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3245 pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3247 pwi->cxWindowBorders = pwi->rcClient.left - pwi->rcWindow.left;
3248 pwi->cyWindowBorders = pwi->rcWindow.bottom - pwi->rcClient.bottom;
3250 pwi->atomWindowType = GetClassLongW( hwnd, GCW_ATOM );
3251 pwi->wCreatorVersion = 0x0400;
3253 return TRUE;
3256 /******************************************************************************
3257 * SwitchDesktop (USER32.@)
3259 * NOTES: Sets the current input or interactive desktop.
3261 BOOL WINAPI SwitchDesktop( HDESK hDesktop)
3263 FIXME("SwitchDesktop(hwnd %p) stub!\n", hDesktop);
3264 return TRUE;
3267 /*****************************************************************************
3268 * SetLayeredWindowAttributes (USER32.@)
3270 BOOL WINAPI SetLayeredWindowAttributes( HWND hWnd, COLORREF rgbKey,
3271 BYTE bAlpha, DWORD dwFlags )
3273 FIXME("(%p,0x%.8x,%d,%d): stub!\n", hWnd, rgbKey, bAlpha, dwFlags);
3274 return TRUE;
3277 /*****************************************************************************
3278 * GetLayeredWindowAttributes (USER32.@)
3280 BOOL WINAPI GetLayeredWindowAttributes( HWND hWnd, COLORREF *prgbKey,
3281 BYTE *pbAlpha, DWORD *pdwFlags )
3283 FIXME("(%p,%p,%p,%p): stub!\n", hWnd, prgbKey, pbAlpha, pdwFlags);
3284 return FALSE;
3287 /*****************************************************************************
3288 * UpdateLayeredWindow (USER32.@)
3290 BOOL WINAPI UpdateLayeredWindow( HWND hwnd, HDC hdcDst, POINT *pptDst, SIZE *psize,
3291 HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend,
3292 DWORD dwFlags)
3294 static int once;
3295 if (!once)
3297 once = 1;
3298 FIXME("(%p,%p,%p,%p,%p,%p,0x%08x,%p,%d): stub!\n",
3299 hwnd, hdcDst, pptDst, psize, hdcSrc, pptSrc, crKey, pblend, dwFlags);
3301 return 0;
3304 /* 64bit versions */
3306 #ifdef GetWindowLongPtrW
3307 #undef GetWindowLongPtrW
3308 #endif
3310 #ifdef GetWindowLongPtrA
3311 #undef GetWindowLongPtrA
3312 #endif
3314 #ifdef SetWindowLongPtrW
3315 #undef SetWindowLongPtrW
3316 #endif
3318 #ifdef SetWindowLongPtrA
3319 #undef SetWindowLongPtrA
3320 #endif
3322 /*****************************************************************************
3323 * GetWindowLongPtrW (USER32.@)
3325 LONG_PTR WINAPI GetWindowLongPtrW( HWND hwnd, INT offset )
3327 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), TRUE );
3330 /*****************************************************************************
3331 * GetWindowLongPtrA (USER32.@)
3333 LONG_PTR WINAPI GetWindowLongPtrA( HWND hwnd, INT offset )
3335 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), FALSE );
3338 /*****************************************************************************
3339 * SetWindowLongPtrW (USER32.@)
3341 LONG_PTR WINAPI SetWindowLongPtrW( HWND hwnd, INT offset, LONG_PTR newval )
3343 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, TRUE );
3346 /*****************************************************************************
3347 * SetWindowLongPtrA (USER32.@)
3349 LONG_PTR WINAPI SetWindowLongPtrA( HWND hwnd, INT offset, LONG_PTR newval )
3351 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, FALSE );