push b59ba84f7e04af9ef068bd4c6e96701941f0256e
[wine/hacks.git] / dlls / user32 / win.c
blob8e02a5dcd2ccc5f23ce24134a62534ebf89d5dc9
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(), 0, sizeof(WND) + extra_bytes - sizeof(win->wExtra) )))
138 SERVER_START_REQ( destroy_window )
140 req->handle = handle;
141 wine_server_call( req );
143 SERVER_END_REQ;
144 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
145 return NULL;
148 if (!parent) /* if parent is 0 we don't have a desktop window yet */
150 struct user_thread_info *thread_info = get_user_thread_info();
152 if (!thread_info->desktop) thread_info->desktop = full_parent ? full_parent : handle;
153 else assert( full_parent == thread_info->desktop );
154 if (full_parent && !USER_Driver->pCreateDesktopWindow( thread_info->desktop ))
155 ERR( "failed to create desktop window\n" );
158 USER_Lock();
160 index = USER_HANDLE_TO_INDEX(handle);
161 assert( index < NB_USER_HANDLES );
162 user_handles[index] = win;
163 win->hwndSelf = handle;
164 win->parent = full_parent;
165 win->owner = full_owner;
166 win->dwMagic = WND_MAGIC;
167 win->flags = 0;
168 win->cbWndExtra = extra_bytes;
169 SetRectEmpty( &win->rectWindow );
170 SetRectEmpty( &win->rectClient );
171 memset( win->wExtra, 0, extra_bytes );
172 CLASS_AddWindow( class, win, unicode );
173 return win;
177 /***********************************************************************
178 * free_window_handle
180 * Free a window handle.
182 static WND *free_window_handle( HWND hwnd )
184 WND *ptr;
185 WORD index = USER_HANDLE_TO_INDEX(hwnd);
187 if (index >= NB_USER_HANDLES) return NULL;
188 USER_Lock();
189 if ((ptr = user_handles[index]))
191 SERVER_START_REQ( destroy_window )
193 req->handle = hwnd;
194 if (!wine_server_call_err( req ))
196 user_handles[index] = NULL;
197 ptr->dwMagic = 0;
199 else
200 ptr = NULL;
202 SERVER_END_REQ;
204 USER_Unlock();
205 HeapFree( GetProcessHeap(), 0, ptr );
206 return ptr;
210 /*******************************************************************
211 * list_window_children
213 * Build an array of the children of a given window. The array must be
214 * freed with HeapFree. Returns NULL when no windows are found.
216 static HWND *list_window_children( HWND hwnd, LPCWSTR class, DWORD tid )
218 HWND *list;
219 int size = 32;
221 for (;;)
223 int count = 0;
225 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) break;
227 SERVER_START_REQ( get_window_children )
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 (++pos == size - 1)
279 /* need to grow the list */
280 HWND *new_list = HeapReAlloc( GetProcessHeap(), 0, list, (size+16) * sizeof(HWND) );
281 if (!new_list) goto empty;
282 list = new_list;
283 size += 16;
287 /* at least one parent belongs to another process, have to query the server */
289 for (;;)
291 count = 0;
292 SERVER_START_REQ( get_window_parents )
294 req->handle = hwnd;
295 wine_server_set_reply( req, list, (size-1) * sizeof(HWND) );
296 if (!wine_server_call( req )) count = reply->count;
298 SERVER_END_REQ;
299 if (!count) goto empty;
300 if (size > count)
302 list[count] = 0;
303 return list;
305 HeapFree( GetProcessHeap(), 0, list );
306 size = count + 1;
307 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
310 empty:
311 HeapFree( GetProcessHeap(), 0, list );
312 return NULL;
316 /*******************************************************************
317 * send_parent_notify
319 static void send_parent_notify( HWND hwnd, UINT msg )
321 if ((GetWindowLongW( hwnd, GWL_STYLE ) & (WS_CHILD | WS_POPUP)) == WS_CHILD &&
322 !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOPARENTNOTIFY))
324 HWND parent = GetParent(hwnd);
325 if (parent && parent != GetDesktopWindow())
326 SendMessageW( parent, WM_PARENTNOTIFY,
327 MAKEWPARAM( msg, GetWindowLongPtrW( hwnd, GWLP_ID )), (LPARAM)hwnd );
332 /*******************************************************************
333 * get_server_window_text
335 * Retrieve the window text from the server.
337 static void get_server_window_text( HWND hwnd, LPWSTR text, INT count )
339 size_t len = 0;
341 SERVER_START_REQ( get_window_text )
343 req->handle = hwnd;
344 wine_server_set_reply( req, text, (count - 1) * sizeof(WCHAR) );
345 if (!wine_server_call_err( req )) len = wine_server_reply_size(reply);
347 SERVER_END_REQ;
348 text[len / sizeof(WCHAR)] = 0;
352 /***********************************************************************
353 * WIN_GetPtr
355 * Return a pointer to the WND structure if local to the process,
356 * or WND_OTHER_PROCESS if handle may be valid in other process.
357 * If ret value is a valid pointer, it must be released with WIN_ReleasePtr.
359 WND *WIN_GetPtr( HWND hwnd )
361 WND * ptr;
362 WORD index = USER_HANDLE_TO_INDEX(hwnd);
364 if (index >= NB_USER_HANDLES) return NULL;
366 USER_Lock();
367 if ((ptr = user_handles[index]))
369 if (ptr->dwMagic == WND_MAGIC &&
370 (hwnd == ptr->hwndSelf || !HIWORD(hwnd) || HIWORD(hwnd) == 0xffff))
371 return ptr;
372 ptr = NULL;
374 else if (index == USER_HANDLE_TO_INDEX(GetDesktopWindow()))
376 if (hwnd == GetDesktopWindow() || !HIWORD(hwnd) || HIWORD(hwnd) == 0xffff) ptr = WND_DESKTOP;
377 else ptr = NULL;
379 else ptr = WND_OTHER_PROCESS;
380 USER_Unlock();
381 return ptr;
385 /***********************************************************************
386 * WIN_IsCurrentProcess
388 * Check whether a given window belongs to the current process (and return the full handle).
390 HWND WIN_IsCurrentProcess( HWND hwnd )
392 WND *ptr;
393 HWND ret;
395 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
396 ret = ptr->hwndSelf;
397 WIN_ReleasePtr( ptr );
398 return ret;
402 /***********************************************************************
403 * WIN_IsCurrentThread
405 * Check whether a given window belongs to the current thread (and return the full handle).
407 HWND WIN_IsCurrentThread( HWND hwnd )
409 WND *ptr;
410 HWND ret = 0;
412 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
413 if (ptr->tid == GetCurrentThreadId()) ret = ptr->hwndSelf;
414 WIN_ReleasePtr( ptr );
415 return ret;
419 /***********************************************************************
420 * WIN_Handle32
422 * Convert a 16-bit window handle to a full 32-bit handle.
424 HWND WIN_Handle32( HWND16 hwnd16 )
426 WND *ptr;
427 HWND hwnd = (HWND)(ULONG_PTR)hwnd16;
429 if (hwnd16 <= 1 || hwnd16 == 0xffff) return hwnd;
430 /* do sign extension for -2 and -3 */
431 if (hwnd16 >= (HWND16)-3) return (HWND)(LONG_PTR)(INT16)hwnd16;
433 if (!(ptr = WIN_GetPtr( hwnd ))) return hwnd;
435 if (ptr == WND_DESKTOP) return GetDesktopWindow();
437 if (ptr != WND_OTHER_PROCESS)
439 hwnd = ptr->hwndSelf;
440 WIN_ReleasePtr( ptr );
442 else /* may belong to another process */
444 SERVER_START_REQ( get_window_info )
446 req->handle = hwnd;
447 if (!wine_server_call_err( req )) hwnd = reply->full_handle;
449 SERVER_END_REQ;
451 return hwnd;
455 /***********************************************************************
456 * WIN_SetOwner
458 * Change the owner of a window.
460 HWND WIN_SetOwner( HWND hwnd, HWND owner )
462 WND *win = WIN_GetPtr( hwnd );
463 HWND ret = 0;
465 if (!win || win == WND_DESKTOP) return 0;
466 if (win == WND_OTHER_PROCESS)
468 if (IsWindow(hwnd)) ERR( "cannot set owner %p on other process window %p\n", owner, hwnd );
469 return 0;
471 SERVER_START_REQ( set_window_owner )
473 req->handle = hwnd;
474 req->owner = owner;
475 if (!wine_server_call( req ))
477 win->owner = reply->full_owner;
478 ret = reply->prev_owner;
481 SERVER_END_REQ;
482 WIN_ReleasePtr( win );
483 return ret;
487 /***********************************************************************
488 * WIN_SetStyle
490 * Change the style of a window.
492 ULONG WIN_SetStyle( HWND hwnd, ULONG set_bits, ULONG clear_bits )
494 BOOL ok;
495 ULONG new_style, old_style = 0;
496 WND *win = WIN_GetPtr( hwnd );
498 if (!win || win == WND_DESKTOP) return 0;
499 if (win == WND_OTHER_PROCESS)
501 if (IsWindow(hwnd))
502 ERR( "cannot set style %x/%x on other process window %p\n",
503 set_bits, clear_bits, hwnd );
504 return 0;
506 new_style = (win->dwStyle | set_bits) & ~clear_bits;
507 if (new_style == win->dwStyle)
509 WIN_ReleasePtr( win );
510 return new_style;
512 SERVER_START_REQ( set_window_info )
514 req->handle = hwnd;
515 req->flags = SET_WIN_STYLE;
516 req->style = new_style;
517 req->extra_offset = -1;
518 if ((ok = !wine_server_call( req )))
520 old_style = reply->old_style;
521 win->dwStyle = new_style;
524 SERVER_END_REQ;
525 WIN_ReleasePtr( win );
526 if (ok) USER_Driver->pSetWindowStyle( hwnd, old_style );
527 return old_style;
531 /***********************************************************************
532 * WIN_GetRectangles
534 * Get the window and client rectangles.
536 BOOL WIN_GetRectangles( HWND hwnd, RECT *rectWindow, RECT *rectClient )
538 WND *win = WIN_GetPtr( hwnd );
539 BOOL ret = TRUE;
541 if (!win) return FALSE;
542 if (win == WND_DESKTOP)
544 RECT rect;
545 rect.left = rect.top = 0;
546 rect.right = GetSystemMetrics(SM_CXSCREEN);
547 rect.bottom = GetSystemMetrics(SM_CYSCREEN);
548 if (rectWindow) *rectWindow = rect;
549 if (rectClient) *rectClient = rect;
551 else if (win == WND_OTHER_PROCESS)
553 SERVER_START_REQ( get_window_rectangles )
555 req->handle = hwnd;
556 if ((ret = !wine_server_call( req )))
558 if (rectWindow)
560 rectWindow->left = reply->window.left;
561 rectWindow->top = reply->window.top;
562 rectWindow->right = reply->window.right;
563 rectWindow->bottom = reply->window.bottom;
565 if (rectClient)
567 rectClient->left = reply->client.left;
568 rectClient->top = reply->client.top;
569 rectClient->right = reply->client.right;
570 rectClient->bottom = reply->client.bottom;
574 SERVER_END_REQ;
576 else
578 if (rectWindow) *rectWindow = win->rectWindow;
579 if (rectClient) *rectClient = win->rectClient;
580 WIN_ReleasePtr( win );
582 return ret;
586 /***********************************************************************
587 * WIN_DestroyWindow
589 * Destroy storage associated to a window. "Internals" p.358
591 LRESULT WIN_DestroyWindow( HWND hwnd )
593 WND *wndPtr;
594 HWND *list;
595 HMENU menu = 0, sys_menu;
597 TRACE("%p\n", hwnd );
599 /* free child windows */
600 if ((list = WIN_ListChildren( hwnd )))
602 int i;
603 for (i = 0; list[i]; i++)
605 if (WIN_IsCurrentThread( list[i] )) WIN_DestroyWindow( list[i] );
606 else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
608 HeapFree( GetProcessHeap(), 0, list );
611 /* Unlink now so we won't bother with the children later on */
612 SERVER_START_REQ( set_parent )
614 req->handle = hwnd;
615 req->parent = 0;
616 wine_server_call( req );
618 SERVER_END_REQ;
621 * Send the WM_NCDESTROY to the window being destroyed.
623 SendMessageW( hwnd, WM_NCDESTROY, 0, 0 );
625 /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
627 WINPOS_CheckInternalPos( hwnd );
629 /* free resources associated with the window */
631 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
632 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
633 menu = (HMENU)wndPtr->wIDmenu;
634 sys_menu = wndPtr->hSysMenu;
635 WIN_ReleasePtr( wndPtr );
637 if (menu) DestroyMenu( menu );
638 if (sys_menu) DestroyMenu( sys_menu );
640 USER_Driver->pDestroyWindow( hwnd );
642 free_window_handle( hwnd );
643 return 0;
646 /***********************************************************************
647 * WIN_DestroyThreadWindows
649 * Destroy all children of 'wnd' owned by the current thread.
651 void WIN_DestroyThreadWindows( HWND hwnd )
653 HWND *list;
654 int i;
656 if (!(list = WIN_ListChildren( hwnd ))) return;
657 for (i = 0; list[i]; i++)
659 if (WIN_IsCurrentThread( list[i] ))
660 DestroyWindow( list[i] );
661 else
662 WIN_DestroyThreadWindows( list[i] );
664 HeapFree( GetProcessHeap(), 0, list );
668 /***********************************************************************
669 * WIN_FixCoordinates
671 * Fix the coordinates - Helper for WIN_CreateWindowEx.
672 * returns default show mode in sw.
674 static void WIN_FixCoordinates( CREATESTRUCTA *cs, INT *sw)
676 #define IS_DEFAULT(x) ((x) == CW_USEDEFAULT || (x) == CW_USEDEFAULT16)
677 POINT pos[2];
679 if (cs->dwExStyle & WS_EX_MDICHILD)
681 UINT id = 0;
683 MDI_CalcDefaultChildPos(cs->hwndParent, -1, pos, 0, &id);
684 if (!(cs->style & WS_POPUP)) cs->hMenu = ULongToHandle(id);
686 TRACE("MDI child id %04x\n", id);
689 if (cs->style & (WS_CHILD | WS_POPUP))
691 if (cs->dwExStyle & WS_EX_MDICHILD)
693 if (IS_DEFAULT(cs->x))
695 cs->x = pos[0].x;
696 cs->y = pos[0].y;
698 if (IS_DEFAULT(cs->cx) || !cs->cx) cs->cx = pos[1].x;
699 if (IS_DEFAULT(cs->cy) || !cs->cy) cs->cy = pos[1].y;
701 else
703 if (IS_DEFAULT(cs->x)) cs->x = cs->y = 0;
704 if (IS_DEFAULT(cs->cx)) cs->cx = cs->cy = 0;
707 else /* overlapped window */
709 HMONITOR monitor;
710 MONITORINFO mon_info;
711 STARTUPINFOW info;
713 if (!IS_DEFAULT(cs->x) && !IS_DEFAULT(cs->cx) && !IS_DEFAULT(cs->cy)) return;
715 monitor = MonitorFromWindow( cs->hwndParent, MONITOR_DEFAULTTOPRIMARY );
716 mon_info.cbSize = sizeof(mon_info);
717 GetMonitorInfoW( monitor, &mon_info );
718 GetStartupInfoW( &info );
720 if (IS_DEFAULT(cs->x))
722 if (!IS_DEFAULT(cs->y)) *sw = cs->y;
723 cs->x = (info.dwFlags & STARTF_USEPOSITION) ? info.dwX : mon_info.rcWork.left;
724 cs->y = (info.dwFlags & STARTF_USEPOSITION) ? info.dwY : mon_info.rcWork.top;
727 if (IS_DEFAULT(cs->cx))
729 if (info.dwFlags & STARTF_USESIZE)
731 cs->cx = info.dwXSize;
732 cs->cy = info.dwYSize;
734 else
736 cs->cx = (mon_info.rcWork.right - mon_info.rcWork.left) * 3 / 4 - cs->x;
737 cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
740 /* neither x nor cx are default. Check the y values .
741 * In the trace we see Outlook and Outlook Express using
742 * cy set to CW_USEDEFAULT when opening the address book.
744 else if (IS_DEFAULT(cs->cy))
746 FIXME("Strange use of CW_USEDEFAULT in nHeight\n");
747 cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
750 #undef IS_DEFAULT
753 /***********************************************************************
754 * dump_window_styles
756 static void dump_window_styles( DWORD style, DWORD exstyle )
758 TRACE( "style:" );
759 if(style & WS_POPUP) TRACE(" WS_POPUP");
760 if(style & WS_CHILD) TRACE(" WS_CHILD");
761 if(style & WS_MINIMIZE) TRACE(" WS_MINIMIZE");
762 if(style & WS_VISIBLE) TRACE(" WS_VISIBLE");
763 if(style & WS_DISABLED) TRACE(" WS_DISABLED");
764 if(style & WS_CLIPSIBLINGS) TRACE(" WS_CLIPSIBLINGS");
765 if(style & WS_CLIPCHILDREN) TRACE(" WS_CLIPCHILDREN");
766 if(style & WS_MAXIMIZE) TRACE(" WS_MAXIMIZE");
767 if((style & WS_CAPTION) == WS_CAPTION) TRACE(" WS_CAPTION");
768 else
770 if(style & WS_BORDER) TRACE(" WS_BORDER");
771 if(style & WS_DLGFRAME) TRACE(" WS_DLGFRAME");
773 if(style & WS_VSCROLL) TRACE(" WS_VSCROLL");
774 if(style & WS_HSCROLL) TRACE(" WS_HSCROLL");
775 if(style & WS_SYSMENU) TRACE(" WS_SYSMENU");
776 if(style & WS_THICKFRAME) TRACE(" WS_THICKFRAME");
777 if (style & WS_CHILD)
779 if(style & WS_GROUP) TRACE(" WS_GROUP");
780 if(style & WS_TABSTOP) TRACE(" WS_TABSTOP");
782 else
784 if(style & WS_MINIMIZEBOX) TRACE(" WS_MINIMIZEBOX");
785 if(style & WS_MAXIMIZEBOX) TRACE(" WS_MAXIMIZEBOX");
788 /* FIXME: Add dumping of BS_/ES_/SBS_/LBS_/CBS_/DS_/etc. styles */
789 #define DUMPED_STYLES \
790 (WS_POPUP | \
791 WS_CHILD | \
792 WS_MINIMIZE | \
793 WS_VISIBLE | \
794 WS_DISABLED | \
795 WS_CLIPSIBLINGS | \
796 WS_CLIPCHILDREN | \
797 WS_MAXIMIZE | \
798 WS_BORDER | \
799 WS_DLGFRAME | \
800 WS_VSCROLL | \
801 WS_HSCROLL | \
802 WS_SYSMENU | \
803 WS_THICKFRAME | \
804 WS_GROUP | \
805 WS_TABSTOP | \
806 WS_MINIMIZEBOX | \
807 WS_MAXIMIZEBOX)
809 if(style & ~DUMPED_STYLES) TRACE(" %08lx", style & ~DUMPED_STYLES);
810 TRACE("\n");
811 #undef DUMPED_STYLES
813 TRACE( "exstyle:" );
814 if(exstyle & WS_EX_DLGMODALFRAME) TRACE(" WS_EX_DLGMODALFRAME");
815 if(exstyle & WS_EX_DRAGDETECT) TRACE(" WS_EX_DRAGDETECT");
816 if(exstyle & WS_EX_NOPARENTNOTIFY) TRACE(" WS_EX_NOPARENTNOTIFY");
817 if(exstyle & WS_EX_TOPMOST) TRACE(" WS_EX_TOPMOST");
818 if(exstyle & WS_EX_ACCEPTFILES) TRACE(" WS_EX_ACCEPTFILES");
819 if(exstyle & WS_EX_TRANSPARENT) TRACE(" WS_EX_TRANSPARENT");
820 if(exstyle & WS_EX_MDICHILD) TRACE(" WS_EX_MDICHILD");
821 if(exstyle & WS_EX_TOOLWINDOW) TRACE(" WS_EX_TOOLWINDOW");
822 if(exstyle & WS_EX_WINDOWEDGE) TRACE(" WS_EX_WINDOWEDGE");
823 if(exstyle & WS_EX_CLIENTEDGE) TRACE(" WS_EX_CLIENTEDGE");
824 if(exstyle & WS_EX_CONTEXTHELP) TRACE(" WS_EX_CONTEXTHELP");
825 if(exstyle & WS_EX_RIGHT) TRACE(" WS_EX_RIGHT");
826 if(exstyle & WS_EX_RTLREADING) TRACE(" WS_EX_RTLREADING");
827 if(exstyle & WS_EX_LEFTSCROLLBAR) TRACE(" WS_EX_LEFTSCROLLBAR");
828 if(exstyle & WS_EX_CONTROLPARENT) TRACE(" WS_EX_CONTROLPARENT");
829 if(exstyle & WS_EX_STATICEDGE) TRACE(" WS_EX_STATICEDGE");
830 if(exstyle & WS_EX_APPWINDOW) TRACE(" WS_EX_APPWINDOW");
831 if(exstyle & WS_EX_LAYERED) TRACE(" WS_EX_LAYERED");
833 #define DUMPED_EX_STYLES \
834 (WS_EX_DLGMODALFRAME | \
835 WS_EX_DRAGDETECT | \
836 WS_EX_NOPARENTNOTIFY | \
837 WS_EX_TOPMOST | \
838 WS_EX_ACCEPTFILES | \
839 WS_EX_TRANSPARENT | \
840 WS_EX_MDICHILD | \
841 WS_EX_TOOLWINDOW | \
842 WS_EX_WINDOWEDGE | \
843 WS_EX_CLIENTEDGE | \
844 WS_EX_CONTEXTHELP | \
845 WS_EX_RIGHT | \
846 WS_EX_RTLREADING | \
847 WS_EX_LEFTSCROLLBAR | \
848 WS_EX_CONTROLPARENT | \
849 WS_EX_STATICEDGE | \
850 WS_EX_APPWINDOW | \
851 WS_EX_LAYERED)
853 if(exstyle & ~DUMPED_EX_STYLES) TRACE(" %08lx", exstyle & ~DUMPED_EX_STYLES);
854 TRACE("\n");
855 #undef DUMPED_EX_STYLES
859 /***********************************************************************
860 * WIN_CreateWindowEx
862 * Implementation of CreateWindowEx().
864 static HWND WIN_CreateWindowEx( CREATESTRUCTA *cs, LPCWSTR className, UINT flags )
866 INT cx, cy, sw = SW_SHOW;
867 LRESULT result;
868 RECT rect;
869 WND *wndPtr;
870 HWND hwnd, parent, owner, top_child = 0;
871 BOOL unicode = (flags & WIN_ISUNICODE) != 0;
872 MDICREATESTRUCTA mdi_cs;
873 CBT_CREATEWNDA cbtc;
874 CREATESTRUCTA cbcs;
876 TRACE("%s %s ex=%08x style=%08x %d,%d %dx%d parent=%p menu=%p inst=%p params=%p\n",
877 unicode ? debugstr_w((LPCWSTR)cs->lpszName) : debugstr_a(cs->lpszName),
878 debugstr_w(className),
879 cs->dwExStyle, cs->style, cs->x, cs->y, cs->cx, cs->cy,
880 cs->hwndParent, cs->hMenu, cs->hInstance, cs->lpCreateParams );
881 if(TRACE_ON(win)) dump_window_styles( cs->style, cs->dwExStyle );
883 /* Fix the styles for MDI children */
884 if (cs->dwExStyle & WS_EX_MDICHILD)
886 UINT flags = 0;
888 wndPtr = WIN_GetPtr(cs->hwndParent);
889 if (wndPtr && wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
891 flags = wndPtr->flags;
892 WIN_ReleasePtr(wndPtr);
895 if (!(flags & WIN_ISMDICLIENT))
897 WARN("WS_EX_MDICHILD, but parent %p is not MDIClient\n", cs->hwndParent);
898 return 0;
901 /* cs->lpCreateParams of WM_[NC]CREATE is different for MDI children.
902 * MDICREATESTRUCT members have the originally passed values.
904 * Note: we rely on the fact that MDICREATESTRUCTA and MDICREATESTRUCTW
905 * have the same layout.
907 mdi_cs.szClass = cs->lpszClass;
908 mdi_cs.szTitle = cs->lpszName;
909 mdi_cs.hOwner = cs->hInstance;
910 mdi_cs.x = cs->x;
911 mdi_cs.y = cs->y;
912 mdi_cs.cx = cs->cx;
913 mdi_cs.cy = cs->cy;
914 mdi_cs.style = cs->style;
915 mdi_cs.lParam = (LPARAM)cs->lpCreateParams;
917 cs->lpCreateParams = (LPVOID)&mdi_cs;
919 if (GetWindowLongW(cs->hwndParent, GWL_STYLE) & MDIS_ALLCHILDSTYLES)
921 if (cs->style & WS_POPUP)
923 TRACE("WS_POPUP with MDIS_ALLCHILDSTYLES is not allowed\n");
924 return 0;
926 cs->style |= WS_CHILD | WS_CLIPSIBLINGS;
928 else
930 cs->style &= ~WS_POPUP;
931 cs->style |= WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION |
932 WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
935 top_child = GetWindow(cs->hwndParent, GW_CHILD);
937 if (top_child)
939 /* Restore current maximized child */
940 if((cs->style & WS_VISIBLE) && IsZoomed(top_child))
942 TRACE("Restoring current maximized child %p\n", top_child);
943 SendMessageW( top_child, WM_SETREDRAW, FALSE, 0 );
944 ShowWindow( top_child, SW_SHOWNORMAL );
945 SendMessageW( top_child, WM_SETREDRAW, TRUE, 0 );
950 /* Find the parent window */
952 parent = cs->hwndParent;
953 owner = 0;
955 if (cs->hwndParent == HWND_MESSAGE)
957 /* native ole32.OleInitialize uses HWND_MESSAGE to create the
958 * message window (style: WS_POPUP|WS_DISABLED)
960 FIXME("Parent is HWND_MESSAGE\n");
961 parent = GetDesktopWindow();
963 else if (cs->hwndParent)
965 if ((cs->style & (WS_CHILD|WS_POPUP)) != WS_CHILD)
967 parent = GetDesktopWindow();
968 owner = cs->hwndParent;
971 else
973 if ((cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
975 WARN("No parent for child window\n" );
976 SetLastError(ERROR_TLW_WITH_WSCHILD);
977 return 0; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
979 if (className != (LPCWSTR)DESKTOP_CLASS_ATOM) /* are we creating the desktop itself? */
980 parent = GetDesktopWindow();
983 WIN_FixCoordinates(cs, &sw); /* fix default coordinates */
985 if ((cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
986 ((!(cs->dwExStyle & WS_EX_STATICEDGE)) &&
987 (cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
988 cs->dwExStyle |= WS_EX_WINDOWEDGE;
989 else
990 cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
992 /* Create the window structure */
994 if (!(wndPtr = create_window_handle( parent, owner, className, cs->hInstance, unicode )))
995 return 0;
996 hwnd = wndPtr->hwndSelf;
998 /* Fill the window structure */
1000 wndPtr->tid = GetCurrentThreadId();
1001 wndPtr->hInstance = cs->hInstance;
1002 wndPtr->text = NULL;
1003 wndPtr->dwStyle = cs->style & ~WS_VISIBLE;
1004 wndPtr->dwExStyle = cs->dwExStyle;
1005 wndPtr->wIDmenu = 0;
1006 wndPtr->helpContext = 0;
1007 wndPtr->pVScroll = NULL;
1008 wndPtr->pHScroll = NULL;
1009 wndPtr->userdata = 0;
1010 wndPtr->hIcon = 0;
1011 wndPtr->hIconSmall = 0;
1012 wndPtr->hSysMenu = 0;
1013 wndPtr->flags |= (flags & WIN_ISWIN32);
1015 if (wndPtr->dwStyle & WS_SYSMENU) SetSystemMenu( hwnd, 0 );
1018 * Correct the window styles.
1020 * It affects only the style loaded into the WIN structure.
1023 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1025 wndPtr->dwStyle |= WS_CLIPSIBLINGS;
1026 if (!(wndPtr->dwStyle & WS_POPUP))
1027 wndPtr->dwStyle |= WS_CAPTION;
1031 * WS_EX_WINDOWEDGE appears to be enforced based on the other styles, so
1032 * why does the user get to set it?
1035 if ((wndPtr->dwExStyle & WS_EX_DLGMODALFRAME) ||
1036 (wndPtr->dwStyle & (WS_DLGFRAME | WS_THICKFRAME)))
1037 wndPtr->dwExStyle |= WS_EX_WINDOWEDGE;
1038 else
1039 wndPtr->dwExStyle &= ~WS_EX_WINDOWEDGE;
1041 if (!(wndPtr->dwStyle & (WS_CHILD | WS_POPUP)))
1042 wndPtr->flags |= WIN_NEED_SIZE;
1044 SERVER_START_REQ( set_window_info )
1046 req->handle = hwnd;
1047 req->flags = SET_WIN_STYLE | SET_WIN_EXSTYLE | SET_WIN_INSTANCE | SET_WIN_UNICODE;
1048 req->style = wndPtr->dwStyle;
1049 req->ex_style = wndPtr->dwExStyle;
1050 req->instance = (void *)wndPtr->hInstance;
1051 req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
1052 req->extra_offset = -1;
1053 wine_server_call( req );
1055 SERVER_END_REQ;
1057 /* Set the window menu */
1059 if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1061 if (cs->hMenu)
1063 if (!MENU_SetMenu(hwnd, cs->hMenu))
1065 WIN_ReleasePtr( wndPtr );
1066 free_window_handle( hwnd );
1067 return 0;
1070 else
1072 LPCSTR menuName = (LPCSTR)GetClassLongPtrA( hwnd, GCLP_MENUNAME );
1073 if (menuName)
1075 if (!cs->hInstance || HIWORD(cs->hInstance))
1076 cs->hMenu = LoadMenuA(cs->hInstance,menuName);
1077 else
1078 cs->hMenu = HMENU_32(LoadMenu16(HINSTANCE_16(cs->hInstance),menuName));
1080 if (cs->hMenu) MENU_SetMenu( hwnd, cs->hMenu );
1084 else SetWindowLongPtrW( hwnd, GWLP_ID, (ULONG_PTR)cs->hMenu );
1086 /* call the WH_CBT hook */
1088 /* the window style passed to the hook must be the real window style,
1089 * rather than just the window style that the caller to CreateWindowEx
1090 * passed in, so we have to copy the original CREATESTRUCT and get the
1091 * the real style. */
1092 cbcs = *cs;
1093 cbcs.style = wndPtr->dwStyle;
1094 cbtc.lpcs = &cbcs;
1095 cbtc.hwndInsertAfter = HWND_TOP;
1096 WIN_ReleasePtr( wndPtr );
1097 if (HOOK_CallHooks( WH_CBT, HCBT_CREATEWND, (WPARAM)hwnd, (LPARAM)&cbtc, unicode )) goto failed;
1099 /* send the WM_GETMINMAXINFO message and fix the size if needed */
1101 cx = cs->cx;
1102 cy = cs->cy;
1103 if ((cs->style & WS_THICKFRAME) || !(cs->style & (WS_POPUP | WS_CHILD)))
1105 POINT maxSize, maxPos, minTrack, maxTrack;
1106 WINPOS_GetMinMaxInfo( hwnd, &maxSize, &maxPos, &minTrack, &maxTrack);
1107 if (maxTrack.x < cx) cx = maxTrack.x;
1108 if (maxTrack.y < cy) cy = maxTrack.y;
1111 if (cx < 0) cx = 0;
1112 if (cy < 0) cy = 0;
1113 SetRect( &rect, cs->x, cs->y, cs->x + cx, cs->y + cy );
1114 if (!set_window_pos( hwnd, 0, SWP_NOZORDER | SWP_NOACTIVATE, &rect, &rect, NULL )) goto failed;
1116 /* send WM_NCCREATE */
1118 TRACE( "hwnd %p cs %d,%d %dx%d\n", hwnd, cs->x, cs->y, cx, cy );
1119 if (unicode)
1120 result = SendMessageW( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1121 else
1122 result = SendMessageA( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1123 if (!result)
1125 WARN( "%p: aborted by WM_NCCREATE\n", hwnd );
1126 goto failed;
1129 /* send WM_NCCALCSIZE */
1131 if ((wndPtr = WIN_GetPtr(hwnd)))
1133 /* yes, even if the CBT hook was called with HWND_TOP */
1134 HWND insert_after = (wndPtr->dwStyle & WS_CHILD) ? HWND_BOTTOM : HWND_TOP;
1135 RECT window_rect = wndPtr->rectWindow;
1136 RECT client_rect = window_rect;
1137 WIN_ReleasePtr( wndPtr );
1138 SendMessageW( hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&client_rect );
1139 set_window_pos( hwnd, insert_after, SWP_NOACTIVATE, &window_rect, &client_rect, NULL );
1141 else return 0;
1143 /* send WM_CREATE */
1145 if (unicode)
1146 result = SendMessageW( hwnd, WM_CREATE, 0, (LPARAM)cs );
1147 else
1148 result = SendMessageA( hwnd, WM_CREATE, 0, (LPARAM)cs );
1149 if (result == -1) goto failed;
1151 NotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_WINDOW, 0);
1153 /* send the size messages */
1155 if (!(wndPtr = WIN_GetPtr(hwnd))) return 0;
1156 if (!(wndPtr->flags & WIN_NEED_SIZE))
1158 rect = wndPtr->rectClient;
1159 WIN_ReleasePtr( wndPtr );
1160 SendMessageW( hwnd, WM_SIZE, SIZE_RESTORED,
1161 MAKELONG(rect.right-rect.left, rect.bottom-rect.top));
1162 SendMessageW( hwnd, WM_MOVE, 0, MAKELONG( rect.left, rect.top ) );
1164 else WIN_ReleasePtr( wndPtr );
1166 /* call the driver */
1168 if (!USER_Driver->pCreateWindow( hwnd )) goto failed;
1170 /* Notify the parent window only */
1172 send_parent_notify( hwnd, WM_CREATE );
1173 if (!IsWindow( hwnd )) return 0;
1175 if (cs->style & WS_VISIBLE)
1177 if (cs->style & WS_MAXIMIZE)
1178 sw = SW_SHOW;
1179 else if (cs->style & WS_MINIMIZE)
1180 sw = SW_SHOWMINIMIZED;
1182 ShowWindow( hwnd, sw );
1183 if (cs->dwExStyle & WS_EX_MDICHILD)
1185 SendMessageW(cs->hwndParent, WM_MDIREFRESHMENU, 0, 0);
1186 /* ShowWindow won't activate child windows */
1187 SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE );
1191 /* Call WH_SHELL hook */
1193 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1194 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0, TRUE );
1196 TRACE("created window %p\n", hwnd);
1197 return hwnd;
1199 failed:
1200 WIN_DestroyWindow( hwnd );
1201 return 0;
1205 /***********************************************************************
1206 * CreateWindow (USER.41)
1208 HWND16 WINAPI CreateWindow16( LPCSTR className, LPCSTR windowName,
1209 DWORD style, INT16 x, INT16 y, INT16 width,
1210 INT16 height, HWND16 parent, HMENU16 menu,
1211 HINSTANCE16 instance, LPVOID data )
1213 return CreateWindowEx16( 0, className, windowName, style,
1214 x, y, width, height, parent, menu, instance, data );
1218 /***********************************************************************
1219 * CreateWindowEx (USER.452)
1221 HWND16 WINAPI CreateWindowEx16( DWORD exStyle, LPCSTR className,
1222 LPCSTR windowName, DWORD style, INT16 x,
1223 INT16 y, INT16 width, INT16 height,
1224 HWND16 parent, HMENU16 menu,
1225 HINSTANCE16 instance, LPVOID data )
1227 CREATESTRUCTA cs;
1228 char buffer[256];
1230 /* Fix the coordinates */
1232 cs.x = (x == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)x;
1233 cs.y = (y == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)y;
1234 cs.cx = (width == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)width;
1235 cs.cy = (height == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)height;
1237 /* Create the window */
1239 cs.lpCreateParams = data;
1240 cs.hInstance = HINSTANCE_32(instance);
1241 cs.hMenu = HMENU_32(menu);
1242 cs.hwndParent = WIN_Handle32( parent );
1243 cs.style = style;
1244 cs.lpszName = windowName;
1245 cs.lpszClass = className;
1246 cs.dwExStyle = exStyle;
1248 if (!IS_INTRESOURCE(className))
1250 WCHAR bufferW[256];
1252 if (!MultiByteToWideChar( CP_ACP, 0, className, -1, bufferW, sizeof(bufferW)/sizeof(WCHAR) ))
1253 return 0;
1254 return HWND_16( WIN_CreateWindowEx( &cs, bufferW, 0 ));
1256 else
1258 if (!GlobalGetAtomNameA( LOWORD(className), buffer, sizeof(buffer) ))
1260 ERR( "bad atom %x\n", LOWORD(className));
1261 return 0;
1263 cs.lpszClass = buffer;
1264 return HWND_16( WIN_CreateWindowEx( &cs, (LPCWSTR)className, 0 ));
1269 /***********************************************************************
1270 * CreateWindowExA (USER32.@)
1272 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1273 LPCSTR windowName, DWORD style, INT x,
1274 INT y, INT width, INT height,
1275 HWND parent, HMENU menu,
1276 HINSTANCE instance, LPVOID data )
1278 CREATESTRUCTA cs;
1280 cs.lpCreateParams = data;
1281 cs.hInstance = instance;
1282 cs.hMenu = menu;
1283 cs.hwndParent = parent;
1284 cs.x = x;
1285 cs.y = y;
1286 cs.cx = width;
1287 cs.cy = height;
1288 cs.style = style;
1289 cs.lpszName = windowName;
1290 cs.lpszClass = className;
1291 cs.dwExStyle = exStyle;
1293 if (!IS_INTRESOURCE(className))
1295 WCHAR bufferW[256];
1296 if (!MultiByteToWideChar( CP_ACP, 0, className, -1, bufferW, sizeof(bufferW)/sizeof(WCHAR) ))
1297 return 0;
1298 return WIN_CreateWindowEx( &cs, bufferW, WIN_ISWIN32 );
1300 return WIN_CreateWindowEx( &cs, (LPCWSTR)className, WIN_ISWIN32 );
1304 /***********************************************************************
1305 * CreateWindowExW (USER32.@)
1307 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1308 LPCWSTR windowName, DWORD style, INT x,
1309 INT y, INT width, INT height,
1310 HWND parent, HMENU menu,
1311 HINSTANCE instance, LPVOID data )
1313 CREATESTRUCTW cs;
1315 cs.lpCreateParams = data;
1316 cs.hInstance = instance;
1317 cs.hMenu = menu;
1318 cs.hwndParent = parent;
1319 cs.x = x;
1320 cs.y = y;
1321 cs.cx = width;
1322 cs.cy = height;
1323 cs.style = style;
1324 cs.lpszName = windowName;
1325 cs.lpszClass = className;
1326 cs.dwExStyle = exStyle;
1328 /* Note: we rely on the fact that CREATESTRUCTA and */
1329 /* CREATESTRUCTW have the same layout. */
1330 return WIN_CreateWindowEx( (CREATESTRUCTA *)&cs, className, WIN_ISWIN32 | WIN_ISUNICODE );
1334 /***********************************************************************
1335 * WIN_SendDestroyMsg
1337 static void WIN_SendDestroyMsg( HWND hwnd )
1339 GUITHREADINFO info;
1341 if (GetGUIThreadInfo( GetCurrentThreadId(), &info ))
1343 if (hwnd == info.hwndCaret) DestroyCaret();
1344 if (hwnd == info.hwndActive) WINPOS_ActivateOtherWindow( hwnd );
1348 * Send the WM_DESTROY to the window.
1350 SendMessageW( hwnd, WM_DESTROY, 0, 0);
1353 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1354 * make sure that the window still exists when we come back.
1356 if (IsWindow(hwnd))
1358 HWND* pWndArray;
1359 int i;
1361 if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1363 for (i = 0; pWndArray[i]; i++)
1365 if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1367 HeapFree( GetProcessHeap(), 0, pWndArray );
1369 else
1370 WARN("\tdestroyed itself while in WM_DESTROY!\n");
1374 /***********************************************************************
1375 * DestroyWindow (USER32.@)
1377 BOOL WINAPI DestroyWindow( HWND hwnd )
1379 BOOL is_child;
1381 if (!(hwnd = WIN_IsCurrentThread( hwnd )) || (hwnd == GetDesktopWindow()))
1383 SetLastError( ERROR_ACCESS_DENIED );
1384 return FALSE;
1387 TRACE("(%p)\n", hwnd);
1389 /* Call hooks */
1391 if (HOOK_CallHooks( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0, TRUE )) return FALSE;
1393 if (MENU_IsMenuActive() == hwnd)
1394 EndMenu();
1396 is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;
1398 if (is_child)
1400 if (!USER_IsExitingThread( GetCurrentThreadId() ))
1401 send_parent_notify( hwnd, WM_DESTROY );
1403 else if (!GetWindow( hwnd, GW_OWNER ))
1405 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
1406 /* FIXME: clean up palette - see "Internals" p.352 */
1409 if (!IsWindow(hwnd)) return TRUE;
1411 /* Hide the window */
1412 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)
1414 /* Only child windows receive WM_SHOWWINDOW in DestroyWindow() */
1415 if (is_child)
1416 ShowWindow( hwnd, SW_HIDE );
1417 else
1418 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE |
1419 SWP_NOZORDER | SWP_NOACTIVATE | SWP_HIDEWINDOW );
1422 if (!IsWindow(hwnd)) return TRUE;
1424 /* Recursively destroy owned windows */
1426 if (!is_child)
1428 for (;;)
1430 int i, got_one = 0;
1431 HWND *list = WIN_ListChildren( GetDesktopWindow() );
1432 if (list)
1434 for (i = 0; list[i]; i++)
1436 if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1437 if (WIN_IsCurrentThread( list[i] ))
1439 DestroyWindow( list[i] );
1440 got_one = 1;
1441 continue;
1443 WIN_SetOwner( list[i], 0 );
1445 HeapFree( GetProcessHeap(), 0, list );
1447 if (!got_one) break;
1451 /* Send destroy messages */
1453 WIN_SendDestroyMsg( hwnd );
1454 if (!IsWindow( hwnd )) return TRUE;
1456 if (GetClipboardOwner() == hwnd)
1457 CLIPBOARD_ReleaseOwner();
1459 /* Destroy the window storage */
1461 WIN_DestroyWindow( hwnd );
1462 return TRUE;
1466 /***********************************************************************
1467 * CloseWindow (USER32.@)
1469 BOOL WINAPI CloseWindow( HWND hwnd )
1471 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1472 ShowWindow( hwnd, SW_MINIMIZE );
1473 return TRUE;
1477 /***********************************************************************
1478 * OpenIcon (USER32.@)
1480 BOOL WINAPI OpenIcon( HWND hwnd )
1482 if (!IsIconic( hwnd )) return FALSE;
1483 ShowWindow( hwnd, SW_SHOWNORMAL );
1484 return TRUE;
1488 /***********************************************************************
1489 * FindWindowExW (USER32.@)
1491 HWND WINAPI FindWindowExW( HWND parent, HWND child, LPCWSTR className, LPCWSTR title )
1493 HWND *list = NULL;
1494 HWND retvalue = 0;
1495 int i = 0, len = 0;
1496 WCHAR *buffer = NULL;
1498 if (!parent) parent = GetDesktopWindow();
1499 if (title)
1501 len = strlenW(title) + 1; /* one extra char to check for chars beyond the end */
1502 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1505 if (!(list = list_window_children( parent, className, 0 ))) goto done;
1507 if (child)
1509 child = WIN_GetFullHandle( child );
1510 while (list[i] && list[i] != child) i++;
1511 if (!list[i]) goto done;
1512 i++; /* start from next window */
1515 if (title)
1517 while (list[i])
1519 if (GetWindowTextW( list[i], buffer, len + 1 ) && !strcmpiW( buffer, title )) break;
1520 i++;
1523 retvalue = list[i];
1525 done:
1526 HeapFree( GetProcessHeap(), 0, list );
1527 HeapFree( GetProcessHeap(), 0, buffer );
1528 return retvalue;
1533 /***********************************************************************
1534 * FindWindowA (USER32.@)
1536 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1538 HWND ret = FindWindowExA( 0, 0, className, title );
1539 if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1540 return ret;
1544 /***********************************************************************
1545 * FindWindowExA (USER32.@)
1547 HWND WINAPI FindWindowExA( HWND parent, HWND child, LPCSTR className, LPCSTR title )
1549 LPWSTR titleW = NULL;
1550 HWND hwnd = 0;
1552 if (title)
1554 DWORD len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
1555 if (!(titleW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
1556 MultiByteToWideChar( CP_ACP, 0, title, -1, titleW, len );
1559 if (!IS_INTRESOURCE(className))
1561 WCHAR classW[256];
1562 if (MultiByteToWideChar( CP_ACP, 0, className, -1, classW, sizeof(classW)/sizeof(WCHAR) ))
1563 hwnd = FindWindowExW( parent, child, classW, titleW );
1565 else
1567 hwnd = FindWindowExW( parent, child, (LPCWSTR)className, titleW );
1570 HeapFree( GetProcessHeap(), 0, titleW );
1571 return hwnd;
1575 /***********************************************************************
1576 * FindWindowW (USER32.@)
1578 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
1580 return FindWindowExW( 0, 0, className, title );
1584 /**********************************************************************
1585 * GetDesktopWindow (USER32.@)
1587 HWND WINAPI GetDesktopWindow(void)
1589 struct user_thread_info *thread_info = get_user_thread_info();
1591 if (thread_info->desktop) return thread_info->desktop;
1593 SERVER_START_REQ( get_desktop_window )
1595 req->force = 0;
1596 if (!wine_server_call( req )) thread_info->desktop = reply->handle;
1598 SERVER_END_REQ;
1600 if (!thread_info->desktop)
1602 static const WCHAR command_line[] = {'\\','e','x','p','l','o','r','e','r','.','e','x','e',' ','/','d','e','s','k','t','o','p',0};
1603 STARTUPINFOW si;
1604 PROCESS_INFORMATION pi;
1605 WCHAR cmdline[MAX_PATH + sizeof(command_line)/sizeof(WCHAR)];
1607 memset( &si, 0, sizeof(si) );
1608 si.cb = sizeof(si);
1609 si.dwFlags = STARTF_USESTDHANDLES;
1610 si.hStdInput = 0;
1611 si.hStdOutput = 0;
1612 si.hStdError = GetStdHandle( STD_ERROR_HANDLE );
1614 GetSystemDirectoryW( cmdline, MAX_PATH );
1615 lstrcatW( cmdline, command_line );
1616 if (CreateProcessW( NULL, cmdline, NULL, NULL, FALSE, DETACHED_PROCESS,
1617 NULL, NULL, &si, &pi ))
1619 TRACE( "started explorer pid %04x tid %04x\n", pi.dwProcessId, pi.dwThreadId );
1620 WaitForInputIdle( pi.hProcess, 10000 );
1621 CloseHandle( pi.hThread );
1622 CloseHandle( pi.hProcess );
1625 else WARN( "failed to start explorer, err %d\n", GetLastError() );
1627 SERVER_START_REQ( get_desktop_window )
1629 req->force = 1;
1630 if (!wine_server_call( req )) thread_info->desktop = reply->handle;
1632 SERVER_END_REQ;
1635 if (!thread_info->desktop || !USER_Driver->pCreateDesktopWindow( thread_info->desktop ))
1636 ERR( "failed to create desktop window\n" );
1638 return thread_info->desktop;
1642 /*******************************************************************
1643 * EnableWindow (USER32.@)
1645 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
1647 BOOL retvalue;
1648 HWND full_handle;
1650 if (is_broadcast(hwnd))
1652 SetLastError( ERROR_INVALID_PARAMETER );
1653 return FALSE;
1656 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
1657 return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
1659 hwnd = full_handle;
1661 TRACE("( %p, %d )\n", hwnd, enable);
1663 retvalue = !IsWindowEnabled( hwnd );
1665 if (enable && retvalue)
1667 WIN_SetStyle( hwnd, 0, WS_DISABLED );
1668 SendMessageW( hwnd, WM_ENABLE, TRUE, 0 );
1670 else if (!enable && !retvalue)
1672 HWND capture_wnd;
1674 SendMessageW( hwnd, WM_CANCELMODE, 0, 0);
1676 WIN_SetStyle( hwnd, WS_DISABLED, 0 );
1678 if (hwnd == GetFocus())
1679 SetFocus( 0 ); /* A disabled window can't have the focus */
1681 capture_wnd = GetCapture();
1682 if (hwnd == capture_wnd || IsChild(hwnd, capture_wnd))
1683 ReleaseCapture(); /* A disabled window can't capture the mouse */
1685 SendMessageW( hwnd, WM_ENABLE, FALSE, 0 );
1687 return retvalue;
1691 /***********************************************************************
1692 * IsWindowEnabled (USER32.@)
1694 BOOL WINAPI IsWindowEnabled(HWND hWnd)
1696 return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
1700 /***********************************************************************
1701 * IsWindowUnicode (USER32.@)
1703 BOOL WINAPI IsWindowUnicode( HWND hwnd )
1705 WND * wndPtr;
1706 BOOL retvalue = FALSE;
1708 if (!(wndPtr = WIN_GetPtr(hwnd))) return FALSE;
1710 if (wndPtr == WND_DESKTOP) return TRUE;
1712 if (wndPtr != WND_OTHER_PROCESS)
1714 retvalue = (wndPtr->flags & WIN_ISUNICODE) != 0;
1715 WIN_ReleasePtr( wndPtr );
1717 else
1719 SERVER_START_REQ( get_window_info )
1721 req->handle = hwnd;
1722 if (!wine_server_call_err( req )) retvalue = reply->is_unicode;
1724 SERVER_END_REQ;
1726 return retvalue;
1730 /**********************************************************************
1731 * WIN_GetWindowLong
1733 * Helper function for GetWindowLong().
1735 static LONG_PTR WIN_GetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicode )
1737 LONG_PTR retvalue = 0;
1738 WND *wndPtr;
1740 if (offset == GWLP_HWNDPARENT)
1742 HWND parent = GetAncestor( hwnd, GA_PARENT );
1743 if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
1744 return (ULONG_PTR)parent;
1747 if (!(wndPtr = WIN_GetPtr( hwnd )))
1749 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1750 return 0;
1753 if (wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP)
1755 if (offset == GWLP_WNDPROC)
1757 SetLastError( ERROR_ACCESS_DENIED );
1758 return 0;
1760 SERVER_START_REQ( set_window_info )
1762 req->handle = hwnd;
1763 req->flags = 0; /* don't set anything, just retrieve */
1764 req->extra_offset = (offset >= 0) ? offset : -1;
1765 req->extra_size = (offset >= 0) ? size : 0;
1766 if (!wine_server_call_err( req ))
1768 switch(offset)
1770 case GWL_STYLE: retvalue = reply->old_style; break;
1771 case GWL_EXSTYLE: retvalue = reply->old_ex_style; break;
1772 case GWLP_ID: retvalue = reply->old_id; break;
1773 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)reply->old_instance; break;
1774 case GWLP_USERDATA: retvalue = reply->old_user_data; break;
1775 default:
1776 if (offset >= 0) retvalue = get_win_data( &reply->old_extra_value, size );
1777 else SetLastError( ERROR_INVALID_INDEX );
1778 break;
1782 SERVER_END_REQ;
1783 return retvalue;
1786 /* now we have a valid wndPtr */
1788 if (offset >= 0)
1790 if (offset > (int)(wndPtr->cbWndExtra - size))
1792 WARN("Invalid offset %d\n", offset );
1793 WIN_ReleasePtr( wndPtr );
1794 SetLastError( ERROR_INVALID_INDEX );
1795 return 0;
1797 retvalue = get_win_data( (char *)wndPtr->wExtra + offset, size );
1799 /* Special case for dialog window procedure */
1800 if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && (wndPtr->flags & WIN_ISDIALOG))
1801 retvalue = (LONG_PTR)WINPROC_GetProc( (WNDPROC)retvalue, unicode );
1802 WIN_ReleasePtr( wndPtr );
1803 return retvalue;
1806 switch(offset)
1808 case GWLP_USERDATA: retvalue = wndPtr->userdata; break;
1809 case GWL_STYLE: retvalue = wndPtr->dwStyle; break;
1810 case GWL_EXSTYLE: retvalue = wndPtr->dwExStyle; break;
1811 case GWLP_ID: retvalue = wndPtr->wIDmenu; break;
1812 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hInstance; break;
1813 case GWLP_WNDPROC:
1814 /* This looks like a hack only for the edit control (see tests). This makes these controls
1815 * more tolerant to A/W mismatches. The lack of W->A->W conversion for such a mismatch suggests
1816 * that the hack is in GetWindowLongPtr[AW], not in winprocs.
1818 if (wndPtr->winproc == EDIT_winproc_handle && (!unicode != !(wndPtr->flags & WIN_ISUNICODE)))
1819 retvalue = (ULONG_PTR)wndPtr->winproc;
1820 else
1821 retvalue = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, unicode );
1822 break;
1823 default:
1824 WARN("Unknown offset %d\n", offset );
1825 SetLastError( ERROR_INVALID_INDEX );
1826 break;
1828 WIN_ReleasePtr(wndPtr);
1829 return retvalue;
1833 /**********************************************************************
1834 * WIN_SetWindowLong
1836 * Helper function for SetWindowLong().
1838 * 0 is the failure code. However, in the case of failure SetLastError
1839 * must be set to distinguish between a 0 return value and a failure.
1841 LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, UINT size, LONG_PTR newval, BOOL unicode )
1843 STYLESTRUCT style;
1844 BOOL ok;
1845 LONG_PTR retval = 0;
1846 WND *wndPtr;
1848 TRACE( "%p %d %lx %c\n", hwnd, offset, newval, unicode ? 'W' : 'A' );
1850 if (is_broadcast(hwnd))
1852 SetLastError( ERROR_INVALID_PARAMETER );
1853 return FALSE;
1856 if (!(wndPtr = WIN_GetPtr( hwnd )))
1858 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1859 return 0;
1861 if (wndPtr == WND_DESKTOP)
1863 /* can't change anything on the desktop window */
1864 SetLastError( ERROR_ACCESS_DENIED );
1865 return 0;
1867 if (wndPtr == WND_OTHER_PROCESS)
1869 if (offset == GWLP_WNDPROC)
1871 SetLastError( ERROR_ACCESS_DENIED );
1872 return 0;
1874 if (offset > 32767 || offset < -32767)
1876 SetLastError( ERROR_INVALID_INDEX );
1877 return 0;
1879 return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, MAKEWPARAM( offset, size ), newval );
1882 /* first some special cases */
1883 switch( offset )
1885 case GWL_STYLE:
1886 case GWL_EXSTYLE:
1887 style.styleOld =
1888 offset == GWL_STYLE ? wndPtr->dwStyle : wndPtr->dwExStyle;
1889 style.styleNew = newval;
1890 WIN_ReleasePtr( wndPtr );
1891 SendMessageW( hwnd, WM_STYLECHANGING, offset, (LPARAM)&style );
1892 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
1893 newval = style.styleNew;
1894 break;
1895 case GWLP_HWNDPARENT:
1896 if (wndPtr->parent == GetDesktopWindow())
1898 WIN_ReleasePtr( wndPtr );
1899 return (ULONG_PTR)WIN_SetOwner( hwnd, (HWND)newval );
1901 else
1903 WIN_ReleasePtr( wndPtr );
1904 return (ULONG_PTR)SetParent( hwnd, (HWND)newval );
1906 case GWLP_WNDPROC:
1908 WNDPROC proc;
1909 UINT old_flags = wndPtr->flags;
1910 retval = WIN_GetWindowLong( hwnd, offset, size, unicode );
1911 if (unicode) proc = WINPROC_AllocProc( NULL, (WNDPROC)newval );
1912 else proc = WINPROC_AllocProc( (WNDPROC)newval, NULL );
1913 if (proc) wndPtr->winproc = proc;
1914 if (WINPROC_IsUnicode( proc, unicode )) wndPtr->flags |= WIN_ISUNICODE;
1915 else wndPtr->flags &= ~WIN_ISUNICODE;
1916 if (!((old_flags ^ wndPtr->flags) & WIN_ISUNICODE))
1918 WIN_ReleasePtr( wndPtr );
1919 return retval;
1921 /* update is_unicode flag on the server side */
1922 break;
1924 case GWLP_ID:
1925 case GWLP_HINSTANCE:
1926 case GWLP_USERDATA:
1927 break;
1928 case DWLP_DLGPROC:
1929 if ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
1930 (size == sizeof(LONG_PTR)) && (wndPtr->flags & WIN_ISDIALOG))
1932 WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWLP_DLGPROC);
1933 retval = (ULONG_PTR)WINPROC_GetProc( *ptr, unicode );
1934 if (unicode) *ptr = WINPROC_AllocProc( NULL, (WNDPROC)newval );
1935 else *ptr = WINPROC_AllocProc( (WNDPROC)newval, NULL );
1936 WIN_ReleasePtr( wndPtr );
1937 return retval;
1939 /* fall through */
1940 default:
1941 if (offset < 0 || offset > (int)(wndPtr->cbWndExtra - size))
1943 WARN("Invalid offset %d\n", offset );
1944 WIN_ReleasePtr( wndPtr );
1945 SetLastError( ERROR_INVALID_INDEX );
1946 return 0;
1948 else if (get_win_data( (char *)wndPtr->wExtra + offset, size ) == newval)
1950 /* already set to the same value */
1951 WIN_ReleasePtr( wndPtr );
1952 return newval;
1954 break;
1957 SERVER_START_REQ( set_window_info )
1959 req->handle = hwnd;
1960 req->extra_offset = -1;
1961 switch(offset)
1963 case GWL_STYLE:
1964 req->flags = SET_WIN_STYLE;
1965 req->style = newval;
1966 break;
1967 case GWL_EXSTYLE:
1968 req->flags = SET_WIN_EXSTYLE;
1969 /* WS_EX_TOPMOST can only be changed through SetWindowPos */
1970 newval = (newval & ~WS_EX_TOPMOST) | (wndPtr->dwExStyle & WS_EX_TOPMOST);
1971 req->ex_style = newval;
1972 break;
1973 case GWLP_ID:
1974 req->flags = SET_WIN_ID;
1975 req->id = newval;
1976 break;
1977 case GWLP_HINSTANCE:
1978 req->flags = SET_WIN_INSTANCE;
1979 req->instance = (void *)newval;
1980 break;
1981 case GWLP_WNDPROC:
1982 req->flags = SET_WIN_UNICODE;
1983 req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
1984 break;
1985 case GWLP_USERDATA:
1986 req->flags = SET_WIN_USERDATA;
1987 req->user_data = newval;
1988 break;
1989 default:
1990 req->flags = SET_WIN_EXTRA;
1991 req->extra_offset = offset;
1992 req->extra_size = size;
1993 set_win_data( &req->extra_value, newval, size );
1995 if ((ok = !wine_server_call_err( req )))
1997 switch(offset)
1999 case GWL_STYLE:
2000 wndPtr->dwStyle = newval;
2001 retval = reply->old_style;
2002 break;
2003 case GWL_EXSTYLE:
2004 wndPtr->dwExStyle = newval;
2005 retval = reply->old_ex_style;
2006 break;
2007 case GWLP_ID:
2008 wndPtr->wIDmenu = newval;
2009 retval = reply->old_id;
2010 break;
2011 case GWLP_HINSTANCE:
2012 wndPtr->hInstance = (HINSTANCE)newval;
2013 retval = (ULONG_PTR)reply->old_instance;
2014 break;
2015 case GWLP_WNDPROC:
2016 break;
2017 case GWLP_USERDATA:
2018 wndPtr->userdata = newval;
2019 retval = reply->old_user_data;
2020 break;
2021 default:
2022 retval = get_win_data( (char *)wndPtr->wExtra + offset, size );
2023 set_win_data( (char *)wndPtr->wExtra + offset, newval, size );
2024 break;
2028 SERVER_END_REQ;
2029 WIN_ReleasePtr( wndPtr );
2031 if (!ok) return 0;
2033 if (offset == GWL_STYLE) USER_Driver->pSetWindowStyle( hwnd, retval );
2035 if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2036 SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2038 return retval;
2042 /**********************************************************************
2043 * GetWindowLong (USER.135)
2045 LONG WINAPI GetWindowLong16( HWND16 hwnd, INT16 offset )
2047 WND *wndPtr;
2048 LONG_PTR retvalue;
2049 BOOL is_winproc = (offset == GWLP_WNDPROC);
2051 if (offset >= 0)
2053 if (!(wndPtr = WIN_GetPtr( WIN_Handle32(hwnd) )))
2055 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2056 return 0;
2058 if (wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
2060 if (offset > (int)(wndPtr->cbWndExtra - sizeof(LONG)))
2063 * Some programs try to access last element from 16 bit
2064 * code using illegal offset value. Hopefully this is
2065 * what those programs really expect.
2067 if (wndPtr->cbWndExtra >= 4 && offset == wndPtr->cbWndExtra - sizeof(WORD))
2069 INT offset2 = wndPtr->cbWndExtra - sizeof(LONG);
2070 ERR( "- replaced invalid offset %d with %d\n", offset, offset2 );
2071 offset = offset2;
2073 else
2075 WARN("Invalid offset %d\n", offset );
2076 WIN_ReleasePtr( wndPtr );
2077 SetLastError( ERROR_INVALID_INDEX );
2078 return 0;
2081 is_winproc = ((offset == DWLP_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG));
2082 WIN_ReleasePtr( wndPtr );
2085 retvalue = GetWindowLongA( WIN_Handle32(hwnd), offset );
2086 if (is_winproc) retvalue = (LONG_PTR)WINPROC_GetProc16( (WNDPROC)retvalue, FALSE );
2087 return retvalue;
2091 /**********************************************************************
2092 * GetWindowWord (USER32.@)
2094 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
2096 switch(offset)
2098 case GWLP_ID:
2099 case GWLP_HINSTANCE:
2100 case GWLP_HWNDPARENT:
2101 break;
2102 default:
2103 if (offset < 0)
2105 WARN("Invalid offset %d\n", offset );
2106 SetLastError( ERROR_INVALID_INDEX );
2107 return 0;
2109 break;
2111 return WIN_GetWindowLong( hwnd, offset, sizeof(WORD), FALSE );
2115 /**********************************************************************
2116 * GetWindowLongA (USER32.@)
2118 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2120 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), FALSE );
2124 /**********************************************************************
2125 * GetWindowLongW (USER32.@)
2127 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2129 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), TRUE );
2133 /**********************************************************************
2134 * SetWindowLong (USER.136)
2136 LONG WINAPI SetWindowLong16( HWND16 hwnd, INT16 offset, LONG newval )
2138 WND *wndPtr;
2139 BOOL is_winproc = (offset == GWLP_WNDPROC);
2141 if (offset == DWLP_DLGPROC)
2143 if (!(wndPtr = WIN_GetPtr( WIN_Handle32(hwnd) )))
2145 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2146 return 0;
2148 if (wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
2150 is_winproc = ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
2151 (wndPtr->flags & WIN_ISDIALOG));
2152 WIN_ReleasePtr( wndPtr );
2156 if (is_winproc)
2158 WNDPROC new_proc = WINPROC_AllocProc16( (WNDPROC16)newval );
2159 WNDPROC old_proc = (WNDPROC)SetWindowLongPtrA( WIN_Handle32(hwnd), offset, (LONG_PTR)new_proc );
2160 return (LONG)WINPROC_GetProc16( old_proc, FALSE );
2162 else return SetWindowLongA( WIN_Handle32(hwnd), offset, newval );
2166 /**********************************************************************
2167 * SetWindowWord (USER32.@)
2169 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
2171 switch(offset)
2173 case GWLP_ID:
2174 case GWLP_HINSTANCE:
2175 case GWLP_HWNDPARENT:
2176 break;
2177 default:
2178 if (offset < 0)
2180 WARN("Invalid offset %d\n", offset );
2181 SetLastError( ERROR_INVALID_INDEX );
2182 return 0;
2184 break;
2186 return WIN_SetWindowLong( hwnd, offset, sizeof(WORD), newval, FALSE );
2190 /**********************************************************************
2191 * SetWindowLongA (USER32.@)
2193 * See SetWindowLongW.
2195 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2197 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, FALSE );
2201 /**********************************************************************
2202 * SetWindowLongW (USER32.@) Set window attribute
2204 * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2205 * value in a window's extra memory.
2207 * The _hwnd_ parameter specifies the window. is the handle to a
2208 * window that has extra memory. The _newval_ parameter contains the
2209 * new attribute or extra memory value. If positive, the _offset_
2210 * parameter is the byte-addressed location in the window's extra
2211 * memory to set. If negative, _offset_ specifies the window
2212 * attribute to set, and should be one of the following values:
2214 * GWL_EXSTYLE The window's extended window style
2216 * GWL_STYLE The window's window style.
2218 * GWLP_WNDPROC Pointer to the window's window procedure.
2220 * GWLP_HINSTANCE The window's pplication instance handle.
2222 * GWLP_ID The window's identifier.
2224 * GWLP_USERDATA The window's user-specified data.
2226 * If the window is a dialog box, the _offset_ parameter can be one of
2227 * the following values:
2229 * DWLP_DLGPROC The address of the window's dialog box procedure.
2231 * DWLP_MSGRESULT The return value of a message
2232 * that the dialog box procedure processed.
2234 * DWLP_USER Application specific information.
2236 * RETURNS
2238 * If successful, returns the previous value located at _offset_. Otherwise,
2239 * returns 0.
2241 * NOTES
2243 * Extra memory for a window class is specified by a nonzero cbWndExtra
2244 * parameter of the WNDCLASS structure passed to RegisterClass() at the
2245 * time of class creation.
2247 * Using GWL_WNDPROC to set a new window procedure effectively creates
2248 * a window subclass. Use CallWindowProc() in the new windows procedure
2249 * to pass messages to the superclass's window procedure.
2251 * The user data is reserved for use by the application which created
2252 * the window.
2254 * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2255 * instead, call the EnableWindow() function to change the window's
2256 * disabled state.
2258 * Do not use GWL_HWNDPARENT to reset the window's parent, use
2259 * SetParent() instead.
2261 * Win95:
2262 * When offset is GWL_STYLE and the calling app's ver is 4.0,
2263 * it sends WM_STYLECHANGING before changing the settings
2264 * and WM_STYLECHANGED afterwards.
2265 * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2267 LONG WINAPI SetWindowLongW(
2268 HWND hwnd, /* [in] window to alter */
2269 INT offset, /* [in] offset, in bytes, of location to alter */
2270 LONG newval /* [in] new value of location */
2272 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, TRUE );
2276 /*******************************************************************
2277 * GetWindowTextA (USER32.@)
2279 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2281 WCHAR *buffer;
2283 if (!lpString) return 0;
2285 if (WIN_IsCurrentProcess( hwnd ))
2286 return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2288 /* when window belongs to other process, don't send a message */
2289 if (nMaxCount <= 0) return 0;
2290 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2291 get_server_window_text( hwnd, buffer, nMaxCount );
2292 if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2293 lpString[nMaxCount-1] = 0;
2294 HeapFree( GetProcessHeap(), 0, buffer );
2295 return strlen(lpString);
2299 /*******************************************************************
2300 * InternalGetWindowText (USER32.@)
2302 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2304 WND *win;
2306 if (nMaxCount <= 0) return 0;
2307 if (!(win = WIN_GetPtr( hwnd ))) return 0;
2308 if (win == WND_DESKTOP) lpString[0] = 0;
2309 else if (win != WND_OTHER_PROCESS)
2311 if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2312 else lpString[0] = 0;
2313 WIN_ReleasePtr( win );
2315 else
2317 get_server_window_text( hwnd, lpString, nMaxCount );
2319 return strlenW(lpString);
2323 /*******************************************************************
2324 * GetWindowTextW (USER32.@)
2326 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2328 if (!lpString) return 0;
2330 if (WIN_IsCurrentProcess( hwnd ))
2331 return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2333 /* when window belongs to other process, don't send a message */
2334 if (nMaxCount <= 0) return 0;
2335 get_server_window_text( hwnd, lpString, nMaxCount );
2336 return strlenW(lpString);
2340 /*******************************************************************
2341 * SetWindowTextA (USER32.@)
2342 * SetWindowText (USER32.@)
2344 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2346 if (is_broadcast(hwnd))
2348 SetLastError( ERROR_INVALID_PARAMETER );
2349 return FALSE;
2351 if (!WIN_IsCurrentProcess( hwnd ))
2352 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2353 debugstr_a(lpString), hwnd );
2354 return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2358 /*******************************************************************
2359 * SetWindowTextW (USER32.@)
2361 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2363 if (is_broadcast(hwnd))
2365 SetLastError( ERROR_INVALID_PARAMETER );
2366 return FALSE;
2368 if (!WIN_IsCurrentProcess( hwnd ))
2369 WARN( "setting text %s of other process window %p should not use SendMessage\n",
2370 debugstr_w(lpString), hwnd );
2371 return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2375 /*******************************************************************
2376 * GetWindowTextLengthA (USER32.@)
2378 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2380 return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2383 /*******************************************************************
2384 * GetWindowTextLengthW (USER32.@)
2386 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2388 return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2392 /*******************************************************************
2393 * IsWindow (USER32.@)
2395 BOOL WINAPI IsWindow( HWND hwnd )
2397 WND *ptr;
2398 BOOL ret;
2400 if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2401 if (ptr == WND_DESKTOP) return TRUE;
2403 if (ptr != WND_OTHER_PROCESS)
2405 WIN_ReleasePtr( ptr );
2406 return TRUE;
2409 /* check other processes */
2410 SERVER_START_REQ( get_window_info )
2412 req->handle = hwnd;
2413 ret = !wine_server_call_err( req );
2415 SERVER_END_REQ;
2416 return ret;
2420 /***********************************************************************
2421 * GetWindowThreadProcessId (USER32.@)
2423 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2425 WND *ptr;
2426 DWORD tid = 0;
2428 if (!(ptr = WIN_GetPtr( hwnd )))
2430 SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2431 return 0;
2434 if (ptr != WND_OTHER_PROCESS && ptr != WND_DESKTOP)
2436 /* got a valid window */
2437 tid = ptr->tid;
2438 if (process) *process = GetCurrentProcessId();
2439 WIN_ReleasePtr( ptr );
2440 return tid;
2443 /* check other processes */
2444 SERVER_START_REQ( get_window_info )
2446 req->handle = hwnd;
2447 if (!wine_server_call_err( req ))
2449 tid = (DWORD)reply->tid;
2450 if (process) *process = (DWORD)reply->pid;
2453 SERVER_END_REQ;
2454 return tid;
2458 /*****************************************************************
2459 * GetParent (USER32.@)
2461 HWND WINAPI GetParent( HWND hwnd )
2463 WND *wndPtr;
2464 HWND retvalue = 0;
2466 if (!(wndPtr = WIN_GetPtr( hwnd )))
2468 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2469 return 0;
2471 if (wndPtr == WND_DESKTOP) return 0;
2472 if (wndPtr == WND_OTHER_PROCESS)
2474 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2475 if (style & (WS_POPUP | WS_CHILD))
2477 SERVER_START_REQ( get_window_tree )
2479 req->handle = hwnd;
2480 if (!wine_server_call_err( req ))
2482 if (style & WS_POPUP) retvalue = reply->owner;
2483 else if (style & WS_CHILD) retvalue = reply->parent;
2486 SERVER_END_REQ;
2489 else
2491 if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2492 else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2493 WIN_ReleasePtr( wndPtr );
2495 return retvalue;
2499 /*****************************************************************
2500 * GetAncestor (USER32.@)
2502 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2504 WND *win;
2505 HWND *list, ret = 0;
2507 switch(type)
2509 case GA_PARENT:
2510 if (!(win = WIN_GetPtr( hwnd )))
2512 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2513 return 0;
2515 if (win == WND_DESKTOP) return 0;
2516 if (win != WND_OTHER_PROCESS)
2518 ret = win->parent;
2519 WIN_ReleasePtr( win );
2521 else /* need to query the server */
2523 SERVER_START_REQ( get_window_tree )
2525 req->handle = hwnd;
2526 if (!wine_server_call_err( req )) ret = reply->parent;
2528 SERVER_END_REQ;
2530 break;
2532 case GA_ROOT:
2533 if (!(list = list_window_parents( hwnd ))) return 0;
2535 if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd ); /* top-level window */
2536 else
2538 int count = 2;
2539 while (list[count]) count++;
2540 ret = list[count - 2]; /* get the one before the desktop */
2542 HeapFree( GetProcessHeap(), 0, list );
2543 break;
2545 case GA_ROOTOWNER:
2546 if ((ret = WIN_GetFullHandle( hwnd )) == GetDesktopWindow()) return 0;
2547 for (;;)
2549 HWND parent = GetParent( ret );
2550 if (!parent) break;
2551 ret = parent;
2553 break;
2555 return ret;
2559 /*****************************************************************
2560 * SetParent (USER32.@)
2562 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2564 HWND full_handle;
2565 HWND old_parent = 0;
2566 BOOL was_visible;
2567 WND *wndPtr;
2568 BOOL ret;
2570 if (is_broadcast(hwnd) || is_broadcast(parent))
2572 SetLastError(ERROR_INVALID_PARAMETER);
2573 return 0;
2576 if (!parent) parent = GetDesktopWindow();
2577 else parent = WIN_GetFullHandle( parent );
2579 if (!IsWindow( parent ))
2581 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2582 return 0;
2585 /* Some applications try to set a child as a parent */
2586 if (IsChild(hwnd, parent))
2588 SetLastError( ERROR_INVALID_PARAMETER );
2589 return 0;
2592 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2593 return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2595 /* Windows hides the window first, then shows it again
2596 * including the WM_SHOWWINDOW messages and all */
2597 was_visible = ShowWindow( hwnd, SW_HIDE );
2599 wndPtr = WIN_GetPtr( hwnd );
2600 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
2602 SERVER_START_REQ( set_parent )
2604 req->handle = hwnd;
2605 req->parent = parent;
2606 if ((ret = !wine_server_call( req )))
2608 old_parent = reply->old_parent;
2609 wndPtr->parent = parent = reply->full_parent;
2613 SERVER_END_REQ;
2614 WIN_ReleasePtr( wndPtr );
2615 if (!ret) return 0;
2617 USER_Driver->pSetParent( full_handle, parent, old_parent );
2619 /* SetParent additionally needs to make hwnd the topmost window
2620 in the x-order and send the expected WM_WINDOWPOSCHANGING and
2621 WM_WINDOWPOSCHANGED notification messages.
2623 SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0,
2624 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | (was_visible ? SWP_SHOWWINDOW : 0) );
2625 /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
2626 * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
2628 return old_parent;
2632 /*******************************************************************
2633 * IsChild (USER32.@)
2635 BOOL WINAPI IsChild( HWND parent, HWND child )
2637 HWND *list = list_window_parents( child );
2638 int i;
2639 BOOL ret;
2641 if (!list) return FALSE;
2642 parent = WIN_GetFullHandle( parent );
2643 for (i = 0; list[i]; i++) if (list[i] == parent) break;
2644 ret = list[i] && list[i+1];
2645 HeapFree( GetProcessHeap(), 0, list );
2646 return ret;
2650 /***********************************************************************
2651 * IsWindowVisible (USER32.@)
2653 BOOL WINAPI IsWindowVisible( HWND hwnd )
2655 HWND *list;
2656 BOOL retval = TRUE;
2657 int i;
2659 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2660 if (!(list = list_window_parents( hwnd ))) return TRUE;
2661 if (list[0] && list[1]) /* desktop window is considered always visible so we don't check it */
2663 for (i = 0; list[i+1]; i++)
2664 if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2665 retval = !list[i+1];
2667 HeapFree( GetProcessHeap(), 0, list );
2668 return retval;
2672 /***********************************************************************
2673 * WIN_IsWindowDrawable
2675 * hwnd is drawable when it is visible, all parents are not
2676 * minimized, and it is itself not minimized unless we are
2677 * trying to draw its default class icon.
2679 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2681 HWND *list;
2682 BOOL retval = TRUE;
2683 int i;
2684 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2686 if (!(style & WS_VISIBLE)) return FALSE;
2687 if ((style & WS_MINIMIZE) && icon && GetClassLongPtrW( hwnd, GCLP_HICON )) return FALSE;
2689 if (!(list = list_window_parents( hwnd ))) return TRUE;
2690 if (list[0] && list[1]) /* desktop window is considered always visible so we don't check it */
2692 for (i = 0; list[i+1]; i++)
2693 if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2694 break;
2695 retval = !list[i+1];
2697 HeapFree( GetProcessHeap(), 0, list );
2698 return retval;
2702 /*******************************************************************
2703 * GetTopWindow (USER32.@)
2705 HWND WINAPI GetTopWindow( HWND hwnd )
2707 if (!hwnd) hwnd = GetDesktopWindow();
2708 return GetWindow( hwnd, GW_CHILD );
2712 /*******************************************************************
2713 * GetWindow (USER32.@)
2715 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2717 HWND retval = 0;
2719 if (rel == GW_OWNER) /* this one may be available locally */
2721 WND *wndPtr = WIN_GetPtr( hwnd );
2722 if (!wndPtr)
2724 SetLastError( ERROR_INVALID_HANDLE );
2725 return 0;
2727 if (wndPtr == WND_DESKTOP) return 0;
2728 if (wndPtr != WND_OTHER_PROCESS)
2730 retval = wndPtr->owner;
2731 WIN_ReleasePtr( wndPtr );
2732 return retval;
2734 /* else fall through to server call */
2737 SERVER_START_REQ( get_window_tree )
2739 req->handle = hwnd;
2740 if (!wine_server_call_err( req ))
2742 switch(rel)
2744 case GW_HWNDFIRST:
2745 retval = reply->first_sibling;
2746 break;
2747 case GW_HWNDLAST:
2748 retval = reply->last_sibling;
2749 break;
2750 case GW_HWNDNEXT:
2751 retval = reply->next_sibling;
2752 break;
2753 case GW_HWNDPREV:
2754 retval = reply->prev_sibling;
2755 break;
2756 case GW_OWNER:
2757 retval = reply->owner;
2758 break;
2759 case GW_CHILD:
2760 retval = reply->first_child;
2761 break;
2765 SERVER_END_REQ;
2766 return retval;
2770 /*******************************************************************
2771 * ShowOwnedPopups (USER32.@)
2773 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2775 int count = 0;
2776 WND *pWnd;
2777 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2779 if (!win_array) return TRUE;
2781 while (win_array[count]) count++;
2782 while (--count >= 0)
2784 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2785 if (!(pWnd = WIN_GetPtr( win_array[count] ))) continue;
2786 if (pWnd == WND_OTHER_PROCESS) continue;
2787 if (fShow)
2789 if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2791 WIN_ReleasePtr( pWnd );
2792 /* In Windows, ShowOwnedPopups(TRUE) generates
2793 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
2794 * regardless of the state of the owner
2796 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
2797 continue;
2800 else
2802 if (pWnd->dwStyle & WS_VISIBLE)
2804 WIN_ReleasePtr( pWnd );
2805 /* In Windows, ShowOwnedPopups(FALSE) generates
2806 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
2807 * regardless of the state of the owner
2809 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
2810 continue;
2813 WIN_ReleasePtr( pWnd );
2815 HeapFree( GetProcessHeap(), 0, win_array );
2816 return TRUE;
2820 /*******************************************************************
2821 * GetLastActivePopup (USER32.@)
2823 HWND WINAPI GetLastActivePopup( HWND hwnd )
2825 HWND retval = hwnd;
2827 SERVER_START_REQ( get_window_info )
2829 req->handle = hwnd;
2830 if (!wine_server_call_err( req )) retval = reply->last_active;
2832 SERVER_END_REQ;
2833 return retval;
2837 /*******************************************************************
2838 * WIN_ListChildren
2840 * Build an array of the children of a given window. The array must be
2841 * freed with HeapFree. Returns NULL when no windows are found.
2843 HWND *WIN_ListChildren( HWND hwnd )
2845 return list_window_children( hwnd, NULL, 0 );
2849 /*******************************************************************
2850 * EnumWindows (USER32.@)
2852 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
2854 HWND *list;
2855 BOOL ret = TRUE;
2856 int i;
2858 USER_CheckNotLock();
2860 /* We have to build a list of all windows first, to avoid */
2861 /* unpleasant side-effects, for instance if the callback */
2862 /* function changes the Z-order of the windows. */
2864 if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
2866 /* Now call the callback function for every window */
2868 for (i = 0; list[i]; i++)
2870 /* Make sure that the window still exists */
2871 if (!IsWindow( list[i] )) continue;
2872 if (!(ret = lpEnumFunc( list[i], lParam ))) break;
2874 HeapFree( GetProcessHeap(), 0, list );
2875 return ret;
2879 /**********************************************************************
2880 * EnumThreadWindows (USER32.@)
2882 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
2884 HWND *list;
2885 int i;
2887 USER_CheckNotLock();
2889 if (!(list = list_window_children( GetDesktopWindow(), NULL, id ))) return TRUE;
2891 /* Now call the callback function for every window */
2893 for (i = 0; list[i]; i++)
2894 if (!func( list[i], lParam )) break;
2895 HeapFree( GetProcessHeap(), 0, list );
2896 return TRUE;
2900 /**********************************************************************
2901 * WIN_EnumChildWindows
2903 * Helper function for EnumChildWindows().
2905 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
2907 HWND *childList;
2908 BOOL ret = FALSE;
2910 for ( ; *list; list++)
2912 /* Make sure that the window still exists */
2913 if (!IsWindow( *list )) continue;
2914 /* Build children list first */
2915 childList = WIN_ListChildren( *list );
2917 ret = func( *list, lParam );
2919 if (childList)
2921 if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
2922 HeapFree( GetProcessHeap(), 0, childList );
2924 if (!ret) return FALSE;
2926 return TRUE;
2930 /**********************************************************************
2931 * EnumChildWindows (USER32.@)
2933 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
2935 HWND *list;
2936 BOOL ret;
2938 USER_CheckNotLock();
2940 if (!(list = WIN_ListChildren( parent ))) return FALSE;
2941 ret = WIN_EnumChildWindows( list, func, lParam );
2942 HeapFree( GetProcessHeap(), 0, list );
2943 return ret;
2947 /*******************************************************************
2948 * AnyPopup (USER.52)
2950 BOOL16 WINAPI AnyPopup16(void)
2952 return AnyPopup();
2956 /*******************************************************************
2957 * AnyPopup (USER32.@)
2959 BOOL WINAPI AnyPopup(void)
2961 int i;
2962 BOOL retvalue;
2963 HWND *list = WIN_ListChildren( GetDesktopWindow() );
2965 if (!list) return FALSE;
2966 for (i = 0; list[i]; i++)
2968 if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
2970 retvalue = (list[i] != 0);
2971 HeapFree( GetProcessHeap(), 0, list );
2972 return retvalue;
2976 /*******************************************************************
2977 * FlashWindow (USER32.@)
2979 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
2981 WND *wndPtr;
2983 TRACE("%p\n", hWnd);
2985 if (IsIconic( hWnd ))
2987 RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
2989 wndPtr = WIN_GetPtr(hWnd);
2990 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
2991 if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
2993 wndPtr->flags |= WIN_NCACTIVATED;
2995 else
2997 wndPtr->flags &= ~WIN_NCACTIVATED;
2999 WIN_ReleasePtr( wndPtr );
3000 return TRUE;
3002 else
3004 WPARAM wparam;
3006 wndPtr = WIN_GetPtr(hWnd);
3007 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3008 hWnd = wndPtr->hwndSelf; /* make it a full handle */
3010 if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3011 else wparam = (hWnd == GetForegroundWindow());
3013 WIN_ReleasePtr( wndPtr );
3014 SendMessageW( hWnd, WM_NCACTIVATE, wparam, (LPARAM)0 );
3015 return wparam;
3019 /*******************************************************************
3020 * FlashWindowEx (USER32.@)
3022 BOOL WINAPI FlashWindowEx( PFLASHWINFO pfwi )
3024 FIXME("%p\n", pfwi);
3025 return TRUE;
3028 /*******************************************************************
3029 * GetWindowContextHelpId (USER32.@)
3031 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3033 DWORD retval;
3034 WND *wnd = WIN_GetPtr( hwnd );
3035 if (!wnd || wnd == WND_DESKTOP) return 0;
3036 if (wnd == WND_OTHER_PROCESS)
3038 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3039 return 0;
3041 retval = wnd->helpContext;
3042 WIN_ReleasePtr( wnd );
3043 return retval;
3047 /*******************************************************************
3048 * SetWindowContextHelpId (USER32.@)
3050 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3052 WND *wnd = WIN_GetPtr( hwnd );
3053 if (!wnd || wnd == WND_DESKTOP) return FALSE;
3054 if (wnd == WND_OTHER_PROCESS)
3056 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3057 return 0;
3059 wnd->helpContext = id;
3060 WIN_ReleasePtr( wnd );
3061 return TRUE;
3065 /*******************************************************************
3066 * DragDetect (USER32.@)
3068 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3070 MSG msg;
3071 RECT rect;
3072 WORD wDragWidth = GetSystemMetrics(SM_CXDRAG);
3073 WORD wDragHeight= GetSystemMetrics(SM_CYDRAG);
3075 rect.left = pt.x - wDragWidth;
3076 rect.right = pt.x + wDragWidth;
3078 rect.top = pt.y - wDragHeight;
3079 rect.bottom = pt.y + wDragHeight;
3081 SetCapture(hWnd);
3083 while(1)
3085 while (PeekMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ))
3087 if( msg.message == WM_LBUTTONUP )
3089 ReleaseCapture();
3090 return 0;
3092 if( msg.message == WM_MOUSEMOVE )
3094 POINT tmp;
3095 tmp.x = (short)LOWORD(msg.lParam);
3096 tmp.y = (short)HIWORD(msg.lParam);
3097 if( !PtInRect( &rect, tmp ))
3099 ReleaseCapture();
3100 return 1;
3104 WaitMessage();
3106 return 0;
3109 /******************************************************************************
3110 * GetWindowModuleFileNameA (USER32.@)
3112 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR lpszFileName, UINT cchFileNameMax)
3114 FIXME("GetWindowModuleFileNameA(hwnd %p, lpszFileName %p, cchFileNameMax %u) stub!\n",
3115 hwnd, lpszFileName, cchFileNameMax);
3116 return 0;
3119 /******************************************************************************
3120 * GetWindowModuleFileNameW (USER32.@)
3122 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR lpszFileName, UINT cchFileNameMax)
3124 FIXME("GetWindowModuleFileNameW(hwnd %p, lpszFileName %p, cchFileNameMax %u) stub!\n",
3125 hwnd, lpszFileName, cchFileNameMax);
3126 return 0;
3129 /******************************************************************************
3130 * GetWindowInfo (USER32.@)
3132 * Note: tests show that Windows doesn't check cbSize of the structure.
3134 BOOL WINAPI GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3136 if (!pwi) return FALSE;
3137 if (!IsWindow(hwnd)) return FALSE;
3139 GetWindowRect(hwnd, &pwi->rcWindow);
3140 GetClientRect(hwnd, &pwi->rcClient);
3141 /* translate to screen coordinates */
3142 MapWindowPoints(hwnd, 0, (LPPOINT)&pwi->rcClient, 2);
3144 pwi->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
3145 pwi->dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3146 pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3148 pwi->cxWindowBorders = pwi->rcClient.left - pwi->rcWindow.left;
3149 pwi->cyWindowBorders = pwi->rcWindow.bottom - pwi->rcClient.bottom;
3151 pwi->atomWindowType = GetClassLongW( hwnd, GCW_ATOM );
3152 pwi->wCreatorVersion = 0x0400;
3154 return TRUE;
3157 /******************************************************************************
3158 * SwitchDesktop (USER32.@)
3160 * NOTES: Sets the current input or interactive desktop.
3162 BOOL WINAPI SwitchDesktop( HDESK hDesktop)
3164 FIXME("SwitchDesktop(hwnd %p) stub!\n", hDesktop);
3165 return TRUE;
3168 /*****************************************************************************
3169 * SetLayeredWindowAttributes (USER32.@)
3171 BOOL WINAPI SetLayeredWindowAttributes( HWND hWnd, COLORREF rgbKey,
3172 BYTE bAlpha, DWORD dwFlags )
3174 FIXME("(%p,0x%.8x,%d,%d): stub!\n", hWnd, rgbKey, bAlpha, dwFlags);
3175 return TRUE;
3178 /*****************************************************************************
3179 * GetLayeredWindowAttributes (USER32.@)
3181 BOOL WINAPI GetLayeredWindowAttributes( HWND hWnd, COLORREF *prgbKey,
3182 BYTE *pbAlpha, DWORD *pdwFlags )
3184 FIXME("(%p,%p,%p,%p): stub!\n", hWnd, prgbKey, pbAlpha, pdwFlags);
3185 return FALSE;
3188 /*****************************************************************************
3189 * UpdateLayeredWindow (USER32.@)
3191 BOOL WINAPI UpdateLayeredWindow( HWND hwnd, HDC hdcDst, POINT *pptDst, SIZE *psize,
3192 HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend,
3193 DWORD dwFlags)
3195 static int once;
3196 if (!once)
3198 once = 1;
3199 FIXME("(%p,%p,%p,%p,%p,%p,0x%08x,%p,%d): stub!\n",
3200 hwnd, hdcDst, pptDst, psize, hdcSrc, pptSrc, crKey, pblend, dwFlags);
3202 return 0;
3205 /* 64bit versions */
3207 #ifdef GetWindowLongPtrW
3208 #undef GetWindowLongPtrW
3209 #endif
3211 #ifdef GetWindowLongPtrA
3212 #undef GetWindowLongPtrA
3213 #endif
3215 #ifdef SetWindowLongPtrW
3216 #undef SetWindowLongPtrW
3217 #endif
3219 #ifdef SetWindowLongPtrA
3220 #undef SetWindowLongPtrA
3221 #endif
3223 /*****************************************************************************
3224 * GetWindowLongPtrW (USER32.@)
3226 LONG_PTR WINAPI GetWindowLongPtrW( HWND hwnd, INT offset )
3228 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), TRUE );
3231 /*****************************************************************************
3232 * GetWindowLongPtrA (USER32.@)
3234 LONG_PTR WINAPI GetWindowLongPtrA( HWND hwnd, INT offset )
3236 return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), FALSE );
3239 /*****************************************************************************
3240 * SetWindowLongPtrW (USER32.@)
3242 LONG_PTR WINAPI SetWindowLongPtrW( HWND hwnd, INT offset, LONG_PTR newval )
3244 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, TRUE );
3247 /*****************************************************************************
3248 * SetWindowLongPtrA (USER32.@)
3250 LONG_PTR WINAPI SetWindowLongPtrA( HWND hwnd, INT offset, LONG_PTR newval )
3252 return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, FALSE );