mshtml: Better timer handling.
[wine/wine-jacek.git] / dlls / user32 / win.c
blob8214fd50e36e741b8be455375d893f808323ebe1
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 (!thread_info->desktop) thread_info->desktop = full_parent ? full_parent : handle;
154 else assert( full_parent == thread_info->desktop );
155 if (full_parent && !USER_Driver->pCreateDesktopWindow( thread_info->desktop ))
156 ERR( "failed to create desktop window\n" );
159 USER_Lock();
161 index = USER_HANDLE_TO_INDEX(handle);
162 assert( index < NB_USER_HANDLES );
163 user_handles[index] = win;
164 win->hwndSelf = handle;
165 win->parent = full_parent;
166 win->owner = full_owner;
167 win->class = class;
168 win->winproc = get_class_winproc( class );
169 win->dwMagic = WND_MAGIC;
170 win->cbWndExtra = extra_bytes;
171 if (WINPROC_IsUnicode( win->winproc, unicode )) win->flags |= WIN_ISUNICODE;
172 return win;
176 /***********************************************************************
177 * free_window_handle
179 * Free a window handle.
181 static WND *free_window_handle( HWND hwnd )
183 WND *ptr;
184 WORD index = USER_HANDLE_TO_INDEX(hwnd);
186 if (index >= NB_USER_HANDLES) return NULL;
187 USER_Lock();
188 if ((ptr = user_handles[index]))
190 SERVER_START_REQ( destroy_window )
192 req->handle = hwnd;
193 if (!wine_server_call_err( req ))
195 user_handles[index] = NULL;
196 ptr->dwMagic = 0;
198 else
199 ptr = NULL;
201 SERVER_END_REQ;
203 USER_Unlock();
204 HeapFree( GetProcessHeap(), 0, ptr );
205 return ptr;
209 /*******************************************************************
210 * list_window_children
212 * Build an array of the children of a given window. The array must be
213 * freed with HeapFree. Returns NULL when no windows are found.
215 static HWND *list_window_children( HDESK desktop, HWND hwnd, LPCWSTR class, DWORD tid )
217 HWND *list;
218 int size = 128;
220 for (;;)
222 int count = 0;
224 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) break;
226 SERVER_START_REQ( get_window_children )
228 req->desktop = desktop;
229 req->parent = hwnd;
230 req->tid = tid;
231 if (!(req->atom = get_int_atom_value( class )) && class)
232 wine_server_add_data( req, class, strlenW(class)*sizeof(WCHAR) );
233 wine_server_set_reply( req, list, (size-1) * sizeof(HWND) );
234 if (!wine_server_call( req )) count = reply->count;
236 SERVER_END_REQ;
237 if (count && count < size)
239 list[count] = 0;
240 return list;
242 HeapFree( GetProcessHeap(), 0, list );
243 if (!count) break;
244 size = count + 1; /* restart with a large enough buffer */
246 return NULL;
250 /*******************************************************************
251 * list_window_parents
253 * Build an array of all parents of a given window, starting with
254 * the immediate parent. The array must be freed with HeapFree.
256 static HWND *list_window_parents( HWND hwnd )
258 WND *win;
259 HWND current, *list;
260 int pos = 0, size = 16, count = 0;
262 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
264 current = hwnd;
265 for (;;)
267 if (!(win = WIN_GetPtr( current ))) goto empty;
268 if (win == WND_OTHER_PROCESS) break; /* need to do it the hard way */
269 if (win == WND_DESKTOP)
271 if (!pos) goto empty;
272 list[pos] = 0;
273 return list;
275 list[pos] = current = win->parent;
276 WIN_ReleasePtr( win );
277 if (!current) return list;
278 if (++pos == size - 1)
280 /* need to grow the list */
281 HWND *new_list = HeapReAlloc( GetProcessHeap(), 0, list, (size+16) * sizeof(HWND) );
282 if (!new_list) goto empty;
283 list = new_list;
284 size += 16;
288 /* at least one parent belongs to another process, have to query the server */
290 for (;;)
292 count = 0;
293 SERVER_START_REQ( get_window_parents )
295 req->handle = hwnd;
296 wine_server_set_reply( req, list, (size-1) * sizeof(HWND) );
297 if (!wine_server_call( req )) count = reply->count;
299 SERVER_END_REQ;
300 if (!count) goto empty;
301 if (size > count)
303 list[count] = 0;
304 return list;
306 HeapFree( GetProcessHeap(), 0, list );
307 size = count + 1;
308 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
311 empty:
312 HeapFree( GetProcessHeap(), 0, list );
313 return NULL;
317 /*******************************************************************
318 * send_parent_notify
320 static void send_parent_notify( HWND hwnd, UINT msg )
322 if ((GetWindowLongW( hwnd, GWL_STYLE ) & (WS_CHILD | WS_POPUP)) == WS_CHILD &&
323 !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOPARENTNOTIFY))
325 HWND parent = GetParent(hwnd);
326 if (parent && parent != GetDesktopWindow())
327 SendMessageW( parent, WM_PARENTNOTIFY,
328 MAKEWPARAM( msg, GetWindowLongPtrW( hwnd, GWLP_ID )), (LPARAM)hwnd );
333 /*******************************************************************
334 * get_server_window_text
336 * Retrieve the window text from the server.
338 static void get_server_window_text( HWND hwnd, LPWSTR text, INT count )
340 size_t len = 0;
342 SERVER_START_REQ( get_window_text )
344 req->handle = hwnd;
345 wine_server_set_reply( req, text, (count - 1) * sizeof(WCHAR) );
346 if (!wine_server_call_err( req )) len = wine_server_reply_size(reply);
348 SERVER_END_REQ;
349 text[len / sizeof(WCHAR)] = 0;
353 /***********************************************************************
354 * WIN_GetPtr
356 * Return a pointer to the WND structure if local to the process,
357 * or WND_OTHER_PROCESS if handle may be valid in other process.
358 * If ret value is a valid pointer, it must be released with WIN_ReleasePtr.
360 WND *WIN_GetPtr( HWND hwnd )
362 WND * ptr;
363 WORD index = USER_HANDLE_TO_INDEX(hwnd);
365 if (index >= NB_USER_HANDLES) return NULL;
367 USER_Lock();
368 if ((ptr = user_handles[index]))
370 if (ptr->dwMagic == WND_MAGIC &&
371 (hwnd == ptr->hwndSelf || !HIWORD(hwnd) || HIWORD(hwnd) == 0xffff))
372 return ptr;
373 ptr = NULL;
375 else if (index == USER_HANDLE_TO_INDEX(GetDesktopWindow()))
377 if (hwnd == GetDesktopWindow() || !HIWORD(hwnd) || HIWORD(hwnd) == 0xffff) ptr = WND_DESKTOP;
378 else ptr = NULL;
380 else ptr = WND_OTHER_PROCESS;
381 USER_Unlock();
382 return ptr;
386 /***********************************************************************
387 * WIN_IsCurrentProcess
389 * Check whether a given window belongs to the current process (and return the full handle).
391 HWND WIN_IsCurrentProcess( HWND hwnd )
393 WND *ptr;
394 HWND ret;
396 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
397 ret = ptr->hwndSelf;
398 WIN_ReleasePtr( ptr );
399 return ret;
403 /***********************************************************************
404 * WIN_IsCurrentThread
406 * Check whether a given window belongs to the current thread (and return the full handle).
408 HWND WIN_IsCurrentThread( HWND hwnd )
410 WND *ptr;
411 HWND ret = 0;
413 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
414 if (ptr->tid == GetCurrentThreadId()) ret = ptr->hwndSelf;
415 WIN_ReleasePtr( ptr );
416 return ret;
420 /***********************************************************************
421 * WIN_Handle32
423 * Convert a 16-bit window handle to a full 32-bit handle.
425 HWND WIN_Handle32( HWND16 hwnd16 )
427 WND *ptr;
428 HWND hwnd = (HWND)(ULONG_PTR)hwnd16;
430 if (hwnd16 <= 1 || hwnd16 == 0xffff) return hwnd;
431 /* do sign extension for -2 and -3 */
432 if (hwnd16 >= (HWND16)-3) return (HWND)(LONG_PTR)(INT16)hwnd16;
434 if (!(ptr = WIN_GetPtr( hwnd ))) return hwnd;
436 if (ptr == WND_DESKTOP) return GetDesktopWindow();
438 if (ptr != WND_OTHER_PROCESS)
440 hwnd = ptr->hwndSelf;
441 WIN_ReleasePtr( ptr );
443 else /* may belong to another process */
445 SERVER_START_REQ( get_window_info )
447 req->handle = hwnd;
448 if (!wine_server_call_err( req )) hwnd = reply->full_handle;
450 SERVER_END_REQ;
452 return hwnd;
456 /***********************************************************************
457 * WIN_SetOwner
459 * Change the owner of a window.
461 HWND WIN_SetOwner( HWND hwnd, HWND owner )
463 WND *win = WIN_GetPtr( hwnd );
464 HWND ret = 0;
466 if (!win || win == WND_DESKTOP) return 0;
467 if (win == WND_OTHER_PROCESS)
469 if (IsWindow(hwnd)) ERR( "cannot set owner %p on other process window %p\n", owner, hwnd );
470 return 0;
472 SERVER_START_REQ( set_window_owner )
474 req->handle = hwnd;
475 req->owner = owner;
476 if (!wine_server_call( req ))
478 win->owner = reply->full_owner;
479 ret = reply->prev_owner;
482 SERVER_END_REQ;
483 WIN_ReleasePtr( win );
484 return ret;
488 /***********************************************************************
489 * WIN_SetStyle
491 * Change the style of a window.
493 ULONG WIN_SetStyle( HWND hwnd, ULONG set_bits, ULONG clear_bits )
495 BOOL ok;
496 ULONG new_style, old_style = 0;
497 WND *win = WIN_GetPtr( hwnd );
499 if (!win || win == WND_DESKTOP) return 0;
500 if (win == WND_OTHER_PROCESS)
502 if (IsWindow(hwnd))
503 ERR( "cannot set style %x/%x on other process window %p\n",
504 set_bits, clear_bits, hwnd );
505 return 0;
507 new_style = (win->dwStyle | set_bits) & ~clear_bits;
508 if (new_style == win->dwStyle)
510 WIN_ReleasePtr( win );
511 return new_style;
513 SERVER_START_REQ( set_window_info )
515 req->handle = hwnd;
516 req->flags = SET_WIN_STYLE;
517 req->style = new_style;
518 req->extra_offset = -1;
519 if ((ok = !wine_server_call( req )))
521 old_style = reply->old_style;
522 win->dwStyle = new_style;
525 SERVER_END_REQ;
526 WIN_ReleasePtr( win );
527 if (ok)
529 USER_Driver->pSetWindowStyle( hwnd, old_style );
530 if ((old_style ^ new_style) & WS_VISIBLE) invalidate_dce( hwnd, NULL );
532 return old_style;
536 /***********************************************************************
537 * WIN_GetRectangles
539 * Get the window and client rectangles.
541 BOOL WIN_GetRectangles( HWND hwnd, RECT *rectWindow, RECT *rectClient )
543 WND *win = WIN_GetPtr( hwnd );
544 BOOL ret = TRUE;
546 if (!win) return FALSE;
547 if (win == WND_DESKTOP)
549 RECT rect;
550 rect.left = rect.top = 0;
551 rect.right = GetSystemMetrics(SM_CXSCREEN);
552 rect.bottom = GetSystemMetrics(SM_CYSCREEN);
553 if (rectWindow) *rectWindow = rect;
554 if (rectClient) *rectClient = rect;
556 else if (win == WND_OTHER_PROCESS)
558 SERVER_START_REQ( get_window_rectangles )
560 req->handle = hwnd;
561 if ((ret = !wine_server_call( req )))
563 if (rectWindow)
565 rectWindow->left = reply->window.left;
566 rectWindow->top = reply->window.top;
567 rectWindow->right = reply->window.right;
568 rectWindow->bottom = reply->window.bottom;
570 if (rectClient)
572 rectClient->left = reply->client.left;
573 rectClient->top = reply->client.top;
574 rectClient->right = reply->client.right;
575 rectClient->bottom = reply->client.bottom;
579 SERVER_END_REQ;
581 else
583 if (rectWindow) *rectWindow = win->rectWindow;
584 if (rectClient) *rectClient = win->rectClient;
585 WIN_ReleasePtr( win );
587 return ret;
591 /***********************************************************************
592 * WIN_DestroyWindow
594 * Destroy storage associated to a window. "Internals" p.358
596 LRESULT WIN_DestroyWindow( HWND hwnd )
598 WND *wndPtr;
599 HWND *list;
600 HMENU menu = 0, sys_menu;
601 HWND icon_title;
603 TRACE("%p\n", hwnd );
605 /* free child windows */
606 if ((list = WIN_ListChildren( hwnd )))
608 int i;
609 for (i = 0; list[i]; i++)
611 if (WIN_IsCurrentThread( list[i] )) WIN_DestroyWindow( list[i] );
612 else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
614 HeapFree( GetProcessHeap(), 0, list );
617 /* Unlink now so we won't bother with the children later on */
618 SERVER_START_REQ( set_parent )
620 req->handle = hwnd;
621 req->parent = 0;
622 wine_server_call( req );
624 SERVER_END_REQ;
627 * Send the WM_NCDESTROY to the window being destroyed.
629 SendMessageW( hwnd, WM_NCDESTROY, 0, 0 );
631 /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
633 /* free resources associated with the window */
635 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
636 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
637 menu = (HMENU)wndPtr->wIDmenu;
638 sys_menu = wndPtr->hSysMenu;
639 free_dce( wndPtr->dce, hwnd );
640 wndPtr->dce = NULL;
641 icon_title = wndPtr->icon_title;
642 WIN_ReleasePtr( wndPtr );
644 if (icon_title) DestroyWindow( icon_title );
645 if (menu) DestroyMenu( menu );
646 if (sys_menu) DestroyMenu( sys_menu );
648 USER_Driver->pDestroyWindow( hwnd );
650 free_window_handle( hwnd );
651 return 0;
654 /***********************************************************************
655 * WIN_DestroyThreadWindows
657 * Destroy all children of 'wnd' owned by the current thread.
659 void WIN_DestroyThreadWindows( HWND hwnd )
661 HWND *list;
662 int i;
664 if (!(list = WIN_ListChildren( hwnd ))) return;
665 for (i = 0; list[i]; i++)
667 if (WIN_IsCurrentThread( list[i] ))
668 DestroyWindow( list[i] );
669 else
670 WIN_DestroyThreadWindows( list[i] );
672 HeapFree( GetProcessHeap(), 0, list );
676 /***********************************************************************
677 * WIN_FixCoordinates
679 * Fix the coordinates - Helper for WIN_CreateWindowEx.
680 * returns default show mode in sw.
682 static void WIN_FixCoordinates( CREATESTRUCTA *cs, INT *sw)
684 #define IS_DEFAULT(x) ((x) == CW_USEDEFAULT || (x) == CW_USEDEFAULT16)
685 POINT pos[2];
687 if (cs->dwExStyle & WS_EX_MDICHILD)
689 UINT id = 0;
691 MDI_CalcDefaultChildPos(cs->hwndParent, -1, pos, 0, &id);
692 if (!(cs->style & WS_POPUP)) cs->hMenu = ULongToHandle(id);
694 TRACE("MDI child id %04x\n", id);
697 if (cs->style & (WS_CHILD | WS_POPUP))
699 if (cs->dwExStyle & WS_EX_MDICHILD)
701 if (IS_DEFAULT(cs->x))
703 cs->x = pos[0].x;
704 cs->y = pos[0].y;
706 if (IS_DEFAULT(cs->cx) || !cs->cx) cs->cx = pos[1].x;
707 if (IS_DEFAULT(cs->cy) || !cs->cy) cs->cy = pos[1].y;
709 else
711 if (IS_DEFAULT(cs->x)) cs->x = cs->y = 0;
712 if (IS_DEFAULT(cs->cx)) cs->cx = cs->cy = 0;
715 else /* overlapped window */
717 HMONITOR monitor;
718 MONITORINFO mon_info;
719 STARTUPINFOW info;
721 if (!IS_DEFAULT(cs->x) && !IS_DEFAULT(cs->cx) && !IS_DEFAULT(cs->cy)) return;
723 monitor = MonitorFromWindow( cs->hwndParent, MONITOR_DEFAULTTOPRIMARY );
724 mon_info.cbSize = sizeof(mon_info);
725 GetMonitorInfoW( monitor, &mon_info );
726 GetStartupInfoW( &info );
728 if (IS_DEFAULT(cs->x))
730 if (!IS_DEFAULT(cs->y)) *sw = cs->y;
731 cs->x = (info.dwFlags & STARTF_USEPOSITION) ? info.dwX : mon_info.rcWork.left;
732 cs->y = (info.dwFlags & STARTF_USEPOSITION) ? info.dwY : mon_info.rcWork.top;
735 if (IS_DEFAULT(cs->cx))
737 if (info.dwFlags & STARTF_USESIZE)
739 cs->cx = info.dwXSize;
740 cs->cy = info.dwYSize;
742 else
744 cs->cx = (mon_info.rcWork.right - mon_info.rcWork.left) * 3 / 4 - cs->x;
745 cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
748 /* neither x nor cx are default. Check the y values .
749 * In the trace we see Outlook and Outlook Express using
750 * cy set to CW_USEDEFAULT when opening the address book.
752 else if (IS_DEFAULT(cs->cy))
754 FIXME("Strange use of CW_USEDEFAULT in nHeight\n");
755 cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
758 #undef IS_DEFAULT
761 /***********************************************************************
762 * dump_window_styles
764 static void dump_window_styles( DWORD style, DWORD exstyle )
766 TRACE( "style:" );
767 if(style & WS_POPUP) TRACE(" WS_POPUP");
768 if(style & WS_CHILD) TRACE(" WS_CHILD");
769 if(style & WS_MINIMIZE) TRACE(" WS_MINIMIZE");
770 if(style & WS_VISIBLE) TRACE(" WS_VISIBLE");
771 if(style & WS_DISABLED) TRACE(" WS_DISABLED");
772 if(style & WS_CLIPSIBLINGS) TRACE(" WS_CLIPSIBLINGS");
773 if(style & WS_CLIPCHILDREN) TRACE(" WS_CLIPCHILDREN");
774 if(style & WS_MAXIMIZE) TRACE(" WS_MAXIMIZE");
775 if((style & WS_CAPTION) == WS_CAPTION) TRACE(" WS_CAPTION");
776 else
778 if(style & WS_BORDER) TRACE(" WS_BORDER");
779 if(style & WS_DLGFRAME) TRACE(" WS_DLGFRAME");
781 if(style & WS_VSCROLL) TRACE(" WS_VSCROLL");
782 if(style & WS_HSCROLL) TRACE(" WS_HSCROLL");
783 if(style & WS_SYSMENU) TRACE(" WS_SYSMENU");
784 if(style & WS_THICKFRAME) TRACE(" WS_THICKFRAME");
785 if (style & WS_CHILD)
787 if(style & WS_GROUP) TRACE(" WS_GROUP");
788 if(style & WS_TABSTOP) TRACE(" WS_TABSTOP");
790 else
792 if(style & WS_MINIMIZEBOX) TRACE(" WS_MINIMIZEBOX");
793 if(style & WS_MAXIMIZEBOX) TRACE(" WS_MAXIMIZEBOX");
796 /* FIXME: Add dumping of BS_/ES_/SBS_/LBS_/CBS_/DS_/etc. styles */
797 #define DUMPED_STYLES \
798 (WS_POPUP | \
799 WS_CHILD | \
800 WS_MINIMIZE | \
801 WS_VISIBLE | \
802 WS_DISABLED | \
803 WS_CLIPSIBLINGS | \
804 WS_CLIPCHILDREN | \
805 WS_MAXIMIZE | \
806 WS_BORDER | \
807 WS_DLGFRAME | \
808 WS_VSCROLL | \
809 WS_HSCROLL | \
810 WS_SYSMENU | \
811 WS_THICKFRAME | \
812 WS_GROUP | \
813 WS_TABSTOP | \
814 WS_MINIMIZEBOX | \
815 WS_MAXIMIZEBOX)
817 if(style & ~DUMPED_STYLES) TRACE(" %08lx", style & ~DUMPED_STYLES);
818 TRACE("\n");
819 #undef DUMPED_STYLES
821 TRACE( "exstyle:" );
822 if(exstyle & WS_EX_DLGMODALFRAME) TRACE(" WS_EX_DLGMODALFRAME");
823 if(exstyle & WS_EX_DRAGDETECT) TRACE(" WS_EX_DRAGDETECT");
824 if(exstyle & WS_EX_NOPARENTNOTIFY) TRACE(" WS_EX_NOPARENTNOTIFY");
825 if(exstyle & WS_EX_TOPMOST) TRACE(" WS_EX_TOPMOST");
826 if(exstyle & WS_EX_ACCEPTFILES) TRACE(" WS_EX_ACCEPTFILES");
827 if(exstyle & WS_EX_TRANSPARENT) TRACE(" WS_EX_TRANSPARENT");
828 if(exstyle & WS_EX_MDICHILD) TRACE(" WS_EX_MDICHILD");
829 if(exstyle & WS_EX_TOOLWINDOW) TRACE(" WS_EX_TOOLWINDOW");
830 if(exstyle & WS_EX_WINDOWEDGE) TRACE(" WS_EX_WINDOWEDGE");
831 if(exstyle & WS_EX_CLIENTEDGE) TRACE(" WS_EX_CLIENTEDGE");
832 if(exstyle & WS_EX_CONTEXTHELP) TRACE(" WS_EX_CONTEXTHELP");
833 if(exstyle & WS_EX_RIGHT) TRACE(" WS_EX_RIGHT");
834 if(exstyle & WS_EX_RTLREADING) TRACE(" WS_EX_RTLREADING");
835 if(exstyle & WS_EX_LEFTSCROLLBAR) TRACE(" WS_EX_LEFTSCROLLBAR");
836 if(exstyle & WS_EX_CONTROLPARENT) TRACE(" WS_EX_CONTROLPARENT");
837 if(exstyle & WS_EX_STATICEDGE) TRACE(" WS_EX_STATICEDGE");
838 if(exstyle & WS_EX_APPWINDOW) TRACE(" WS_EX_APPWINDOW");
839 if(exstyle & WS_EX_LAYERED) TRACE(" WS_EX_LAYERED");
841 #define DUMPED_EX_STYLES \
842 (WS_EX_DLGMODALFRAME | \
843 WS_EX_DRAGDETECT | \
844 WS_EX_NOPARENTNOTIFY | \
845 WS_EX_TOPMOST | \
846 WS_EX_ACCEPTFILES | \
847 WS_EX_TRANSPARENT | \
848 WS_EX_MDICHILD | \
849 WS_EX_TOOLWINDOW | \
850 WS_EX_WINDOWEDGE | \
851 WS_EX_CLIENTEDGE | \
852 WS_EX_CONTEXTHELP | \
853 WS_EX_RIGHT | \
854 WS_EX_RTLREADING | \
855 WS_EX_LEFTSCROLLBAR | \
856 WS_EX_CONTROLPARENT | \
857 WS_EX_STATICEDGE | \
858 WS_EX_APPWINDOW | \
859 WS_EX_LAYERED)
861 if(exstyle & ~DUMPED_EX_STYLES) TRACE(" %08lx", exstyle & ~DUMPED_EX_STYLES);
862 TRACE("\n");
863 #undef DUMPED_EX_STYLES
867 /***********************************************************************
868 * WIN_CreateWindowEx
870 * Implementation of CreateWindowEx().
872 static HWND WIN_CreateWindowEx( CREATESTRUCTA *cs, LPCWSTR className, UINT flags )
874 INT cx, cy, style, sw = SW_SHOW;
875 LRESULT result;
876 RECT rect;
877 WND *wndPtr;
878 HWND hwnd, parent, owner, top_child = 0;
879 BOOL unicode = (flags & WIN_ISUNICODE) != 0;
880 MDICREATESTRUCTA mdi_cs;
881 CBT_CREATEWNDA cbtc;
882 CREATESTRUCTA cbcs;
884 TRACE("%s %s ex=%08x style=%08x %d,%d %dx%d parent=%p menu=%p inst=%p params=%p\n",
885 unicode ? debugstr_w((LPCWSTR)cs->lpszName) : debugstr_a(cs->lpszName),
886 debugstr_w(className),
887 cs->dwExStyle, cs->style, cs->x, cs->y, cs->cx, cs->cy,
888 cs->hwndParent, cs->hMenu, cs->hInstance, cs->lpCreateParams );
889 if(TRACE_ON(win)) dump_window_styles( cs->style, cs->dwExStyle );
891 /* Fix the styles for MDI children */
892 if (cs->dwExStyle & WS_EX_MDICHILD)
894 UINT flags = 0;
896 wndPtr = WIN_GetPtr(cs->hwndParent);
897 if (wndPtr && wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
899 flags = wndPtr->flags;
900 WIN_ReleasePtr(wndPtr);
903 if (!(flags & WIN_ISMDICLIENT))
905 WARN("WS_EX_MDICHILD, but parent %p is not MDIClient\n", cs->hwndParent);
906 return 0;
909 /* cs->lpCreateParams of WM_[NC]CREATE is different for MDI children.
910 * MDICREATESTRUCT members have the originally passed values.
912 * Note: we rely on the fact that MDICREATESTRUCTA and MDICREATESTRUCTW
913 * have the same layout.
915 mdi_cs.szClass = cs->lpszClass;
916 mdi_cs.szTitle = cs->lpszName;
917 mdi_cs.hOwner = cs->hInstance;
918 mdi_cs.x = cs->x;
919 mdi_cs.y = cs->y;
920 mdi_cs.cx = cs->cx;
921 mdi_cs.cy = cs->cy;
922 mdi_cs.style = cs->style;
923 mdi_cs.lParam = (LPARAM)cs->lpCreateParams;
925 cs->lpCreateParams = (LPVOID)&mdi_cs;
927 if (GetWindowLongW(cs->hwndParent, GWL_STYLE) & MDIS_ALLCHILDSTYLES)
929 if (cs->style & WS_POPUP)
931 TRACE("WS_POPUP with MDIS_ALLCHILDSTYLES is not allowed\n");
932 return 0;
934 cs->style |= WS_CHILD | WS_CLIPSIBLINGS;
936 else
938 cs->style &= ~WS_POPUP;
939 cs->style |= WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION |
940 WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
943 top_child = GetWindow(cs->hwndParent, GW_CHILD);
945 if (top_child)
947 /* Restore current maximized child */
948 if((cs->style & WS_VISIBLE) && IsZoomed(top_child))
950 TRACE("Restoring current maximized child %p\n", top_child);
951 SendMessageW( top_child, WM_SETREDRAW, FALSE, 0 );
952 ShowWindow( top_child, SW_SHOWNORMAL );
953 SendMessageW( top_child, WM_SETREDRAW, TRUE, 0 );
958 /* Find the parent window */
960 parent = cs->hwndParent;
961 owner = 0;
963 if (cs->hwndParent == HWND_MESSAGE)
965 /* native ole32.OleInitialize uses HWND_MESSAGE to create the
966 * message window (style: WS_POPUP|WS_DISABLED)
968 FIXME("Parent is HWND_MESSAGE\n");
969 parent = GetDesktopWindow();
971 else if (cs->hwndParent)
973 if ((cs->style & (WS_CHILD|WS_POPUP)) != WS_CHILD)
975 parent = GetDesktopWindow();
976 owner = cs->hwndParent;
979 else
981 if ((cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
983 WARN("No parent for child window\n" );
984 SetLastError(ERROR_TLW_WITH_WSCHILD);
985 return 0; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
987 if (className != (LPCWSTR)DESKTOP_CLASS_ATOM) /* are we creating the desktop itself? */
988 parent = GetDesktopWindow();
991 WIN_FixCoordinates(cs, &sw); /* fix default coordinates */
993 if ((cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
994 ((!(cs->dwExStyle & WS_EX_STATICEDGE)) &&
995 (cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
996 cs->dwExStyle |= WS_EX_WINDOWEDGE;
997 else
998 cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
1000 /* Create the window structure */
1002 if (!(wndPtr = create_window_handle( parent, owner, className, cs->hInstance, unicode )))
1003 return 0;
1004 hwnd = wndPtr->hwndSelf;
1006 /* Fill the window structure */
1008 wndPtr->tid = GetCurrentThreadId();
1009 wndPtr->hInstance = cs->hInstance;
1010 wndPtr->text = NULL;
1011 wndPtr->dwStyle = cs->style & ~WS_VISIBLE;
1012 wndPtr->dwExStyle = cs->dwExStyle;
1013 wndPtr->wIDmenu = 0;
1014 wndPtr->helpContext = 0;
1015 wndPtr->pVScroll = NULL;
1016 wndPtr->pHScroll = NULL;
1017 wndPtr->userdata = 0;
1018 wndPtr->hIcon = 0;
1019 wndPtr->hIconSmall = 0;
1020 wndPtr->hSysMenu = 0;
1021 wndPtr->flags |= (flags & WIN_ISWIN32);
1023 if (wndPtr->dwStyle & WS_SYSMENU) SetSystemMenu( hwnd, 0 );
1026 * Correct the window styles.
1028 * It affects only the style loaded into the WIN structure.
1031 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1033 wndPtr->dwStyle |= WS_CLIPSIBLINGS;
1034 if (!(wndPtr->dwStyle & WS_POPUP))
1035 wndPtr->dwStyle |= WS_CAPTION;
1039 * WS_EX_WINDOWEDGE appears to be enforced based on the other styles, so
1040 * why does the user get to set it?
1043 if ((wndPtr->dwExStyle & WS_EX_DLGMODALFRAME) ||
1044 (wndPtr->dwStyle & (WS_DLGFRAME | WS_THICKFRAME)))
1045 wndPtr->dwExStyle |= WS_EX_WINDOWEDGE;
1046 else
1047 wndPtr->dwExStyle &= ~WS_EX_WINDOWEDGE;
1049 if (!(wndPtr->dwStyle & (WS_CHILD | WS_POPUP)))
1050 wndPtr->flags |= WIN_NEED_SIZE;
1052 SERVER_START_REQ( set_window_info )
1054 req->handle = hwnd;
1055 req->flags = SET_WIN_STYLE | SET_WIN_EXSTYLE | SET_WIN_INSTANCE | SET_WIN_UNICODE;
1056 req->style = wndPtr->dwStyle;
1057 req->ex_style = wndPtr->dwExStyle;
1058 req->instance = (void *)wndPtr->hInstance;
1059 req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
1060 req->extra_offset = -1;
1061 wine_server_call( req );
1063 SERVER_END_REQ;
1065 /* Set the window menu */
1067 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1069 if (cs->hMenu)
1071 if (!MENU_SetMenu(hwnd, cs->hMenu))
1073 WIN_ReleasePtr( wndPtr );
1074 free_window_handle( hwnd );
1075 return 0;
1078 else
1080 LPCSTR menuName = (LPCSTR)GetClassLongPtrA( hwnd, GCLP_MENUNAME );
1081 if (menuName)
1083 if (!cs->hInstance || HIWORD(cs->hInstance))
1084 cs->hMenu = LoadMenuA(cs->hInstance,menuName);
1085 else
1086 cs->hMenu = HMENU_32(LoadMenu16(HINSTANCE_16(cs->hInstance),menuName));
1088 if (cs->hMenu) MENU_SetMenu( hwnd, cs->hMenu );
1092 else SetWindowLongPtrW( hwnd, GWLP_ID, (ULONG_PTR)cs->hMenu );
1094 /* call the WH_CBT hook */
1096 /* the window style passed to the hook must be the real window style,
1097 * rather than just the window style that the caller to CreateWindowEx
1098 * passed in, so we have to copy the original CREATESTRUCT and get the
1099 * the real style. */
1100 cbcs = *cs;
1101 cbcs.style = wndPtr->dwStyle;
1102 cbtc.lpcs = &cbcs;
1103 cbtc.hwndInsertAfter = HWND_TOP;
1104 WIN_ReleasePtr( wndPtr );
1105 if (HOOK_CallHooks( WH_CBT, HCBT_CREATEWND, (WPARAM)hwnd, (LPARAM)&cbtc, unicode )) goto failed;
1107 /* send the WM_GETMINMAXINFO message and fix the size if needed */
1109 cx = cs->cx;
1110 cy = cs->cy;
1111 if ((cs->style & WS_THICKFRAME) || !(cs->style & (WS_POPUP | WS_CHILD)))
1113 POINT maxSize, maxPos, minTrack, maxTrack;
1114 WINPOS_GetMinMaxInfo( hwnd, &maxSize, &maxPos, &minTrack, &maxTrack);
1115 if (maxTrack.x < cx) cx = maxTrack.x;
1116 if (maxTrack.y < cy) cy = maxTrack.y;
1119 if (cx < 0) cx = 0;
1120 if (cy < 0) cy = 0;
1121 SetRect( &rect, cs->x, cs->y, cs->x + cx, cs->y + cy );
1122 if (!set_window_pos( hwnd, 0, SWP_NOZORDER | SWP_NOACTIVATE, &rect, &rect, NULL )) goto failed;
1124 /* send WM_NCCREATE */
1126 TRACE( "hwnd %p cs %d,%d %dx%d\n", hwnd, cs->x, cs->y, cx, cy );
1127 if (unicode)
1128 result = SendMessageW( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1129 else
1130 result = SendMessageA( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1131 if (!result)
1133 WARN( "%p: aborted by WM_NCCREATE\n", hwnd );
1134 goto failed;
1137 /* send WM_NCCALCSIZE */
1139 if ((wndPtr = WIN_GetPtr(hwnd)))
1141 /* yes, even if the CBT hook was called with HWND_TOP */
1142 POINT pt;
1143 HWND insert_after = (wndPtr->dwStyle & WS_CHILD) ? HWND_BOTTOM : HWND_TOP;
1144 RECT window_rect = wndPtr->rectWindow;
1145 RECT client_rect = window_rect;
1146 WIN_ReleasePtr( wndPtr );
1148 /* the rectangle is in screen coords for WM_NCCALCSIZE when wparam is FALSE */
1149 pt.x = pt.y = 0;
1150 MapWindowPoints( parent, 0, &pt, 1 );
1151 OffsetRect( &client_rect, pt.x, pt.y );
1152 SendMessageW( hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&client_rect );
1153 OffsetRect( &client_rect, -pt.x, -pt.y );
1154 set_window_pos( hwnd, insert_after, SWP_NOACTIVATE, &window_rect, &client_rect, NULL );
1156 else return 0;
1158 /* send WM_CREATE */
1160 if (unicode)
1161 result = SendMessageW( hwnd, WM_CREATE, 0, (LPARAM)cs );
1162 else
1163 result = SendMessageA( hwnd, WM_CREATE, 0, (LPARAM)cs );
1164 if (result == -1) goto failed;
1166 /* call the driver */
1168 if (!USER_Driver->pCreateWindow( hwnd )) goto failed;
1170 NotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_WINDOW, 0);
1172 /* send the size messages */
1174 if (!(wndPtr = WIN_GetPtr(hwnd))) return 0;
1175 if (!(wndPtr->flags & WIN_NEED_SIZE))
1177 rect = wndPtr->rectClient;
1178 WIN_ReleasePtr( wndPtr );
1179 SendMessageW( hwnd, WM_SIZE, SIZE_RESTORED,
1180 MAKELONG(rect.right-rect.left, rect.bottom-rect.top));
1181 SendMessageW( hwnd, WM_MOVE, 0, MAKELONG( rect.left, rect.top ) );
1183 else WIN_ReleasePtr( wndPtr );
1185 /* Show the window, maximizing or minimizing if needed */
1187 style = WIN_SetStyle( hwnd, 0, WS_MAXIMIZE | WS_MINIMIZE );
1188 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
1190 RECT newPos;
1191 UINT swFlag = (style & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;
1193 swFlag = WINPOS_MinMaximize( hwnd, swFlag, &newPos );
1194 swFlag |= SWP_FRAMECHANGED; /* Frame always gets changed */
1195 if (!(style & WS_VISIBLE) || (style & WS_CHILD) || GetActiveWindow()) swFlag |= SWP_NOACTIVATE;
1196 SetWindowPos( hwnd, 0, newPos.left, newPos.top, newPos.right, newPos.bottom, swFlag );
1199 /* Notify the parent window only */
1201 send_parent_notify( hwnd, WM_CREATE );
1202 if (!IsWindow( hwnd )) return 0;
1204 if (cs->style & WS_VISIBLE)
1206 if (cs->style & WS_MAXIMIZE)
1207 sw = SW_SHOW;
1208 else if (cs->style & WS_MINIMIZE)
1209 sw = SW_SHOWMINIMIZED;
1211 ShowWindow( hwnd, sw );
1212 if (cs->dwExStyle & WS_EX_MDICHILD)
1214 SendMessageW(cs->hwndParent, WM_MDIREFRESHMENU, 0, 0);
1215 /* ShowWindow won't activate child windows */
1216 SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE );
1220 /* Call WH_SHELL hook */
1222 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1223 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0, TRUE );
1225 TRACE("created window %p\n", hwnd);
1226 return hwnd;
1228 failed:
1229 WIN_DestroyWindow( hwnd );
1230 return 0;
1234 /***********************************************************************
1235 * CreateWindow (USER.41)
1237 HWND16 WINAPI CreateWindow16( LPCSTR className, LPCSTR windowName,
1238 DWORD style, INT16 x, INT16 y, INT16 width,
1239 INT16 height, HWND16 parent, HMENU16 menu,
1240 HINSTANCE16 instance, LPVOID data )
1242 return CreateWindowEx16( 0, className, windowName, style,
1243 x, y, width, height, parent, menu, instance, data );
1247 /***********************************************************************
1248 * CreateWindowEx (USER.452)
1250 HWND16 WINAPI CreateWindowEx16( DWORD exStyle, LPCSTR className,
1251 LPCSTR windowName, DWORD style, INT16 x,
1252 INT16 y, INT16 width, INT16 height,
1253 HWND16 parent, HMENU16 menu,
1254 HINSTANCE16 instance, LPVOID data )
1256 CREATESTRUCTA cs;
1257 char buffer[256];
1259 /* Fix the coordinates */
1261 cs.x = (x == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)x;
1262 cs.y = (y == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)y;
1263 cs.cx = (width == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)width;
1264 cs.cy = (height == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)height;
1266 /* Create the window */
1268 cs.lpCreateParams = data;
1269 cs.hInstance = HINSTANCE_32(instance);
1270 cs.hMenu = HMENU_32(menu);
1271 cs.hwndParent = WIN_Handle32( parent );
1272 cs.style = style;
1273 cs.lpszName = windowName;
1274 cs.lpszClass = className;
1275 cs.dwExStyle = exStyle;
1277 if (!IS_INTRESOURCE(className))
1279 WCHAR bufferW[256];
1281 if (!MultiByteToWideChar( CP_ACP, 0, className, -1, bufferW, sizeof(bufferW)/sizeof(WCHAR) ))
1282 return 0;
1283 return HWND_16( WIN_CreateWindowEx( &cs, bufferW, 0 ));
1285 else
1287 if (!GlobalGetAtomNameA( LOWORD(className), buffer, sizeof(buffer) ))
1289 ERR( "bad atom %x\n", LOWORD(className));
1290 return 0;
1292 cs.lpszClass = buffer;
1293 return HWND_16( WIN_CreateWindowEx( &cs, (LPCWSTR)className, 0 ));
1298 /***********************************************************************
1299 * CreateWindowExA (USER32.@)
1301 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1302 LPCSTR windowName, DWORD style, INT x,
1303 INT y, INT width, INT height,
1304 HWND parent, HMENU menu,
1305 HINSTANCE instance, LPVOID data )
1307 CREATESTRUCTA cs;
1309 cs.lpCreateParams = data;
1310 cs.hInstance = instance;
1311 cs.hMenu = menu;
1312 cs.hwndParent = parent;
1313 cs.x = x;
1314 cs.y = y;
1315 cs.cx = width;
1316 cs.cy = height;
1317 cs.style = style;
1318 cs.lpszName = windowName;
1319 cs.lpszClass = className;
1320 cs.dwExStyle = exStyle;
1322 if (!IS_INTRESOURCE(className))
1324 WCHAR bufferW[256];
1325 if (!MultiByteToWideChar( CP_ACP, 0, className, -1, bufferW, sizeof(bufferW)/sizeof(WCHAR) ))
1326 return 0;
1327 return WIN_CreateWindowEx( &cs, bufferW, WIN_ISWIN32 );
1329 return WIN_CreateWindowEx( &cs, (LPCWSTR)className, WIN_ISWIN32 );
1333 /***********************************************************************
1334 * CreateWindowExW (USER32.@)
1336 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1337 LPCWSTR windowName, DWORD style, INT x,
1338 INT y, INT width, INT height,
1339 HWND parent, HMENU menu,
1340 HINSTANCE instance, LPVOID data )
1342 CREATESTRUCTW cs;
1344 cs.lpCreateParams = data;
1345 cs.hInstance = instance;
1346 cs.hMenu = menu;
1347 cs.hwndParent = parent;
1348 cs.x = x;
1349 cs.y = y;
1350 cs.cx = width;
1351 cs.cy = height;
1352 cs.style = style;
1353 cs.lpszName = windowName;
1354 cs.lpszClass = className;
1355 cs.dwExStyle = exStyle;
1357 /* Note: we rely on the fact that CREATESTRUCTA and */
1358 /* CREATESTRUCTW have the same layout. */
1359 return WIN_CreateWindowEx( (CREATESTRUCTA *)&cs, className, WIN_ISWIN32 | WIN_ISUNICODE );
1363 /***********************************************************************
1364 * WIN_SendDestroyMsg
1366 static void WIN_SendDestroyMsg( HWND hwnd )
1368 GUITHREADINFO info;
1370 if (GetGUIThreadInfo( GetCurrentThreadId(), &info ))
1372 if (hwnd == info.hwndCaret) DestroyCaret();
1373 if (hwnd == info.hwndActive) WINPOS_ActivateOtherWindow( hwnd );
1377 * Send the WM_DESTROY to the window.
1379 SendMessageW( hwnd, WM_DESTROY, 0, 0);
1382 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1383 * make sure that the window still exists when we come back.
1385 if (IsWindow(hwnd))
1387 HWND* pWndArray;
1388 int i;
1390 if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1392 for (i = 0; pWndArray[i]; i++)
1394 if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1396 HeapFree( GetProcessHeap(), 0, pWndArray );
1398 else
1399 WARN("\tdestroyed itself while in WM_DESTROY!\n");
1403 /***********************************************************************
1404 * DestroyWindow (USER32.@)
1406 BOOL WINAPI DestroyWindow( HWND hwnd )
1408 BOOL is_child;
1410 if (!(hwnd = WIN_IsCurrentThread( hwnd )) || (hwnd == GetDesktopWindow()))
1412 SetLastError( ERROR_ACCESS_DENIED );
1413 return FALSE;
1416 TRACE("(%p)\n", hwnd);
1418 /* Call hooks */
1420 if (HOOK_CallHooks( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0, TRUE )) return FALSE;
1422 if (MENU_IsMenuActive() == hwnd)
1423 EndMenu();
1425 is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;
1427 if (is_child)
1429 if (!USER_IsExitingThread( GetCurrentThreadId() ))
1430 send_parent_notify( hwnd, WM_DESTROY );
1432 else if (!GetWindow( hwnd, GW_OWNER ))
1434 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
1435 /* FIXME: clean up palette - see "Internals" p.352 */
1438 if (!IsWindow(hwnd)) return TRUE;
1440 /* Hide the window */
1441 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)
1443 /* Only child windows receive WM_SHOWWINDOW in DestroyWindow() */
1444 if (is_child)
1445 ShowWindow( hwnd, SW_HIDE );
1446 else
1447 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE |
1448 SWP_NOZORDER | SWP_NOACTIVATE | SWP_HIDEWINDOW );
1451 if (!IsWindow(hwnd)) return TRUE;
1453 /* Recursively destroy owned windows */
1455 if (!is_child)
1457 for (;;)
1459 int i, got_one = 0;
1460 HWND *list = WIN_ListChildren( GetDesktopWindow() );
1461 if (list)
1463 for (i = 0; list[i]; i++)
1465 if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1466 if (WIN_IsCurrentThread( list[i] ))
1468 DestroyWindow( list[i] );
1469 got_one = 1;
1470 continue;
1472 WIN_SetOwner( list[i], 0 );
1474 HeapFree( GetProcessHeap(), 0, list );
1476 if (!got_one) break;
1480 /* Send destroy messages */
1482 WIN_SendDestroyMsg( hwnd );
1483 if (!IsWindow( hwnd )) return TRUE;
1485 if (GetClipboardOwner() == hwnd)
1486 CLIPBOARD_ReleaseOwner();
1488 /* Destroy the window storage */
1490 WIN_DestroyWindow( hwnd );
1491 return TRUE;
1495 /***********************************************************************
1496 * CloseWindow (USER32.@)
1498 BOOL WINAPI CloseWindow( HWND hwnd )
1500 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1501 ShowWindow( hwnd, SW_MINIMIZE );
1502 return TRUE;
1506 /***********************************************************************
1507 * OpenIcon (USER32.@)
1509 BOOL WINAPI OpenIcon( HWND hwnd )
1511 if (!IsIconic( hwnd )) return FALSE;
1512 ShowWindow( hwnd, SW_SHOWNORMAL );
1513 return TRUE;
1517 /***********************************************************************
1518 * FindWindowExW (USER32.@)
1520 HWND WINAPI FindWindowExW( HWND parent, HWND child, LPCWSTR className, LPCWSTR title )
1522 HWND *list = NULL;
1523 HWND retvalue = 0;
1524 int i = 0, len = 0;
1525 WCHAR *buffer = NULL;
1527 if (!parent) parent = GetDesktopWindow();
1528 if (title)
1530 len = strlenW(title) + 1; /* one extra char to check for chars beyond the end */
1531 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1534 if (!(list = list_window_children( 0, parent, className, 0 ))) goto done;
1536 if (child)
1538 child = WIN_GetFullHandle( child );
1539 while (list[i] && list[i] != child) i++;
1540 if (!list[i]) goto done;
1541 i++; /* start from next window */
1544 if (title)
1546 while (list[i])
1548 if (GetWindowTextW( list[i], buffer, len + 1 ) && !strcmpiW( buffer, title )) break;
1549 i++;
1552 retvalue = list[i];
1554 done:
1555 HeapFree( GetProcessHeap(), 0, list );
1556 HeapFree( GetProcessHeap(), 0, buffer );
1557 return retvalue;
1562 /***********************************************************************
1563 * FindWindowA (USER32.@)
1565 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1567 HWND ret = FindWindowExA( 0, 0, className, title );
1568 if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1569 return ret;
1573 /***********************************************************************
1574 * FindWindowExA (USER32.@)
1576 HWND WINAPI FindWindowExA( HWND parent, HWND child, LPCSTR className, LPCSTR title )
1578 LPWSTR titleW = NULL;
1579 HWND hwnd = 0;
1581 if (title)
1583 DWORD len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
1584 if (!(titleW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
1585 MultiByteToWideChar( CP_ACP, 0, title, -1, titleW, len );
1588 if (!IS_INTRESOURCE(className))
1590 WCHAR classW[256];
1591 if (MultiByteToWideChar( CP_ACP, 0, className, -1, classW, sizeof(classW)/sizeof(WCHAR) ))
1592 hwnd = FindWindowExW( parent, child, classW, titleW );
1594 else
1596 hwnd = FindWindowExW( parent, child, (LPCWSTR)className, titleW );
1599 HeapFree( GetProcessHeap(), 0, titleW );
1600 return hwnd;
1604 /***********************************************************************
1605 * FindWindowW (USER32.@)
1607 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
1609 return FindWindowExW( 0, 0, className, title );
1613 /**********************************************************************
1614 * GetDesktopWindow (USER32.@)
1616 HWND WINAPI GetDesktopWindow(void)
1618 struct user_thread_info *thread_info = get_user_thread_info();
1620 if (thread_info->desktop) return thread_info->desktop;
1622 SERVER_START_REQ( get_desktop_window )
1624 req->force = 0;
1625 if (!wine_server_call( req )) thread_info->desktop = reply->handle;
1627 SERVER_END_REQ;
1629 if (!thread_info->desktop)
1631 USEROBJECTFLAGS flags;
1632 if (!GetUserObjectInformationW( GetProcessWindowStation(), UOI_FLAGS, &flags,
1633 sizeof(flags), NULL ) || (flags.dwFlags & WSF_VISIBLE))
1635 static const WCHAR command_line[] = {'\\','e','x','p','l','o','r','e','r','.','e','x','e',' ','/','d','e','s','k','t','o','p',0};
1636 STARTUPINFOW si;
1637 PROCESS_INFORMATION pi;
1638 WCHAR cmdline[MAX_PATH + sizeof(command_line)/sizeof(WCHAR)];
1640 memset( &si, 0, sizeof(si) );
1641 si.cb = sizeof(si);
1642 si.dwFlags = STARTF_USESTDHANDLES;
1643 si.hStdInput = 0;
1644 si.hStdOutput = 0;
1645 si.hStdError = GetStdHandle( STD_ERROR_HANDLE );
1647 GetSystemDirectoryW( cmdline, MAX_PATH );
1648 lstrcatW( cmdline, command_line );
1649 if (CreateProcessW( NULL, cmdline, NULL, NULL, FALSE, DETACHED_PROCESS,
1650 NULL, NULL, &si, &pi ))
1652 TRACE( "started explorer pid %04x tid %04x\n", pi.dwProcessId, pi.dwThreadId );
1653 WaitForInputIdle( pi.hProcess, 10000 );
1654 CloseHandle( pi.hThread );
1655 CloseHandle( pi.hProcess );
1657 else WARN( "failed to start explorer, err %d\n", GetLastError() );
1659 else TRACE( "not starting explorer since winstation is not visible\n" );
1661 SERVER_START_REQ( get_desktop_window )
1663 req->force = 1;
1664 if (!wine_server_call( req )) thread_info->desktop = reply->handle;
1666 SERVER_END_REQ;
1669 if (!thread_info->desktop || !USER_Driver->pCreateDesktopWindow( thread_info->desktop ))
1670 ERR( "failed to create desktop window\n" );
1672 return thread_info->desktop;
1676 /*******************************************************************
1677 * EnableWindow (USER32.@)
1679 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
1681 BOOL retvalue;
1682 HWND full_handle;
1684 if (is_broadcast(hwnd))
1686 SetLastError( ERROR_INVALID_PARAMETER );
1687 return FALSE;
1690 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
1691 return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
1693 hwnd = full_handle;
1695 TRACE("( %p, %d )\n", hwnd, enable);
1697 retvalue = !IsWindowEnabled( hwnd );
1699 if (enable && retvalue)
1701 WIN_SetStyle( hwnd, 0, WS_DISABLED );
1702 SendMessageW( hwnd, WM_ENABLE, TRUE, 0 );
1704 else if (!enable && !retvalue)
1706 HWND capture_wnd;
1708 SendMessageW( hwnd, WM_CANCELMODE, 0, 0);
1710 WIN_SetStyle( hwnd, WS_DISABLED, 0 );
1712 if (hwnd == GetFocus())
1713 SetFocus( 0 ); /* A disabled window can't have the focus */
1715 capture_wnd = GetCapture();
1716 if (hwnd == capture_wnd || IsChild(hwnd, capture_wnd))
1717 ReleaseCapture(); /* A disabled window can't capture the mouse */
1719 SendMessageW( hwnd, WM_ENABLE, FALSE, 0 );
1721 return retvalue;
1725 /***********************************************************************
1726 * IsWindowEnabled (USER32.@)
1728 BOOL WINAPI IsWindowEnabled(HWND hWnd)
1730 return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
1734 /***********************************************************************
1735 * IsWindowUnicode (USER32.@)
1737 BOOL WINAPI IsWindowUnicode( HWND hwnd )
1739 WND * wndPtr;
1740 BOOL retvalue = FALSE;
1742 if (!(wndPtr = WIN_GetPtr(hwnd))) return FALSE;
1744 if (wndPtr == WND_DESKTOP) return TRUE;
1746 if (wndPtr != WND_OTHER_PROCESS)
1748 retvalue = (wndPtr->flags & WIN_ISUNICODE) != 0;
1749 WIN_ReleasePtr( wndPtr );
1751 else
1753 SERVER_START_REQ( get_window_info )
1755 req->handle = hwnd;
1756 if (!wine_server_call_err( req )) retvalue = reply->is_unicode;
1758 SERVER_END_REQ;
1760 return retvalue;
1764 /**********************************************************************
1765 * WIN_GetWindowLong
1767 * Helper function for GetWindowLong().
1769 static LONG_PTR WIN_GetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicode )
1771 LONG_PTR retvalue = 0;
1772 WND *wndPtr;
1774 if (offset == GWLP_HWNDPARENT)
1776 HWND parent = GetAncestor( hwnd, GA_PARENT );
1777 if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
1778 return (ULONG_PTR)parent;
1781 if (!(wndPtr = WIN_GetPtr( hwnd )))
1783 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1784 return 0;
1787 if (wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP)
1789 if (offset == GWLP_WNDPROC)
1791 SetLastError( ERROR_ACCESS_DENIED );
1792 return 0;
1794 SERVER_START_REQ( set_window_info )
1796 req->handle = hwnd;
1797 req->flags = 0; /* don't set anything, just retrieve */
1798 req->extra_offset = (offset >= 0) ? offset : -1;
1799 req->extra_size = (offset >= 0) ? size : 0;
1800 if (!wine_server_call_err( req ))
1802 switch(offset)
1804 case GWL_STYLE: retvalue = reply->old_style; break;
1805 case GWL_EXSTYLE: retvalue = reply->old_ex_style; break;
1806 case GWLP_ID: retvalue = reply->old_id; break;
1807 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)reply->old_instance; break;
1808 case GWLP_USERDATA: retvalue = reply->old_user_data; break;
1809 default:
1810 if (offset >= 0) retvalue = get_win_data( &reply->old_extra_value, size );
1811 else SetLastError( ERROR_INVALID_INDEX );
1812 break;
1816 SERVER_END_REQ;
1817 return retvalue;
1820 /* now we have a valid wndPtr */
1822 if (offset >= 0)
1824 if (offset > (int)(wndPtr->cbWndExtra - size))
1826 WARN("Invalid offset %d\n", offset );
1827 WIN_ReleasePtr( wndPtr );
1828 SetLastError( ERROR_INVALID_INDEX );
1829 return 0;
1831 retvalue = get_win_data( (char *)wndPtr->wExtra + offset, size );
1833 /* Special case for dialog window procedure */
1834 if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && (wndPtr->flags & WIN_ISDIALOG))
1835 retvalue = (LONG_PTR)WINPROC_GetProc( (WNDPROC)retvalue, unicode );
1836 WIN_ReleasePtr( wndPtr );
1837 return retvalue;
1840 switch(offset)
1842 case GWLP_USERDATA: retvalue = wndPtr->userdata; break;
1843 case GWL_STYLE: retvalue = wndPtr->dwStyle; break;
1844 case GWL_EXSTYLE: retvalue = wndPtr->dwExStyle; break;
1845 case GWLP_ID: retvalue = wndPtr->wIDmenu; break;
1846 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hInstance; break;
1847 case GWLP_WNDPROC:
1848 /* This looks like a hack only for the edit control (see tests). This makes these controls
1849 * more tolerant to A/W mismatches. The lack of W->A->W conversion for such a mismatch suggests
1850 * that the hack is in GetWindowLongPtr[AW], not in winprocs.
1852 if (wndPtr->winproc == EDIT_winproc_handle && (!unicode != !(wndPtr->flags & WIN_ISUNICODE)))
1853 retvalue = (ULONG_PTR)wndPtr->winproc;
1854 else
1855 retvalue = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, unicode );
1856 break;
1857 default:
1858 WARN("Unknown offset %d\n", offset );
1859 SetLastError( ERROR_INVALID_INDEX );
1860 break;
1862 WIN_ReleasePtr(wndPtr);
1863 return retvalue;
1867 /**********************************************************************
1868 * WIN_SetWindowLong
1870 * Helper function for SetWindowLong().
1872 * 0 is the failure code. However, in the case of failure SetLastError
1873 * must be set to distinguish between a 0 return value and a failure.
1875 LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, UINT size, LONG_PTR newval, BOOL unicode )
1877 STYLESTRUCT style;
1878 BOOL ok;
1879 LONG_PTR retval = 0;
1880 WND *wndPtr;
1882 TRACE( "%p %d %lx %c\n", hwnd, offset, newval, unicode ? 'W' : 'A' );
1884 if (is_broadcast(hwnd))
1886 SetLastError( ERROR_INVALID_PARAMETER );
1887 return FALSE;
1890 if (!(wndPtr = WIN_GetPtr( hwnd )))
1892 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1893 return 0;
1895 if (wndPtr == WND_DESKTOP)
1897 /* can't change anything on the desktop window */
1898 SetLastError( ERROR_ACCESS_DENIED );
1899 return 0;
1901 if (wndPtr == WND_OTHER_PROCESS)
1903 if (offset == GWLP_WNDPROC)
1905 SetLastError( ERROR_ACCESS_DENIED );
1906 return 0;
1908 if (offset > 32767 || offset < -32767)
1910 SetLastError( ERROR_INVALID_INDEX );
1911 return 0;
1913 return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, MAKEWPARAM( offset, size ), newval );
1916 /* first some special cases */
1917 switch( offset )
1919 case GWL_STYLE:
1920 case GWL_EXSTYLE:
1921 style.styleOld =
1922 offset == GWL_STYLE ? wndPtr->dwStyle : wndPtr->dwExStyle;
1923 style.styleNew = newval;
1924 WIN_ReleasePtr( wndPtr );
1925 SendMessageW( hwnd, WM_STYLECHANGING, offset, (LPARAM)&style );
1926 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
1927 newval = style.styleNew;
1928 break;
1929 case GWLP_HWNDPARENT:
1930 if (wndPtr->parent == GetDesktopWindow())
1932 WIN_ReleasePtr( wndPtr );
1933 return (ULONG_PTR)WIN_SetOwner( hwnd, (HWND)newval );
1935 else
1937 WIN_ReleasePtr( wndPtr );
1938 return (ULONG_PTR)SetParent( hwnd, (HWND)newval );
1940 case GWLP_WNDPROC:
1942 WNDPROC proc;
1943 UINT old_flags = wndPtr->flags;
1944 retval = WIN_GetWindowLong( hwnd, offset, size, unicode );
1945 if (unicode) proc = WINPROC_AllocProc( NULL, (WNDPROC)newval );
1946 else proc = WINPROC_AllocProc( (WNDPROC)newval, NULL );
1947 if (proc) wndPtr->winproc = proc;
1948 if (WINPROC_IsUnicode( proc, unicode )) wndPtr->flags |= WIN_ISUNICODE;
1949 else wndPtr->flags &= ~WIN_ISUNICODE;
1950 if (!((old_flags ^ wndPtr->flags) & WIN_ISUNICODE))
1952 WIN_ReleasePtr( wndPtr );
1953 return retval;
1955 /* update is_unicode flag on the server side */
1956 break;
1958 case GWLP_ID:
1959 case GWLP_HINSTANCE:
1960 case GWLP_USERDATA:
1961 break;
1962 case DWLP_DLGPROC:
1963 if ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
1964 (size == sizeof(LONG_PTR)) && (wndPtr->flags & WIN_ISDIALOG))
1966 WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWLP_DLGPROC);
1967 retval = (ULONG_PTR)WINPROC_GetProc( *ptr, unicode );
1968 if (unicode) *ptr = WINPROC_AllocProc( NULL, (WNDPROC)newval );
1969 else *ptr = WINPROC_AllocProc( (WNDPROC)newval, NULL );
1970 WIN_ReleasePtr( wndPtr );
1971 return retval;
1973 /* fall through */
1974 default:
1975 if (offset < 0 || offset > (int)(wndPtr->cbWndExtra - size))
1977 WARN("Invalid offset %d\n", offset );
1978 WIN_ReleasePtr( wndPtr );
1979 SetLastError( ERROR_INVALID_INDEX );
1980 return 0;
1982 else if (get_win_data( (char *)wndPtr->wExtra + offset, size ) == newval)
1984 /* already set to the same value */
1985 WIN_ReleasePtr( wndPtr );
1986 return newval;
1988 break;
1991 SERVER_START_REQ( set_window_info )
1993 req->handle = hwnd;
1994 req->extra_offset = -1;
1995 switch(offset)
1997 case GWL_STYLE:
1998 req->flags = SET_WIN_STYLE;
1999 req->style = newval;
2000 break;
2001 case GWL_EXSTYLE:
2002 req->flags = SET_WIN_EXSTYLE;
2003 /* WS_EX_TOPMOST can only be changed through SetWindowPos */
2004 newval = (newval & ~WS_EX_TOPMOST) | (wndPtr->dwExStyle & WS_EX_TOPMOST);
2005 req->ex_style = newval;
2006 break;
2007 case GWLP_ID:
2008 req->flags = SET_WIN_ID;
2009 req->id = newval;
2010 break;
2011 case GWLP_HINSTANCE:
2012 req->flags = SET_WIN_INSTANCE;
2013 req->instance = (void *)newval;
2014 break;
2015 case GWLP_WNDPROC:
2016 req->flags = SET_WIN_UNICODE;
2017 req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
2018 break;
2019 case GWLP_USERDATA:
2020 req->flags = SET_WIN_USERDATA;
2021 req->user_data = newval;
2022 break;
2023 default:
2024 req->flags = SET_WIN_EXTRA;
2025 req->extra_offset = offset;
2026 req->extra_size = size;
2027 set_win_data( &req->extra_value, newval, size );
2029 if ((ok = !wine_server_call_err( req )))
2031 switch(offset)
2033 case GWL_STYLE:
2034 wndPtr->dwStyle = newval;
2035 retval = reply->old_style;
2036 break;
2037 case GWL_EXSTYLE:
2038 wndPtr->dwExStyle = newval;
2039 retval = reply->old_ex_style;
2040 break;
2041 case GWLP_ID:
2042 wndPtr->wIDmenu = newval;
2043 retval = reply->old_id;
2044 break;
2045 case GWLP_HINSTANCE:
2046 wndPtr->hInstance = (HINSTANCE)newval;
2047 retval = (ULONG_PTR)reply->old_instance;
2048 break;
2049 case GWLP_WNDPROC:
2050 break;
2051 case GWLP_USERDATA:
2052 wndPtr->userdata = newval;
2053 retval = reply->old_user_data;
2054 break;
2055 default:
2056 retval = get_win_data( (char *)wndPtr->wExtra + offset, size );
2057 set_win_data( (char *)wndPtr->wExtra + offset, newval, size );
2058 break;
2062 SERVER_END_REQ;
2063 WIN_ReleasePtr( wndPtr );
2065 if (!ok) return 0;
2067 if (offset == GWL_STYLE) USER_Driver->pSetWindowStyle( hwnd, retval );
2069 if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2070 SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2072 return retval;
2076 /**********************************************************************
2077 * GetWindowLong (USER.135)
2079 LONG WINAPI GetWindowLong16( HWND16 hwnd, INT16 offset )
2081 WND *wndPtr;
2082 LONG_PTR retvalue;
2083 BOOL is_winproc = (offset == GWLP_WNDPROC);
2085 if (offset >= 0)
2087 if (!(wndPtr = WIN_GetPtr( WIN_Handle32(hwnd) )))
2089 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2090 return 0;
2092 if (wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
2094 if (offset > (int)(wndPtr->cbWndExtra - sizeof(LONG)))
2097 * Some programs try to access last element from 16 bit
2098 * code using illegal offset value. Hopefully this is
2099 * what those programs really expect.
2101 if (wndPtr->cbWndExtra >= 4 && offset == wndPtr->cbWndExtra - sizeof(WORD))
2103 INT offset2 = wndPtr->cbWndExtra - sizeof(LONG);
2104 ERR( "- replaced invalid offset %d with %d\n", offset, offset2 );
2105 offset = offset2;
2107 else
2109 WARN("Invalid offset %d\n", offset );
2110 WIN_ReleasePtr( wndPtr );
2111 SetLastError( ERROR_INVALID_INDEX );
2112 return 0;
2115 is_winproc = ((offset == DWLP_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG));
2116 WIN_ReleasePtr( wndPtr );
2119 retvalue = GetWindowLongA( WIN_Handle32(hwnd), offset );
2120 if (is_winproc) retvalue = (LONG_PTR)WINPROC_GetProc16( (WNDPROC)retvalue, FALSE );
2121 return retvalue;
2125 /**********************************************************************
2126 * GetWindowWord (USER32.@)
2128 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
2130 switch(offset)
2132 case GWLP_ID:
2133 case GWLP_HINSTANCE:
2134 case GWLP_HWNDPARENT:
2135 break;
2136 default:
2137 if (offset < 0)
2139 WARN("Invalid offset %d\n", offset );
2140 SetLastError( ERROR_INVALID_INDEX );
2141 return 0;
2143 break;
2145 return WIN_GetWindowLong( hwnd, offset, sizeof(WORD), FALSE );
2149 /**********************************************************************
2150 * GetWindowLongA (USER32.@)
2152 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2154 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), FALSE );
2158 /**********************************************************************
2159 * GetWindowLongW (USER32.@)
2161 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2163 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), TRUE );
2167 /**********************************************************************
2168 * SetWindowLong (USER.136)
2170 LONG WINAPI SetWindowLong16( HWND16 hwnd, INT16 offset, LONG newval )
2172 WND *wndPtr;
2173 BOOL is_winproc = (offset == GWLP_WNDPROC);
2175 if (offset == DWLP_DLGPROC)
2177 if (!(wndPtr = WIN_GetPtr( WIN_Handle32(hwnd) )))
2179 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2180 return 0;
2182 if (wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
2184 is_winproc = ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
2185 (wndPtr->flags & WIN_ISDIALOG));
2186 WIN_ReleasePtr( wndPtr );
2190 if (is_winproc)
2192 WNDPROC new_proc = WINPROC_AllocProc16( (WNDPROC16)newval );
2193 WNDPROC old_proc = (WNDPROC)SetWindowLongPtrA( WIN_Handle32(hwnd), offset, (LONG_PTR)new_proc );
2194 return (LONG)WINPROC_GetProc16( old_proc, FALSE );
2196 else return SetWindowLongA( WIN_Handle32(hwnd), offset, newval );
2200 /**********************************************************************
2201 * SetWindowWord (USER32.@)
2203 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
2205 switch(offset)
2207 case GWLP_ID:
2208 case GWLP_HINSTANCE:
2209 case GWLP_HWNDPARENT:
2210 break;
2211 default:
2212 if (offset < 0)
2214 WARN("Invalid offset %d\n", offset );
2215 SetLastError( ERROR_INVALID_INDEX );
2216 return 0;
2218 break;
2220 return WIN_SetWindowLong( hwnd, offset, sizeof(WORD), newval, FALSE );
2224 /**********************************************************************
2225 * SetWindowLongA (USER32.@)
2227 * See SetWindowLongW.
2229 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2231 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, FALSE );
2235 /**********************************************************************
2236 * SetWindowLongW (USER32.@) Set window attribute
2238 * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2239 * value in a window's extra memory.
2241 * The _hwnd_ parameter specifies the window. is the handle to a
2242 * window that has extra memory. The _newval_ parameter contains the
2243 * new attribute or extra memory value. If positive, the _offset_
2244 * parameter is the byte-addressed location in the window's extra
2245 * memory to set. If negative, _offset_ specifies the window
2246 * attribute to set, and should be one of the following values:
2248 * GWL_EXSTYLE The window's extended window style
2250 * GWL_STYLE The window's window style.
2252 * GWLP_WNDPROC Pointer to the window's window procedure.
2254 * GWLP_HINSTANCE The window's pplication instance handle.
2256 * GWLP_ID The window's identifier.
2258 * GWLP_USERDATA The window's user-specified data.
2260 * If the window is a dialog box, the _offset_ parameter can be one of
2261 * the following values:
2263 * DWLP_DLGPROC The address of the window's dialog box procedure.
2265 * DWLP_MSGRESULT The return value of a message
2266 * that the dialog box procedure processed.
2268 * DWLP_USER Application specific information.
2270 * RETURNS
2272 * If successful, returns the previous value located at _offset_. Otherwise,
2273 * returns 0.
2275 * NOTES
2277 * Extra memory for a window class is specified by a nonzero cbWndExtra
2278 * parameter of the WNDCLASS structure passed to RegisterClass() at the
2279 * time of class creation.
2281 * Using GWL_WNDPROC to set a new window procedure effectively creates
2282 * a window subclass. Use CallWindowProc() in the new windows procedure
2283 * to pass messages to the superclass's window procedure.
2285 * The user data is reserved for use by the application which created
2286 * the window.
2288 * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2289 * instead, call the EnableWindow() function to change the window's
2290 * disabled state.
2292 * Do not use GWL_HWNDPARENT to reset the window's parent, use
2293 * SetParent() instead.
2295 * Win95:
2296 * When offset is GWL_STYLE and the calling app's ver is 4.0,
2297 * it sends WM_STYLECHANGING before changing the settings
2298 * and WM_STYLECHANGED afterwards.
2299 * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2301 LONG WINAPI SetWindowLongW(
2302 HWND hwnd, /* [in] window to alter */
2303 INT offset, /* [in] offset, in bytes, of location to alter */
2304 LONG newval /* [in] new value of location */
2306 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, TRUE );
2310 /*******************************************************************
2311 * GetWindowTextA (USER32.@)
2313 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2315 WCHAR *buffer;
2317 if (!lpString) return 0;
2319 if (WIN_IsCurrentProcess( hwnd ))
2320 return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2322 /* when window belongs to other process, don't send a message */
2323 if (nMaxCount <= 0) return 0;
2324 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2325 get_server_window_text( hwnd, buffer, nMaxCount );
2326 if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2327 lpString[nMaxCount-1] = 0;
2328 HeapFree( GetProcessHeap(), 0, buffer );
2329 return strlen(lpString);
2333 /*******************************************************************
2334 * InternalGetWindowText (USER32.@)
2336 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2338 WND *win;
2340 if (nMaxCount <= 0) return 0;
2341 if (!(win = WIN_GetPtr( hwnd ))) return 0;
2342 if (win == WND_DESKTOP) lpString[0] = 0;
2343 else if (win != WND_OTHER_PROCESS)
2345 if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2346 else lpString[0] = 0;
2347 WIN_ReleasePtr( win );
2349 else
2351 get_server_window_text( hwnd, lpString, nMaxCount );
2353 return strlenW(lpString);
2357 /*******************************************************************
2358 * GetWindowTextW (USER32.@)
2360 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2362 if (!lpString) return 0;
2364 if (WIN_IsCurrentProcess( hwnd ))
2365 return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2367 /* when window belongs to other process, don't send a message */
2368 if (nMaxCount <= 0) return 0;
2369 get_server_window_text( hwnd, lpString, nMaxCount );
2370 return strlenW(lpString);
2374 /*******************************************************************
2375 * SetWindowTextA (USER32.@)
2376 * SetWindowText (USER32.@)
2378 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2380 if (is_broadcast(hwnd))
2382 SetLastError( ERROR_INVALID_PARAMETER );
2383 return FALSE;
2385 if (!WIN_IsCurrentProcess( hwnd ))
2386 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2387 debugstr_a(lpString), hwnd );
2388 return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2392 /*******************************************************************
2393 * SetWindowTextW (USER32.@)
2395 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2397 if (is_broadcast(hwnd))
2399 SetLastError( ERROR_INVALID_PARAMETER );
2400 return FALSE;
2402 if (!WIN_IsCurrentProcess( hwnd ))
2403 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2404 debugstr_w(lpString), hwnd );
2405 return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2409 /*******************************************************************
2410 * GetWindowTextLengthA (USER32.@)
2412 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2414 return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2417 /*******************************************************************
2418 * GetWindowTextLengthW (USER32.@)
2420 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2422 return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2426 /*******************************************************************
2427 * IsWindow (USER32.@)
2429 BOOL WINAPI IsWindow( HWND hwnd )
2431 WND *ptr;
2432 BOOL ret;
2434 if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2435 if (ptr == WND_DESKTOP) return TRUE;
2437 if (ptr != WND_OTHER_PROCESS)
2439 WIN_ReleasePtr( ptr );
2440 return TRUE;
2443 /* check other processes */
2444 SERVER_START_REQ( get_window_info )
2446 req->handle = hwnd;
2447 ret = !wine_server_call_err( req );
2449 SERVER_END_REQ;
2450 return ret;
2454 /***********************************************************************
2455 * GetWindowThreadProcessId (USER32.@)
2457 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2459 WND *ptr;
2460 DWORD tid = 0;
2462 if (!(ptr = WIN_GetPtr( hwnd )))
2464 SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2465 return 0;
2468 if (ptr != WND_OTHER_PROCESS && ptr != WND_DESKTOP)
2470 /* got a valid window */
2471 tid = ptr->tid;
2472 if (process) *process = GetCurrentProcessId();
2473 WIN_ReleasePtr( ptr );
2474 return tid;
2477 /* check other processes */
2478 SERVER_START_REQ( get_window_info )
2480 req->handle = hwnd;
2481 if (!wine_server_call_err( req ))
2483 tid = (DWORD)reply->tid;
2484 if (process) *process = (DWORD)reply->pid;
2487 SERVER_END_REQ;
2488 return tid;
2492 /*****************************************************************
2493 * GetParent (USER32.@)
2495 HWND WINAPI GetParent( HWND hwnd )
2497 WND *wndPtr;
2498 HWND retvalue = 0;
2500 if (!(wndPtr = WIN_GetPtr( hwnd )))
2502 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2503 return 0;
2505 if (wndPtr == WND_DESKTOP) return 0;
2506 if (wndPtr == WND_OTHER_PROCESS)
2508 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2509 if (style & (WS_POPUP | WS_CHILD))
2511 SERVER_START_REQ( get_window_tree )
2513 req->handle = hwnd;
2514 if (!wine_server_call_err( req ))
2516 if (style & WS_POPUP) retvalue = reply->owner;
2517 else if (style & WS_CHILD) retvalue = reply->parent;
2520 SERVER_END_REQ;
2523 else
2525 if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2526 else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2527 WIN_ReleasePtr( wndPtr );
2529 return retvalue;
2533 /*****************************************************************
2534 * GetAncestor (USER32.@)
2536 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2538 WND *win;
2539 HWND *list, ret = 0;
2541 switch(type)
2543 case GA_PARENT:
2544 if (!(win = WIN_GetPtr( hwnd )))
2546 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2547 return 0;
2549 if (win == WND_DESKTOP) return 0;
2550 if (win != WND_OTHER_PROCESS)
2552 ret = win->parent;
2553 WIN_ReleasePtr( win );
2555 else /* need to query the server */
2557 SERVER_START_REQ( get_window_tree )
2559 req->handle = hwnd;
2560 if (!wine_server_call_err( req )) ret = reply->parent;
2562 SERVER_END_REQ;
2564 break;
2566 case GA_ROOT:
2567 if (!(list = list_window_parents( hwnd ))) return 0;
2569 if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd ); /* top-level window */
2570 else
2572 int count = 2;
2573 while (list[count]) count++;
2574 ret = list[count - 2]; /* get the one before the desktop */
2576 HeapFree( GetProcessHeap(), 0, list );
2577 break;
2579 case GA_ROOTOWNER:
2580 if ((ret = WIN_GetFullHandle( hwnd )) == GetDesktopWindow()) return 0;
2581 for (;;)
2583 HWND parent = GetParent( ret );
2584 if (!parent) break;
2585 ret = parent;
2587 break;
2589 return ret;
2593 /*****************************************************************
2594 * SetParent (USER32.@)
2596 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2598 HWND full_handle;
2599 HWND old_parent = 0;
2600 BOOL was_visible;
2601 WND *wndPtr;
2602 BOOL ret;
2604 if (is_broadcast(hwnd) || is_broadcast(parent))
2606 SetLastError(ERROR_INVALID_PARAMETER);
2607 return 0;
2610 if (!parent) parent = GetDesktopWindow();
2611 else parent = WIN_GetFullHandle( parent );
2613 if (!IsWindow( parent ))
2615 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2616 return 0;
2619 /* Some applications try to set a child as a parent */
2620 if (IsChild(hwnd, parent))
2622 SetLastError( ERROR_INVALID_PARAMETER );
2623 return 0;
2626 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2627 return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2629 /* Windows hides the window first, then shows it again
2630 * including the WM_SHOWWINDOW messages and all */
2631 was_visible = ShowWindow( hwnd, SW_HIDE );
2633 wndPtr = WIN_GetPtr( hwnd );
2634 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
2636 SERVER_START_REQ( set_parent )
2638 req->handle = hwnd;
2639 req->parent = parent;
2640 if ((ret = !wine_server_call( req )))
2642 old_parent = reply->old_parent;
2643 wndPtr->parent = parent = reply->full_parent;
2647 SERVER_END_REQ;
2648 WIN_ReleasePtr( wndPtr );
2649 if (!ret) return 0;
2651 USER_Driver->pSetParent( full_handle, parent, old_parent );
2653 /* SetParent additionally needs to make hwnd the topmost window
2654 in the x-order and send the expected WM_WINDOWPOSCHANGING and
2655 WM_WINDOWPOSCHANGED notification messages.
2657 SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0,
2658 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | (was_visible ? SWP_SHOWWINDOW : 0) );
2659 /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
2660 * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
2662 return old_parent;
2666 /*******************************************************************
2667 * IsChild (USER32.@)
2669 BOOL WINAPI IsChild( HWND parent, HWND child )
2671 HWND *list = list_window_parents( child );
2672 int i;
2673 BOOL ret;
2675 if (!list) return FALSE;
2676 parent = WIN_GetFullHandle( parent );
2677 for (i = 0; list[i]; i++) if (list[i] == parent) break;
2678 ret = list[i] && list[i+1];
2679 HeapFree( GetProcessHeap(), 0, list );
2680 return ret;
2684 /***********************************************************************
2685 * IsWindowVisible (USER32.@)
2687 BOOL WINAPI IsWindowVisible( HWND hwnd )
2689 HWND *list;
2690 BOOL retval = TRUE;
2691 int i;
2693 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2694 if (!(list = list_window_parents( hwnd ))) return TRUE;
2695 if (list[0] && list[1]) /* desktop window is considered always visible so we don't check it */
2697 for (i = 0; list[i+1]; i++)
2698 if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2699 retval = !list[i+1];
2701 HeapFree( GetProcessHeap(), 0, list );
2702 return retval;
2706 /***********************************************************************
2707 * WIN_IsWindowDrawable
2709 * hwnd is drawable when it is visible, all parents are not
2710 * minimized, and it is itself not minimized unless we are
2711 * trying to draw its default class icon.
2713 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2715 HWND *list;
2716 BOOL retval = TRUE;
2717 int i;
2718 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2720 if (!(style & WS_VISIBLE)) return FALSE;
2721 if ((style & WS_MINIMIZE) && icon && GetClassLongPtrW( hwnd, GCLP_HICON )) return FALSE;
2723 if (!(list = list_window_parents( hwnd ))) return TRUE;
2724 if (list[0] && list[1]) /* desktop window is considered always visible so we don't check it */
2726 for (i = 0; list[i+1]; i++)
2727 if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2728 break;
2729 retval = !list[i+1];
2731 HeapFree( GetProcessHeap(), 0, list );
2732 return retval;
2736 /*******************************************************************
2737 * GetTopWindow (USER32.@)
2739 HWND WINAPI GetTopWindow( HWND hwnd )
2741 if (!hwnd) hwnd = GetDesktopWindow();
2742 return GetWindow( hwnd, GW_CHILD );
2746 /*******************************************************************
2747 * GetWindow (USER32.@)
2749 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2751 HWND retval = 0;
2753 if (rel == GW_OWNER) /* this one may be available locally */
2755 WND *wndPtr = WIN_GetPtr( hwnd );
2756 if (!wndPtr)
2758 SetLastError( ERROR_INVALID_HANDLE );
2759 return 0;
2761 if (wndPtr == WND_DESKTOP) return 0;
2762 if (wndPtr != WND_OTHER_PROCESS)
2764 retval = wndPtr->owner;
2765 WIN_ReleasePtr( wndPtr );
2766 return retval;
2768 /* else fall through to server call */
2771 SERVER_START_REQ( get_window_tree )
2773 req->handle = hwnd;
2774 if (!wine_server_call_err( req ))
2776 switch(rel)
2778 case GW_HWNDFIRST:
2779 retval = reply->first_sibling;
2780 break;
2781 case GW_HWNDLAST:
2782 retval = reply->last_sibling;
2783 break;
2784 case GW_HWNDNEXT:
2785 retval = reply->next_sibling;
2786 break;
2787 case GW_HWNDPREV:
2788 retval = reply->prev_sibling;
2789 break;
2790 case GW_OWNER:
2791 retval = reply->owner;
2792 break;
2793 case GW_CHILD:
2794 retval = reply->first_child;
2795 break;
2799 SERVER_END_REQ;
2800 return retval;
2804 /*******************************************************************
2805 * ShowOwnedPopups (USER32.@)
2807 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2809 int count = 0;
2810 WND *pWnd;
2811 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2813 if (!win_array) return TRUE;
2815 while (win_array[count]) count++;
2816 while (--count >= 0)
2818 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2819 if (!(pWnd = WIN_GetPtr( win_array[count] ))) continue;
2820 if (pWnd == WND_OTHER_PROCESS) continue;
2821 if (fShow)
2823 if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2825 WIN_ReleasePtr( pWnd );
2826 /* In Windows, ShowOwnedPopups(TRUE) generates
2827 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
2828 * regardless of the state of the owner
2830 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
2831 continue;
2834 else
2836 if (pWnd->dwStyle & WS_VISIBLE)
2838 WIN_ReleasePtr( pWnd );
2839 /* In Windows, ShowOwnedPopups(FALSE) generates
2840 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
2841 * regardless of the state of the owner
2843 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
2844 continue;
2847 WIN_ReleasePtr( pWnd );
2849 HeapFree( GetProcessHeap(), 0, win_array );
2850 return TRUE;
2854 /*******************************************************************
2855 * GetLastActivePopup (USER32.@)
2857 HWND WINAPI GetLastActivePopup( HWND hwnd )
2859 HWND retval = hwnd;
2861 SERVER_START_REQ( get_window_info )
2863 req->handle = hwnd;
2864 if (!wine_server_call_err( req )) retval = reply->last_active;
2866 SERVER_END_REQ;
2867 return retval;
2871 /*******************************************************************
2872 * WIN_ListChildren
2874 * Build an array of the children of a given window. The array must be
2875 * freed with HeapFree. Returns NULL when no windows are found.
2877 HWND *WIN_ListChildren( HWND hwnd )
2879 return list_window_children( 0, hwnd, NULL, 0 );
2883 /*******************************************************************
2884 * EnumWindows (USER32.@)
2886 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
2888 HWND *list;
2889 BOOL ret = TRUE;
2890 int i;
2892 USER_CheckNotLock();
2894 /* We have to build a list of all windows first, to avoid */
2895 /* unpleasant side-effects, for instance if the callback */
2896 /* function changes the Z-order of the windows. */
2898 if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
2900 /* Now call the callback function for every window */
2902 for (i = 0; list[i]; i++)
2904 /* Make sure that the window still exists */
2905 if (!IsWindow( list[i] )) continue;
2906 if (!(ret = lpEnumFunc( list[i], lParam ))) break;
2908 HeapFree( GetProcessHeap(), 0, list );
2909 return ret;
2913 /**********************************************************************
2914 * EnumThreadWindows (USER32.@)
2916 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
2918 HWND *list;
2919 int i;
2921 USER_CheckNotLock();
2923 if (!(list = list_window_children( 0, GetDesktopWindow(), NULL, id ))) return TRUE;
2925 /* Now call the callback function for every window */
2927 for (i = 0; list[i]; i++)
2928 if (!func( list[i], lParam )) break;
2929 HeapFree( GetProcessHeap(), 0, list );
2930 return TRUE;
2934 /***********************************************************************
2935 * EnumDesktopWindows (USER32.@)
2937 BOOL WINAPI EnumDesktopWindows( HDESK desktop, WNDENUMPROC func, LPARAM lparam )
2939 HWND *list;
2940 int i;
2942 USER_CheckNotLock();
2944 if (!(list = list_window_children( desktop, 0, NULL, 0 ))) return TRUE;
2946 for (i = 0; list[i]; i++)
2947 if (!func( list[i], lparam )) break;
2948 HeapFree( GetProcessHeap(), 0, list );
2949 return TRUE;
2953 /**********************************************************************
2954 * WIN_EnumChildWindows
2956 * Helper function for EnumChildWindows().
2958 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
2960 HWND *childList;
2961 BOOL ret = FALSE;
2963 for ( ; *list; list++)
2965 /* Make sure that the window still exists */
2966 if (!IsWindow( *list )) continue;
2967 /* Build children list first */
2968 childList = WIN_ListChildren( *list );
2970 ret = func( *list, lParam );
2972 if (childList)
2974 if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
2975 HeapFree( GetProcessHeap(), 0, childList );
2977 if (!ret) return FALSE;
2979 return TRUE;
2983 /**********************************************************************
2984 * EnumChildWindows (USER32.@)
2986 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
2988 HWND *list;
2989 BOOL ret;
2991 USER_CheckNotLock();
2993 if (!(list = WIN_ListChildren( parent ))) return FALSE;
2994 ret = WIN_EnumChildWindows( list, func, lParam );
2995 HeapFree( GetProcessHeap(), 0, list );
2996 return ret;
3000 /*******************************************************************
3001 * AnyPopup (USER.52)
3003 BOOL16 WINAPI AnyPopup16(void)
3005 return AnyPopup();
3009 /*******************************************************************
3010 * AnyPopup (USER32.@)
3012 BOOL WINAPI AnyPopup(void)
3014 int i;
3015 BOOL retvalue;
3016 HWND *list = WIN_ListChildren( GetDesktopWindow() );
3018 if (!list) return FALSE;
3019 for (i = 0; list[i]; i++)
3021 if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
3023 retvalue = (list[i] != 0);
3024 HeapFree( GetProcessHeap(), 0, list );
3025 return retvalue;
3029 /*******************************************************************
3030 * FlashWindow (USER32.@)
3032 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3034 WND *wndPtr;
3036 TRACE("%p\n", hWnd);
3038 if (IsIconic( hWnd ))
3040 RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
3042 wndPtr = WIN_GetPtr(hWnd);
3043 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3044 if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
3046 wndPtr->flags |= WIN_NCACTIVATED;
3048 else
3050 wndPtr->flags &= ~WIN_NCACTIVATED;
3052 WIN_ReleasePtr( wndPtr );
3053 return TRUE;
3055 else
3057 WPARAM wparam;
3059 wndPtr = WIN_GetPtr(hWnd);
3060 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3061 hWnd = wndPtr->hwndSelf; /* make it a full handle */
3063 if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3064 else wparam = (hWnd == GetForegroundWindow());
3066 WIN_ReleasePtr( wndPtr );
3067 SendMessageW( hWnd, WM_NCACTIVATE, wparam, (LPARAM)0 );
3068 return wparam;
3072 /*******************************************************************
3073 * FlashWindowEx (USER32.@)
3075 BOOL WINAPI FlashWindowEx( PFLASHWINFO pfwi )
3077 FIXME("%p\n", pfwi);
3078 return TRUE;
3081 /*******************************************************************
3082 * GetWindowContextHelpId (USER32.@)
3084 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3086 DWORD retval;
3087 WND *wnd = WIN_GetPtr( hwnd );
3088 if (!wnd || wnd == WND_DESKTOP) return 0;
3089 if (wnd == WND_OTHER_PROCESS)
3091 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3092 return 0;
3094 retval = wnd->helpContext;
3095 WIN_ReleasePtr( wnd );
3096 return retval;
3100 /*******************************************************************
3101 * SetWindowContextHelpId (USER32.@)
3103 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3105 WND *wnd = WIN_GetPtr( hwnd );
3106 if (!wnd || wnd == WND_DESKTOP) return FALSE;
3107 if (wnd == WND_OTHER_PROCESS)
3109 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3110 return 0;
3112 wnd->helpContext = id;
3113 WIN_ReleasePtr( wnd );
3114 return TRUE;
3118 /*******************************************************************
3119 * DragDetect (USER32.@)
3121 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3123 MSG msg;
3124 RECT rect;
3125 WORD wDragWidth = GetSystemMetrics(SM_CXDRAG);
3126 WORD wDragHeight= GetSystemMetrics(SM_CYDRAG);
3128 rect.left = pt.x - wDragWidth;
3129 rect.right = pt.x + wDragWidth;
3131 rect.top = pt.y - wDragHeight;
3132 rect.bottom = pt.y + wDragHeight;
3134 SetCapture(hWnd);
3136 while(1)
3138 while (PeekMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ))
3140 if( msg.message == WM_LBUTTONUP )
3142 ReleaseCapture();
3143 return 0;
3145 if( msg.message == WM_MOUSEMOVE )
3147 POINT tmp;
3148 tmp.x = (short)LOWORD(msg.lParam);
3149 tmp.y = (short)HIWORD(msg.lParam);
3150 if( !PtInRect( &rect, tmp ))
3152 ReleaseCapture();
3153 return 1;
3157 WaitMessage();
3159 return 0;
3162 /******************************************************************************
3163 * GetWindowModuleFileNameA (USER32.@)
3165 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR lpszFileName, UINT cchFileNameMax)
3167 FIXME("GetWindowModuleFileNameA(hwnd %p, lpszFileName %p, cchFileNameMax %u) stub!\n",
3168 hwnd, lpszFileName, cchFileNameMax);
3169 return 0;
3172 /******************************************************************************
3173 * GetWindowModuleFileNameW (USER32.@)
3175 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR lpszFileName, UINT cchFileNameMax)
3177 FIXME("GetWindowModuleFileNameW(hwnd %p, lpszFileName %p, cchFileNameMax %u) stub!\n",
3178 hwnd, lpszFileName, cchFileNameMax);
3179 return 0;
3182 /******************************************************************************
3183 * GetWindowInfo (USER32.@)
3185 * Note: tests show that Windows doesn't check cbSize of the structure.
3187 BOOL WINAPI GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3189 if (!pwi) return FALSE;
3190 if (!IsWindow(hwnd)) return FALSE;
3192 GetWindowRect(hwnd, &pwi->rcWindow);
3193 GetClientRect(hwnd, &pwi->rcClient);
3194 /* translate to screen coordinates */
3195 MapWindowPoints(hwnd, 0, (LPPOINT)&pwi->rcClient, 2);
3197 pwi->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
3198 pwi->dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3199 pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3201 pwi->cxWindowBorders = pwi->rcClient.left - pwi->rcWindow.left;
3202 pwi->cyWindowBorders = pwi->rcWindow.bottom - pwi->rcClient.bottom;
3204 pwi->atomWindowType = GetClassLongW( hwnd, GCW_ATOM );
3205 pwi->wCreatorVersion = 0x0400;
3207 return TRUE;
3210 /******************************************************************************
3211 * SwitchDesktop (USER32.@)
3213 * NOTES: Sets the current input or interactive desktop.
3215 BOOL WINAPI SwitchDesktop( HDESK hDesktop)
3217 FIXME("SwitchDesktop(hwnd %p) stub!\n", hDesktop);
3218 return TRUE;
3221 /*****************************************************************************
3222 * SetLayeredWindowAttributes (USER32.@)
3224 BOOL WINAPI SetLayeredWindowAttributes( HWND hWnd, COLORREF rgbKey,
3225 BYTE bAlpha, DWORD dwFlags )
3227 FIXME("(%p,0x%.8x,%d,%d): stub!\n", hWnd, rgbKey, bAlpha, dwFlags);
3228 return TRUE;
3231 /*****************************************************************************
3232 * GetLayeredWindowAttributes (USER32.@)
3234 BOOL WINAPI GetLayeredWindowAttributes( HWND hWnd, COLORREF *prgbKey,
3235 BYTE *pbAlpha, DWORD *pdwFlags )
3237 FIXME("(%p,%p,%p,%p): stub!\n", hWnd, prgbKey, pbAlpha, pdwFlags);
3238 return FALSE;
3241 /*****************************************************************************
3242 * UpdateLayeredWindow (USER32.@)
3244 BOOL WINAPI UpdateLayeredWindow( HWND hwnd, HDC hdcDst, POINT *pptDst, SIZE *psize,
3245 HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend,
3246 DWORD dwFlags)
3248 static int once;
3249 if (!once)
3251 once = 1;
3252 FIXME("(%p,%p,%p,%p,%p,%p,0x%08x,%p,%d): stub!\n",
3253 hwnd, hdcDst, pptDst, psize, hdcSrc, pptSrc, crKey, pblend, dwFlags);
3255 return 0;
3258 /* 64bit versions */
3260 #ifdef GetWindowLongPtrW
3261 #undef GetWindowLongPtrW
3262 #endif
3264 #ifdef GetWindowLongPtrA
3265 #undef GetWindowLongPtrA
3266 #endif
3268 #ifdef SetWindowLongPtrW
3269 #undef SetWindowLongPtrW
3270 #endif
3272 #ifdef SetWindowLongPtrA
3273 #undef SetWindowLongPtrA
3274 #endif
3276 /*****************************************************************************
3277 * GetWindowLongPtrW (USER32.@)
3279 LONG_PTR WINAPI GetWindowLongPtrW( HWND hwnd, INT offset )
3281 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), TRUE );
3284 /*****************************************************************************
3285 * GetWindowLongPtrA (USER32.@)
3287 LONG_PTR WINAPI GetWindowLongPtrA( HWND hwnd, INT offset )
3289 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), FALSE );
3292 /*****************************************************************************
3293 * SetWindowLongPtrW (USER32.@)
3295 LONG_PTR WINAPI SetWindowLongPtrW( HWND hwnd, INT offset, LONG_PTR newval )
3297 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, TRUE );
3300 /*****************************************************************************
3301 * SetWindowLongPtrA (USER32.@)
3303 LONG_PTR WINAPI SetWindowLongPtrA( HWND hwnd, INT offset, LONG_PTR newval )
3305 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, FALSE );