Fixed 16-bit MDI support (based on a patch by Dmitry Timoshkov).
[wine.git] / windows / win.c
blob0a73819308aebe312bf3d3679803ebaf20df36ba
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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.h"
37 #include "dce.h"
38 #include "controls.h"
39 #include "cursoricon.h"
40 #include "message.h"
41 #include "winpos.h"
42 #include "winerror.h"
43 #include "wine/debug.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(win);
46 WINE_DECLARE_DEBUG_CHANNEL(msg);
48 #define NB_USER_HANDLES (LAST_USER_HANDLE - FIRST_USER_HANDLE + 1)
50 /**********************************************************************/
52 /* Desktop window */
53 static WND *pWndDesktop = NULL;
55 static WORD wDragWidth = 4;
56 static WORD wDragHeight= 3;
58 static void *user_handles[NB_USER_HANDLES];
60 /***********************************************************************
61 * create_window_handle
63 * Create a window handle with the server.
65 static WND *create_window_handle( HWND parent, HWND owner, ATOM atom,
66 HINSTANCE instance, WINDOWPROCTYPE type )
68 WORD index;
69 WND *win;
70 struct tagCLASS *class = NULL;
71 user_handle_t handle = 0;
72 int extra_bytes = 0;
74 /* if 16-bit instance, map to module handle */
75 if (instance && !HIWORD(instance))
76 instance = HINSTANCE_32(GetExePtr(HINSTANCE_16(instance)));
78 SERVER_START_REQ( create_window )
80 req->parent = parent;
81 req->owner = owner;
82 req->atom = atom;
83 req->instance = instance;
84 if (!wine_server_call_err( req ))
86 handle = reply->handle;
87 extra_bytes = reply->extra;
88 class = reply->class_ptr;
91 SERVER_END_REQ;
93 if (!handle)
95 WARN( "error %ld creating window\n", GetLastError() );
96 return NULL;
99 if (!(win = HeapAlloc( GetProcessHeap(), 0, sizeof(WND) + extra_bytes - sizeof(win->wExtra) )))
101 SERVER_START_REQ( destroy_window )
103 req->handle = handle;
104 wine_server_call( req );
106 SERVER_END_REQ;
107 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
108 return NULL;
111 USER_Lock();
113 index = LOWORD(handle) - FIRST_USER_HANDLE;
114 assert( index < NB_USER_HANDLES );
115 user_handles[index] = win;
116 win->hwndSelf = handle;
117 win->dwMagic = WND_MAGIC;
118 win->irefCount = 1;
119 win->cbWndExtra = extra_bytes;
120 memset( win->wExtra, 0, extra_bytes );
121 CLASS_AddWindow( class, win, type );
122 return win;
126 /***********************************************************************
127 * free_window_handle
129 * Free a window handle.
131 static WND *free_window_handle( HWND hwnd )
133 WND *ptr;
134 WORD index = LOWORD(hwnd) - FIRST_USER_HANDLE;
136 if (index >= NB_USER_HANDLES) return NULL;
137 USER_Lock();
138 if ((ptr = user_handles[index]))
140 SERVER_START_REQ( destroy_window )
142 req->handle = hwnd;
143 if (!wine_server_call_err( req ))
144 user_handles[index] = NULL;
145 else
146 ptr = NULL;
148 SERVER_END_REQ;
150 USER_Unlock();
151 if (ptr) HeapFree( GetProcessHeap(), 0, ptr );
152 return ptr;
156 /*******************************************************************
157 * list_window_children
159 * Build an array of the children of a given window. The array must be
160 * freed with HeapFree. Returns NULL when no windows are found.
162 static HWND *list_window_children( HWND hwnd, ATOM atom, DWORD tid )
164 HWND *list;
165 int size = 32;
167 for (;;)
169 int count = 0;
171 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) break;
173 SERVER_START_REQ( get_window_children )
175 req->parent = hwnd;
176 req->atom = atom;
177 req->tid = tid;
178 wine_server_set_reply( req, list, (size-1) * sizeof(HWND) );
179 if (!wine_server_call( req )) count = reply->count;
181 SERVER_END_REQ;
182 if (count && count < size)
184 list[count] = 0;
185 return list;
187 HeapFree( GetProcessHeap(), 0, list );
188 if (!count) break;
189 size = count + 1; /* restart with a large enough buffer */
191 return NULL;
195 /*******************************************************************
196 * send_parent_notify
198 static void send_parent_notify( HWND hwnd, UINT msg )
200 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD)) return;
201 if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOPARENTNOTIFY) return;
202 SendMessageW( GetParent(hwnd), WM_PARENTNOTIFY,
203 MAKEWPARAM( msg, GetWindowLongW( hwnd, GWL_ID )), (LPARAM)hwnd );
207 /*******************************************************************
208 * get_server_window_text
210 * Retrieve the window text from the server.
212 static void get_server_window_text( HWND hwnd, LPWSTR text, INT count )
214 size_t len = 0;
216 SERVER_START_REQ( get_window_text )
218 req->handle = hwnd;
219 wine_server_set_reply( req, text, (count - 1) * sizeof(WCHAR) );
220 if (!wine_server_call_err( req )) len = wine_server_reply_size(reply);
222 SERVER_END_REQ;
223 text[len / sizeof(WCHAR)] = 0;
227 /***********************************************************************
228 * WIN_GetPtr
230 * Return a pointer to the WND structure if local to the process,
231 * or WND_OTHER_PROCESS if handle may be valid in other process.
232 * If ret value is a valid pointer, it must be released with WIN_ReleasePtr.
234 WND *WIN_GetPtr( HWND hwnd )
236 WND * ptr;
237 WORD index = LOWORD(hwnd) - FIRST_USER_HANDLE;
239 if (index >= NB_USER_HANDLES) return NULL;
241 USER_Lock();
242 if ((ptr = user_handles[index]))
244 if (ptr->dwMagic == WND_MAGIC && (!HIWORD(hwnd) || hwnd == ptr->hwndSelf))
245 return ptr;
246 ptr = NULL;
248 else ptr = WND_OTHER_PROCESS;
249 USER_Unlock();
250 return ptr;
254 /***********************************************************************
255 * WIN_IsCurrentProcess
257 * Check whether a given window belongs to the current process (and return the full handle).
259 HWND WIN_IsCurrentProcess( HWND hwnd )
261 WND *ptr;
262 HWND ret;
264 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS) return 0;
265 ret = ptr->hwndSelf;
266 WIN_ReleasePtr( ptr );
267 return ret;
271 /***********************************************************************
272 * WIN_IsCurrentThread
274 * Check whether a given window belongs to the current thread (and return the full handle).
276 HWND WIN_IsCurrentThread( HWND hwnd )
278 WND *ptr;
279 HWND ret = 0;
281 if ((ptr = WIN_GetPtr( hwnd )) && ptr != WND_OTHER_PROCESS)
283 if (ptr->tid == GetCurrentThreadId()) ret = ptr->hwndSelf;
284 WIN_ReleasePtr( ptr );
286 return ret;
290 /***********************************************************************
291 * WIN_Handle32
293 * Convert a 16-bit window handle to a full 32-bit handle.
295 HWND WIN_Handle32( HWND16 hwnd16 )
297 WND *ptr;
298 HWND hwnd = (HWND)(ULONG_PTR)hwnd16;
300 if (hwnd16 <= 1 || hwnd16 == 0xffff) return hwnd;
301 /* do sign extension for -2 and -3 */
302 if (hwnd16 >= (HWND16)-3) return (HWND)(LONG_PTR)(INT16)hwnd16;
304 if (!(ptr = WIN_GetPtr( hwnd ))) return hwnd;
306 if (ptr != WND_OTHER_PROCESS)
308 hwnd = ptr->hwndSelf;
309 WIN_ReleasePtr( ptr );
311 else /* may belong to another process */
313 SERVER_START_REQ( get_window_info )
315 req->handle = hwnd;
316 if (!wine_server_call_err( req )) hwnd = reply->full_handle;
318 SERVER_END_REQ;
320 return hwnd;
324 /***********************************************************************
325 * WIN_FindWndPtr
327 * Return a pointer to the WND structure corresponding to a HWND.
329 WND * WIN_FindWndPtr( HWND hwnd )
331 WND * ptr;
333 if (!hwnd) return NULL;
335 if ((ptr = WIN_GetPtr( hwnd )))
337 if (ptr != WND_OTHER_PROCESS)
339 /* increment destruction monitoring */
340 ptr->irefCount++;
341 return ptr;
343 if (IsWindow( hwnd )) /* check other processes */
345 ERR( "window %p belongs to other process\n", hwnd );
346 /* DbgBreakPoint(); */
349 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
350 return NULL;
354 /***********************************************************************
355 * WIN_ReleaseWndPtr
357 * Release the pointer to the WND structure.
359 void WIN_ReleaseWndPtr(WND *wndPtr)
361 if(!wndPtr) return;
363 /* Decrement destruction monitoring value */
364 wndPtr->irefCount--;
365 /* Check if it's time to release the memory */
366 if(wndPtr->irefCount == 0 && !wndPtr->dwMagic)
368 /* Release memory */
369 free_window_handle( wndPtr->hwndSelf );
371 else if(wndPtr->irefCount < 0)
373 /* This else if is useful to monitor the WIN_ReleaseWndPtr function */
374 ERR("forgot a Lock on %p somewhere\n",wndPtr);
376 /* unlock all WND structures for thread safeness */
377 USER_Unlock();
381 /***********************************************************************
382 * WIN_UnlinkWindow
384 * Remove a window from the siblings linked list.
386 void WIN_UnlinkWindow( HWND hwnd )
388 WIN_LinkWindow( hwnd, 0, 0 );
392 /***********************************************************************
393 * WIN_LinkWindow
395 * Insert a window into the siblings linked list.
396 * The window is inserted after the specified window, which can also
397 * be specified as HWND_TOP or HWND_BOTTOM.
398 * If parent is 0, window is unlinked from the tree.
400 void WIN_LinkWindow( HWND hwnd, HWND parent, HWND hwndInsertAfter )
402 WND *wndPtr = WIN_GetPtr( hwnd );
404 if (!wndPtr) return;
405 if (wndPtr == WND_OTHER_PROCESS)
407 if (IsWindow(hwnd)) ERR(" cannot link other process window %p\n", hwnd );
408 return;
411 SERVER_START_REQ( link_window )
413 req->handle = hwnd;
414 req->parent = parent;
415 req->previous = hwndInsertAfter;
416 if (!wine_server_call( req ))
418 if (reply->full_parent) wndPtr->parent = reply->full_parent;
422 SERVER_END_REQ;
423 WIN_ReleasePtr( wndPtr );
427 /***********************************************************************
428 * WIN_SetOwner
430 * Change the owner of a window.
432 HWND WIN_SetOwner( HWND hwnd, HWND owner )
434 WND *win = WIN_GetPtr( hwnd );
435 HWND ret = 0;
437 if (!win) return 0;
438 if (win == WND_OTHER_PROCESS)
440 if (IsWindow(hwnd)) ERR( "cannot set owner %p on other process window %p\n", owner, hwnd );
441 return 0;
443 SERVER_START_REQ( set_window_owner )
445 req->handle = hwnd;
446 req->owner = owner;
447 if (!wine_server_call( req ))
449 win->owner = reply->full_owner;
450 ret = reply->prev_owner;
453 SERVER_END_REQ;
454 WIN_ReleasePtr( win );
455 return ret;
459 /***********************************************************************
460 * WIN_SetStyle
462 * Change the style of a window.
464 LONG WIN_SetStyle( HWND hwnd, LONG style )
466 BOOL ok;
467 LONG ret = 0;
468 WND *win = WIN_GetPtr( hwnd );
470 if (!win) return 0;
471 if (win == WND_OTHER_PROCESS)
473 if (IsWindow(hwnd))
474 ERR( "cannot set style %lx on other process window %p\n", style, hwnd );
475 return 0;
477 if (style == win->dwStyle)
479 WIN_ReleasePtr( win );
480 return style;
482 SERVER_START_REQ( set_window_info )
484 req->handle = hwnd;
485 req->flags = SET_WIN_STYLE;
486 req->style = style;
487 req->extra_offset = -1;
488 if ((ok = !wine_server_call( req )))
490 ret = reply->old_style;
491 win->dwStyle = style;
494 SERVER_END_REQ;
495 WIN_ReleasePtr( win );
496 if (ok && USER_Driver.pSetWindowStyle) USER_Driver.pSetWindowStyle( hwnd, ret );
497 return ret;
501 /***********************************************************************
502 * WIN_SetExStyle
504 * Change the extended style of a window.
506 LONG WIN_SetExStyle( HWND hwnd, LONG style )
508 LONG ret = 0;
509 WND *win = WIN_GetPtr( hwnd );
511 if (!win) return 0;
512 if (win == WND_OTHER_PROCESS)
514 if (IsWindow(hwnd))
515 ERR( "cannot set exstyle %lx on other process window %p\n", style, hwnd );
516 return 0;
518 if (style == win->dwExStyle)
520 WIN_ReleasePtr( win );
521 return style;
523 SERVER_START_REQ( set_window_info )
525 req->handle = hwnd;
526 req->flags = SET_WIN_EXSTYLE;
527 req->ex_style = style;
528 req->extra_offset = -1;
529 if (!wine_server_call( req ))
531 ret = reply->old_ex_style;
532 win->dwExStyle = style;
535 SERVER_END_REQ;
536 WIN_ReleasePtr( win );
537 return ret;
541 /***********************************************************************
542 * WIN_SetRectangles
544 * Set the window and client rectangles.
546 void WIN_SetRectangles( HWND hwnd, const RECT *rectWindow, const RECT *rectClient )
548 WND *win = WIN_GetPtr( hwnd );
549 BOOL ret;
551 if (!win) return;
552 if (win == WND_OTHER_PROCESS)
554 if (IsWindow( hwnd )) ERR( "cannot set rectangles of other process window %p\n", hwnd );
555 return;
557 SERVER_START_REQ( set_window_rectangles )
559 req->handle = hwnd;
560 req->window.left = rectWindow->left;
561 req->window.top = rectWindow->top;
562 req->window.right = rectWindow->right;
563 req->window.bottom = rectWindow->bottom;
564 req->client.left = rectClient->left;
565 req->client.top = rectClient->top;
566 req->client.right = rectClient->right;
567 req->client.bottom = rectClient->bottom;
568 ret = !wine_server_call( req );
570 SERVER_END_REQ;
571 if (ret)
573 win->rectWindow = *rectWindow;
574 win->rectClient = *rectClient;
576 TRACE( "win %p window (%ld,%ld)-(%ld,%ld) client (%ld,%ld)-(%ld,%ld)\n", hwnd,
577 rectWindow->left, rectWindow->top, rectWindow->right, rectWindow->bottom,
578 rectClient->left, rectClient->top, rectClient->right, rectClient->bottom );
580 WIN_ReleasePtr( win );
584 /***********************************************************************
585 * WIN_GetRectangles
587 * Get the window and client rectangles.
589 BOOL WIN_GetRectangles( HWND hwnd, RECT *rectWindow, RECT *rectClient )
591 WND *win = WIN_GetPtr( hwnd );
592 BOOL ret = TRUE;
594 if (!win) return FALSE;
595 if (win == WND_OTHER_PROCESS)
597 SERVER_START_REQ( get_window_rectangles )
599 req->handle = hwnd;
600 if ((ret = !wine_server_call( req )))
602 if (rectWindow)
604 rectWindow->left = reply->window.left;
605 rectWindow->top = reply->window.top;
606 rectWindow->right = reply->window.right;
607 rectWindow->bottom = reply->window.bottom;
609 if (rectClient)
611 rectClient->left = reply->client.left;
612 rectClient->top = reply->client.top;
613 rectClient->right = reply->client.right;
614 rectClient->bottom = reply->client.bottom;
618 SERVER_END_REQ;
620 else
622 if (rectWindow) *rectWindow = win->rectWindow;
623 if (rectClient) *rectClient = win->rectClient;
624 WIN_ReleasePtr( win );
626 return ret;
630 /***********************************************************************
631 * WIN_DestroyWindow
633 * Destroy storage associated to a window. "Internals" p.358
635 LRESULT WIN_DestroyWindow( HWND hwnd )
637 WND *wndPtr;
638 HWND *list;
640 TRACE("%p\n", hwnd );
642 if (!(hwnd = WIN_IsCurrentThread( hwnd )))
644 ERR( "window doesn't belong to current thread\n" );
645 return 0;
648 /* free child windows */
649 if ((list = WIN_ListChildren( hwnd )))
651 int i;
652 for (i = 0; list[i]; i++)
654 if (WIN_IsCurrentThread( list[i] )) WIN_DestroyWindow( list[i] );
655 else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
657 HeapFree( GetProcessHeap(), 0, list );
661 * Clear the update region to make sure no WM_PAINT messages will be
662 * generated for this window while processing the WM_NCDESTROY.
664 RedrawWindow( hwnd, NULL, 0,
665 RDW_VALIDATE | RDW_NOFRAME | RDW_NOERASE | RDW_NOINTERNALPAINT | RDW_NOCHILDREN);
668 * Send the WM_NCDESTROY to the window being destroyed.
670 SendMessageA( hwnd, WM_NCDESTROY, 0, 0);
672 /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
674 WINPOS_CheckInternalPos( hwnd );
675 if( hwnd == GetCapture()) ReleaseCapture();
677 /* free resources associated with the window */
679 TIMER_RemoveWindowTimers( hwnd );
681 if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
683 if (!(wndPtr->dwStyle & WS_CHILD))
685 HMENU menu = (HMENU)SetWindowLongW( hwnd, GWL_ID, 0 );
686 if (menu) DestroyMenu( menu );
688 if (wndPtr->hSysMenu)
690 DestroyMenu( wndPtr->hSysMenu );
691 wndPtr->hSysMenu = 0;
693 DCE_FreeWindowDCE( hwnd ); /* Always do this to catch orphaned DCs */
694 USER_Driver.pDestroyWindow( hwnd );
695 WINPROC_FreeProc( wndPtr->winproc, WIN_PROC_WINDOW );
696 wndPtr->class = NULL;
697 wndPtr->dwMagic = 0; /* Mark it as invalid */
698 WIN_ReleaseWndPtr( wndPtr );
699 return 0;
702 /***********************************************************************
703 * WIN_DestroyThreadWindows
705 * Destroy all children of 'wnd' owned by the current thread.
706 * Return TRUE if something was done.
708 void WIN_DestroyThreadWindows( HWND hwnd )
710 HWND *list;
711 int i;
713 if (!(list = WIN_ListChildren( hwnd ))) return;
714 for (i = 0; list[i]; i++)
716 if (WIN_IsCurrentThread( list[i] ))
717 DestroyWindow( list[i] );
718 else
719 WIN_DestroyThreadWindows( list[i] );
721 HeapFree( GetProcessHeap(), 0, list );
724 /***********************************************************************
725 * WIN_CreateDesktopWindow
727 * Create the desktop window.
729 BOOL WIN_CreateDesktopWindow(void)
731 HWND hwndDesktop;
732 CREATESTRUCTA cs;
733 RECT rect;
735 TRACE("Creating desktop window\n");
737 if (!WINPOS_CreateInternalPosAtom()) return FALSE;
739 pWndDesktop = create_window_handle( 0, 0, LOWORD(DESKTOP_CLASS_ATOM), 0, WIN_PROC_32W );
740 if (!pWndDesktop) return FALSE;
741 hwndDesktop = pWndDesktop->hwndSelf;
743 pWndDesktop->tid = 0; /* nobody owns the desktop */
744 pWndDesktop->parent = 0;
745 pWndDesktop->owner = 0;
746 pWndDesktop->text = NULL;
747 pWndDesktop->hrgnUpdate = 0;
748 pWndDesktop->pVScroll = NULL;
749 pWndDesktop->pHScroll = NULL;
750 pWndDesktop->helpContext = 0;
751 pWndDesktop->flags = 0;
752 pWndDesktop->hSysMenu = 0;
754 cs.lpCreateParams = NULL;
755 cs.hInstance = 0;
756 cs.hMenu = 0;
757 cs.hwndParent = 0;
758 cs.x = 0;
759 cs.y = 0;
760 cs.cx = GetSystemMetrics( SM_CXSCREEN );
761 cs.cy = GetSystemMetrics( SM_CYSCREEN );
762 cs.style = pWndDesktop->dwStyle;
763 cs.dwExStyle = pWndDesktop->dwExStyle;
764 cs.lpszName = NULL;
765 cs.lpszClass = DESKTOP_CLASS_ATOM;
767 SetRect( &rect, 0, 0, cs.cx, cs.cy );
768 WIN_SetRectangles( hwndDesktop, &rect, &rect );
770 SERVER_START_REQ( set_window_info )
772 req->handle = hwndDesktop;
773 req->flags = 0; /* don't set anything, just retrieve */
774 req->extra_offset = -1;
775 wine_server_call( req );
776 pWndDesktop->dwStyle = reply->old_style;
777 pWndDesktop->dwExStyle = reply->old_ex_style;
778 pWndDesktop->hInstance = (HINSTANCE)reply->old_instance;
779 pWndDesktop->userdata = (ULONG_PTR)reply->old_user_data;
780 pWndDesktop->wIDmenu = reply->old_id;
782 SERVER_END_REQ;
784 if (!USER_Driver.pCreateWindow( hwndDesktop, &cs, FALSE ))
786 WIN_ReleaseWndPtr( pWndDesktop );
787 return FALSE;
790 pWndDesktop->flags |= WIN_NEEDS_ERASEBKGND;
791 WIN_ReleaseWndPtr( pWndDesktop );
792 return TRUE;
796 /***********************************************************************
797 * WIN_FixCoordinates
799 * Fix the coordinates - Helper for WIN_CreateWindowEx.
800 * returns default show mode in sw.
801 * Note: the feature presented as undocumented *is* in the MSDN since 1993.
803 static void WIN_FixCoordinates( CREATESTRUCTA *cs, INT *sw)
805 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16 ||
806 cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16)
808 if (cs->style & (WS_CHILD | WS_POPUP))
810 if (cs->dwExStyle & WS_EX_MDICHILD)
812 POINT pos[2];
814 MDI_CalcDefaultChildPos(cs->hwndParent, -1, pos, 0);
816 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16)
818 cs->x = pos[0].x;
819 cs->y = pos[0].y;
821 if (cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16 || !cs->cx)
822 cs->cx = pos[1].x;
823 if (cs->cy == CW_USEDEFAULT || cs->cy == CW_USEDEFAULT16 || !cs->cy)
824 cs->cy = pos[1].y;
826 else
828 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16)
829 cs->x = cs->y = 0;
830 if (cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16)
831 cs->cx = cs->cy = 0;
834 else /* overlapped window */
836 STARTUPINFOA info;
838 GetStartupInfoA( &info );
840 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16)
842 /* Never believe Microsoft's documentation... CreateWindowEx doc says
843 * that if an overlapped window is created with WS_VISIBLE style bit
844 * set and the x parameter is set to CW_USEDEFAULT, the system ignores
845 * the y parameter. However, disassembling NT implementation (WIN32K.SYS)
846 * reveals that
848 * 1) not only it checks for CW_USEDEFAULT but also for CW_USEDEFAULT16
849 * 2) it does not ignore the y parameter as the docs claim; instead, it
850 * uses it as second parameter to ShowWindow() unless y is either
851 * CW_USEDEFAULT or CW_USEDEFAULT16.
853 * The fact that we didn't do 2) caused bogus windows pop up when wine
854 * was running apps that were using this obscure feature. Example -
855 * calc.exe that comes with Win98 (only Win98, it's different from
856 * the one that comes with Win95 and NT)
858 if (cs->y != CW_USEDEFAULT && cs->y != CW_USEDEFAULT16) *sw = cs->y;
859 cs->x = (info.dwFlags & STARTF_USEPOSITION) ? info.dwX : 0;
860 cs->y = (info.dwFlags & STARTF_USEPOSITION) ? info.dwY : 0;
863 if (cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16)
865 if (info.dwFlags & STARTF_USESIZE)
867 cs->cx = info.dwXSize;
868 cs->cy = info.dwYSize;
870 else /* if no other hint from the app, pick 3/4 of the screen real estate */
872 RECT r;
873 SystemParametersInfoA( SPI_GETWORKAREA, 0, &r, 0);
874 cs->cx = (((r.right - r.left) * 3) / 4) - cs->x;
875 cs->cy = (((r.bottom - r.top) * 3) / 4) - cs->y;
880 else
882 /* neither x nor cx are default. Check the y values .
883 * In the trace we see Outlook and Outlook Express using
884 * cy set to CW_USEDEFAULT when opening the address book.
886 if (cs->cy == CW_USEDEFAULT || cs->cy == CW_USEDEFAULT16) {
887 RECT r;
888 FIXME("Strange use of CW_USEDEFAULT in nHeight\n");
889 SystemParametersInfoA( SPI_GETWORKAREA, 0, &r, 0);
890 cs->cy = (((r.bottom - r.top) * 3) / 4) - cs->y;
895 /***********************************************************************
896 * dump_window_styles
898 static void dump_window_styles( DWORD style, DWORD exstyle )
900 TRACE( "style:" );
901 if(style & WS_POPUP) TRACE(" WS_POPUP");
902 if(style & WS_CHILD) TRACE(" WS_CHILD");
903 if(style & WS_MINIMIZE) TRACE(" WS_MINIMIZE");
904 if(style & WS_VISIBLE) TRACE(" WS_VISIBLE");
905 if(style & WS_DISABLED) TRACE(" WS_DISABLED");
906 if(style & WS_CLIPSIBLINGS) TRACE(" WS_CLIPSIBLINGS");
907 if(style & WS_CLIPCHILDREN) TRACE(" WS_CLIPCHILDREN");
908 if(style & WS_MAXIMIZE) TRACE(" WS_MAXIMIZE");
909 if((style & WS_CAPTION) == WS_CAPTION) TRACE(" WS_CAPTION");
910 else
912 if(style & WS_BORDER) TRACE(" WS_BORDER");
913 if(style & WS_DLGFRAME) TRACE(" WS_DLGFRAME");
915 if(style & WS_VSCROLL) TRACE(" WS_VSCROLL");
916 if(style & WS_HSCROLL) TRACE(" WS_HSCROLL");
917 if(style & WS_SYSMENU) TRACE(" WS_SYSMENU");
918 if(style & WS_THICKFRAME) TRACE(" WS_THICKFRAME");
919 if(style & WS_GROUP) TRACE(" WS_GROUP");
920 if(style & WS_TABSTOP) TRACE(" WS_TABSTOP");
921 if(style & WS_MINIMIZEBOX) TRACE(" WS_MINIMIZEBOX");
922 if(style & WS_MAXIMIZEBOX) TRACE(" WS_MAXIMIZEBOX");
924 /* FIXME: Add dumping of BS_/ES_/SBS_/LBS_/CBS_/DS_/etc. styles */
925 #define DUMPED_STYLES \
926 (WS_POPUP | \
927 WS_CHILD | \
928 WS_MINIMIZE | \
929 WS_VISIBLE | \
930 WS_DISABLED | \
931 WS_CLIPSIBLINGS | \
932 WS_CLIPCHILDREN | \
933 WS_MAXIMIZE | \
934 WS_BORDER | \
935 WS_DLGFRAME | \
936 WS_VSCROLL | \
937 WS_HSCROLL | \
938 WS_SYSMENU | \
939 WS_THICKFRAME | \
940 WS_GROUP | \
941 WS_TABSTOP | \
942 WS_MINIMIZEBOX | \
943 WS_MAXIMIZEBOX)
945 if(style & ~DUMPED_STYLES) TRACE(" %08lx", style & ~DUMPED_STYLES);
946 TRACE("\n");
947 #undef DUMPED_STYLES
949 TRACE( "exstyle:" );
950 if(exstyle & WS_EX_DLGMODALFRAME) TRACE(" WS_EX_DLGMODALFRAME");
951 if(exstyle & WS_EX_DRAGDETECT) TRACE(" WS_EX_DRAGDETECT");
952 if(exstyle & WS_EX_NOPARENTNOTIFY) TRACE(" WS_EX_NOPARENTNOTIFY");
953 if(exstyle & WS_EX_TOPMOST) TRACE(" WS_EX_TOPMOST");
954 if(exstyle & WS_EX_ACCEPTFILES) TRACE(" WS_EX_ACCEPTFILES");
955 if(exstyle & WS_EX_TRANSPARENT) TRACE(" WS_EX_TRANSPARENT");
956 if(exstyle & WS_EX_MDICHILD) TRACE(" WS_EX_MDICHILD");
957 if(exstyle & WS_EX_TOOLWINDOW) TRACE(" WS_EX_TOOLWINDOW");
958 if(exstyle & WS_EX_WINDOWEDGE) TRACE(" WS_EX_WINDOWEDGE");
959 if(exstyle & WS_EX_CLIENTEDGE) TRACE(" WS_EX_CLIENTEDGE");
960 if(exstyle & WS_EX_CONTEXTHELP) TRACE(" WS_EX_CONTEXTHELP");
961 if(exstyle & WS_EX_RIGHT) TRACE(" WS_EX_RIGHT");
962 if(exstyle & WS_EX_RTLREADING) TRACE(" WS_EX_RTLREADING");
963 if(exstyle & WS_EX_LEFTSCROLLBAR) TRACE(" WS_EX_LEFTSCROLLBAR");
964 if(exstyle & WS_EX_CONTROLPARENT) TRACE(" WS_EX_CONTROLPARENT");
965 if(exstyle & WS_EX_STATICEDGE) TRACE(" WS_EX_STATICEDGE");
966 if(exstyle & WS_EX_APPWINDOW) TRACE(" WS_EX_APPWINDOW");
967 if(exstyle & WS_EX_LAYERED) TRACE(" WS_EX_LAYERED");
969 #define DUMPED_EX_STYLES \
970 (WS_EX_DLGMODALFRAME | \
971 WS_EX_DRAGDETECT | \
972 WS_EX_NOPARENTNOTIFY | \
973 WS_EX_TOPMOST | \
974 WS_EX_ACCEPTFILES | \
975 WS_EX_TRANSPARENT | \
976 WS_EX_MDICHILD | \
977 WS_EX_TOOLWINDOW | \
978 WS_EX_WINDOWEDGE | \
979 WS_EX_CLIENTEDGE | \
980 WS_EX_CONTEXTHELP | \
981 WS_EX_RIGHT | \
982 WS_EX_RTLREADING | \
983 WS_EX_LEFTSCROLLBAR | \
984 WS_EX_CONTROLPARENT | \
985 WS_EX_STATICEDGE | \
986 WS_EX_APPWINDOW | \
987 WS_EX_LAYERED)
989 if(exstyle & ~DUMPED_EX_STYLES) TRACE(" %08lx", exstyle & ~DUMPED_EX_STYLES);
990 TRACE("\n");
991 #undef DUMPED_EX_STYLES
995 /***********************************************************************
996 * WIN_CreateWindowEx
998 * Implementation of CreateWindowEx().
1000 static HWND WIN_CreateWindowEx( CREATESTRUCTA *cs, ATOM classAtom,
1001 WINDOWPROCTYPE type )
1003 INT sw = SW_SHOW;
1004 WND *wndPtr;
1005 HWND hwnd, parent, owner, top_child = 0;
1006 BOOL unicode = (type == WIN_PROC_32W);
1008 TRACE("%s %s ex=%08lx style=%08lx %d,%d %dx%d parent=%p menu=%p inst=%p params=%p\n",
1009 (type == WIN_PROC_32W) ? debugstr_w((LPWSTR)cs->lpszName) : debugstr_a(cs->lpszName),
1010 (type == WIN_PROC_32W) ? debugstr_w((LPWSTR)cs->lpszClass) : debugstr_a(cs->lpszClass),
1011 cs->dwExStyle, cs->style, cs->x, cs->y, cs->cx, cs->cy,
1012 cs->hwndParent, cs->hMenu, cs->hInstance, cs->lpCreateParams );
1014 if(TRACE_ON(win)) dump_window_styles( cs->style, cs->dwExStyle );
1016 TRACE("winproc type is %d (%s)\n", type, (type == WIN_PROC_16) ? "WIN_PROC_16" :
1017 ((type == WIN_PROC_32A) ? "WIN_PROC_32A" : "WIN_PROC_32W") );
1019 /* Fix the styles for MDI children */
1020 if (cs->dwExStyle & WS_EX_MDICHILD)
1022 MDICREATESTRUCTA mdi_cs;
1023 UINT flags = 0;
1025 wndPtr = WIN_GetPtr(cs->hwndParent);
1026 if (wndPtr && wndPtr != WND_OTHER_PROCESS)
1028 flags = wndPtr->flags;
1029 WIN_ReleasePtr(wndPtr);
1032 if (!(flags & WIN_ISMDICLIENT))
1034 WARN("WS_EX_MDICHILD, but parent %p is not MDIClient\n", cs->hwndParent);
1035 return 0;
1038 /* cs->lpCreateParams of WM_[NC]CREATE is different for MDI children.
1039 * MDICREATESTRUCT members have the originally passed values.
1041 * Note: we rely on the fact that MDICREATESTRUCTA and MDICREATESTRUCTW
1042 * have the same layout.
1044 mdi_cs.szClass = cs->lpszClass;
1045 mdi_cs.szTitle = cs->lpszName;
1046 mdi_cs.hOwner = cs->hInstance;
1047 mdi_cs.x = cs->x;
1048 mdi_cs.y = cs->y;
1049 mdi_cs.cx = cs->cx;
1050 mdi_cs.cy = cs->cy;
1051 mdi_cs.style = cs->style;
1052 mdi_cs.lParam = (LPARAM)cs->lpCreateParams;
1054 cs->lpCreateParams = (LPVOID)&mdi_cs;
1056 if (GetWindowLongW(cs->hwndParent, GWL_STYLE) & MDIS_ALLCHILDSTYLES)
1058 if (cs->style & WS_POPUP)
1060 TRACE("WS_POPUP with MDIS_ALLCHILDSTYLES is not allowed\n");
1061 return 0;
1063 cs->style |= WS_CHILD | WS_CLIPSIBLINGS;
1065 else
1067 cs->style &= ~WS_POPUP;
1068 cs->style |= WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION |
1069 WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
1072 top_child = GetWindow(cs->hwndParent, GW_CHILD);
1075 /* Find the parent window */
1077 parent = GetDesktopWindow();
1078 owner = 0;
1080 if (cs->hwndParent == HWND_MESSAGE)
1082 /* native ole32.OleInitialize uses HWND_MESSAGE to create the
1083 * message window (style: WS_POPUP|WS_DISABLED)
1085 FIXME("Parent is HWND_MESSAGE\n");
1087 else if (cs->hwndParent)
1089 /* Make sure parent is valid */
1090 if (!IsWindow( cs->hwndParent ))
1092 WARN("Bad parent %p\n", cs->hwndParent );
1093 return 0;
1095 if ((cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
1096 parent = WIN_GetFullHandle(cs->hwndParent);
1097 else
1098 owner = GetAncestor( cs->hwndParent, GA_ROOT );
1100 else if ((cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
1102 WARN("No parent for child window\n" );
1103 return 0; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
1106 WIN_FixCoordinates(cs, &sw); /* fix default coordinates */
1108 /* Correct the window style - stage 1
1110 * These are patches that appear to affect both the style loaded into the
1111 * WIN structure and passed in the CreateStruct to the WM_CREATE etc.
1113 * WS_EX_WINDOWEDGE appears to be enforced based on the other styles, so
1114 * why does the user get to set it?
1117 /* This has been tested for WS_CHILD | WS_VISIBLE. It has not been
1118 * tested for WS_POPUP
1120 if ((cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
1121 ((!(cs->dwExStyle & WS_EX_STATICEDGE)) &&
1122 (cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
1123 cs->dwExStyle |= WS_EX_WINDOWEDGE;
1124 else
1125 cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
1127 /* Create the window structure */
1129 if (!(wndPtr = create_window_handle( parent, owner, classAtom, cs->hInstance, type )))
1131 TRACE("out of memory\n" );
1132 return 0;
1134 hwnd = wndPtr->hwndSelf;
1136 /* Fill the window structure */
1138 wndPtr->tid = GetCurrentThreadId();
1139 wndPtr->owner = owner;
1140 wndPtr->parent = parent;
1141 wndPtr->hInstance = cs->hInstance;
1142 wndPtr->text = NULL;
1143 wndPtr->hrgnUpdate = 0;
1144 wndPtr->hrgnWnd = 0;
1145 wndPtr->dwStyle = cs->style & ~WS_VISIBLE;
1146 wndPtr->dwExStyle = cs->dwExStyle;
1147 wndPtr->wIDmenu = 0;
1148 wndPtr->helpContext = 0;
1149 wndPtr->flags = (type == WIN_PROC_16) ? 0 : WIN_ISWIN32;
1150 wndPtr->pVScroll = NULL;
1151 wndPtr->pHScroll = NULL;
1152 wndPtr->userdata = 0;
1153 wndPtr->hIcon = 0;
1154 wndPtr->hIconSmall = 0;
1155 wndPtr->hSysMenu = (wndPtr->dwStyle & WS_SYSMENU) ? MENU_GetSysMenu( hwnd, 0 ) : 0;
1157 /* Correct the window style - stage 2 */
1159 if (!(cs->style & WS_CHILD))
1161 wndPtr->dwStyle |= WS_CLIPSIBLINGS;
1162 if (!(cs->style & WS_POPUP))
1164 wndPtr->dwStyle |= WS_CAPTION;
1165 wndPtr->flags |= WIN_NEED_SIZE;
1168 SERVER_START_REQ( set_window_info )
1170 req->handle = hwnd;
1171 req->flags = SET_WIN_STYLE | SET_WIN_EXSTYLE | SET_WIN_INSTANCE;
1172 req->style = wndPtr->dwStyle;
1173 req->ex_style = wndPtr->dwExStyle;
1174 req->instance = (void *)wndPtr->hInstance;
1175 req->extra_offset = -1;
1176 wine_server_call( req );
1178 SERVER_END_REQ;
1180 /* Get class or window DC if needed */
1182 if (wndPtr->clsStyle & CS_OWNDC) wndPtr->dce = DCE_AllocDCE(hwnd,DCE_WINDOW_DC);
1184 /* Set the window menu */
1186 if (((wndPtr->dwStyle & (WS_CAPTION|WS_CHILD)) == WS_CAPTION) ||
1187 (wndPtr->dwExStyle & WS_EX_APPWINDOW))
1189 if (cs->hMenu) SetMenu(hwnd, cs->hMenu);
1190 else
1192 LPCSTR menuName = (LPCSTR)GetClassLongA( hwnd, GCL_MENUNAME );
1193 if (menuName)
1195 if (HIWORD(cs->hInstance))
1196 cs->hMenu = LoadMenuA(cs->hInstance,menuName);
1197 else
1198 cs->hMenu = HMENU_32(LoadMenu16(HINSTANCE_16(cs->hInstance),menuName));
1200 if (cs->hMenu) SetMenu( hwnd, cs->hMenu );
1204 else SetWindowLongW( hwnd, GWL_ID, (UINT)cs->hMenu );
1205 WIN_ReleaseWndPtr( wndPtr );
1207 if (!USER_Driver.pCreateWindow( hwnd, cs, unicode))
1209 WIN_DestroyWindow( hwnd );
1210 return 0;
1213 /* Notify the parent window only */
1215 send_parent_notify( hwnd, WM_CREATE );
1216 if (!IsWindow( hwnd )) return 0;
1218 if (cs->dwExStyle & WS_EX_MDICHILD)
1220 if (top_child)
1222 /* Restore current maximized child */
1223 if((cs->style & WS_VISIBLE) && IsZoomed(top_child))
1225 TRACE("Restoring current maximized child %p\n", top_child);
1226 ShowWindow(top_child, SW_SHOWNOACTIVATE);
1230 SendMessageW(cs->hwndParent, WM_MDIREFRESHMENU, 0, 0);
1233 if (cs->style & WS_VISIBLE)
1235 /* in case WS_VISIBLE got set in the meantime */
1236 if (!(wndPtr = WIN_GetPtr( hwnd ))) return 0;
1237 WIN_SetStyle( hwnd, wndPtr->dwStyle & ~WS_VISIBLE );
1238 WIN_ReleasePtr( wndPtr );
1239 ShowWindow( hwnd, sw );
1242 /* Call WH_SHELL hook */
1244 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1245 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0, TRUE );
1247 TRACE("created window %p\n", hwnd);
1248 return hwnd;
1252 /***********************************************************************
1253 * CreateWindow (USER.41)
1255 HWND16 WINAPI CreateWindow16( LPCSTR className, LPCSTR windowName,
1256 DWORD style, INT16 x, INT16 y, INT16 width,
1257 INT16 height, HWND16 parent, HMENU16 menu,
1258 HINSTANCE16 instance, LPVOID data )
1260 return CreateWindowEx16( 0, className, windowName, style,
1261 x, y, width, height, parent, menu, instance, data );
1265 /***********************************************************************
1266 * CreateWindowEx (USER.452)
1268 HWND16 WINAPI CreateWindowEx16( DWORD exStyle, LPCSTR className,
1269 LPCSTR windowName, DWORD style, INT16 x,
1270 INT16 y, INT16 width, INT16 height,
1271 HWND16 parent, HMENU16 menu,
1272 HINSTANCE16 instance, LPVOID data )
1274 ATOM classAtom;
1275 CREATESTRUCTA cs;
1276 char buffer[256];
1278 /* Find the class atom */
1280 if (HIWORD(className))
1282 if (!(classAtom = GlobalFindAtomA( className )))
1284 ERR( "bad class name %s\n", debugstr_a(className) );
1285 return 0;
1288 else
1290 classAtom = LOWORD(className);
1291 if (!GlobalGetAtomNameA( classAtom, buffer, sizeof(buffer) ))
1293 ERR( "bad atom %x\n", classAtom);
1294 return 0;
1296 className = buffer;
1299 /* Fix the coordinates */
1301 cs.x = (x == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)x;
1302 cs.y = (y == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)y;
1303 cs.cx = (width == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)width;
1304 cs.cy = (height == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)height;
1306 /* Create the window */
1308 cs.lpCreateParams = data;
1309 cs.hInstance = HINSTANCE_32(instance);
1310 cs.hMenu = HMENU_32(menu);
1311 cs.hwndParent = WIN_Handle32( parent );
1312 cs.style = style;
1313 cs.lpszName = windowName;
1314 cs.lpszClass = className;
1315 cs.dwExStyle = exStyle;
1317 return HWND_16( WIN_CreateWindowEx( &cs, classAtom, WIN_PROC_16 ));
1321 /***********************************************************************
1322 * CreateWindowExA (USER32.@)
1324 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1325 LPCSTR windowName, DWORD style, INT x,
1326 INT y, INT width, INT height,
1327 HWND parent, HMENU menu,
1328 HINSTANCE instance, LPVOID data )
1330 ATOM classAtom;
1331 CREATESTRUCTA cs;
1332 char buffer[256];
1334 /* Find the class atom */
1336 if (HIWORD(className))
1338 if (!(classAtom = GlobalFindAtomA( className )))
1340 ERR( "bad class name %s\n", debugstr_a(className) );
1341 return 0;
1344 else
1346 classAtom = LOWORD(className);
1347 if (!GlobalGetAtomNameA( classAtom, buffer, sizeof(buffer) ))
1349 ERR( "bad atom %x\n", classAtom);
1350 return 0;
1352 className = buffer;
1355 /* Create the window */
1357 cs.lpCreateParams = data;
1358 cs.hInstance = instance;
1359 cs.hMenu = menu;
1360 cs.hwndParent = parent;
1361 cs.x = x;
1362 cs.y = y;
1363 cs.cx = width;
1364 cs.cy = height;
1365 cs.style = style;
1366 cs.lpszName = windowName;
1367 cs.lpszClass = className;
1368 cs.dwExStyle = exStyle;
1370 return WIN_CreateWindowEx( &cs, classAtom, WIN_PROC_32A );
1374 /***********************************************************************
1375 * CreateWindowExW (USER32.@)
1377 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1378 LPCWSTR windowName, DWORD style, INT x,
1379 INT y, INT width, INT height,
1380 HWND parent, HMENU menu,
1381 HINSTANCE instance, LPVOID data )
1383 ATOM classAtom;
1384 CREATESTRUCTW cs;
1385 WCHAR buffer[256];
1387 /* Find the class atom */
1389 if (HIWORD(className))
1391 if (!(classAtom = GlobalFindAtomW( className )))
1393 ERR( "bad class name %s\n", debugstr_w(className) );
1394 return 0;
1397 else
1399 classAtom = LOWORD(className);
1400 if (!GlobalGetAtomNameW( classAtom, buffer, sizeof(buffer)/sizeof(WCHAR) ))
1402 ERR( "bad atom %x\n", classAtom);
1403 return 0;
1405 className = buffer;
1408 /* Create the window */
1410 cs.lpCreateParams = data;
1411 cs.hInstance = instance;
1412 cs.hMenu = menu;
1413 cs.hwndParent = parent;
1414 cs.x = x;
1415 cs.y = y;
1416 cs.cx = width;
1417 cs.cy = height;
1418 cs.style = style;
1419 cs.lpszName = windowName;
1420 cs.lpszClass = className;
1421 cs.dwExStyle = exStyle;
1423 /* Note: we rely on the fact that CREATESTRUCTA and */
1424 /* CREATESTRUCTW have the same layout. */
1425 return WIN_CreateWindowEx( (CREATESTRUCTA *)&cs, classAtom, WIN_PROC_32W );
1429 /***********************************************************************
1430 * WIN_SendDestroyMsg
1432 static void WIN_SendDestroyMsg( HWND hwnd )
1434 GUITHREADINFO info;
1436 if (GetGUIThreadInfo( GetCurrentThreadId(), &info ))
1438 if (hwnd == info.hwndCaret) DestroyCaret();
1440 if (USER_Driver.pResetSelectionOwner)
1441 USER_Driver.pResetSelectionOwner( hwnd, TRUE );
1444 * Send the WM_DESTROY to the window.
1446 SendMessageA( hwnd, WM_DESTROY, 0, 0);
1449 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1450 * make sure that the window still exists when we come back.
1452 if (IsWindow(hwnd))
1454 HWND* pWndArray;
1455 int i;
1457 if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1459 /* start from the end (FIXME: is this needed?) */
1460 for (i = 0; pWndArray[i]; i++) ;
1462 while (--i >= 0)
1464 if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1466 HeapFree( GetProcessHeap(), 0, pWndArray );
1468 else
1469 WARN("\tdestroyed itself while in WM_DESTROY!\n");
1473 /***********************************************************************
1474 * DestroyWindow (USER32.@)
1476 BOOL WINAPI DestroyWindow( HWND hwnd )
1478 BOOL is_child;
1479 HWND h;
1481 if (!(hwnd = WIN_IsCurrentThread( hwnd )) || (hwnd == GetDesktopWindow()))
1483 SetLastError( ERROR_ACCESS_DENIED );
1484 return FALSE;
1487 TRACE("(%p)\n", hwnd);
1489 /* Look whether the focus is within the tree of windows we will
1490 * be destroying.
1492 h = GetFocus();
1493 if (h == hwnd || IsChild( hwnd, h ))
1495 HWND parent = GetAncestor( hwnd, GA_PARENT );
1496 if (parent == GetDesktopWindow()) parent = 0;
1497 SetFocus( parent );
1500 if (GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_MDICHILD)
1501 SendMessageW(GetAncestor(hwnd, GA_PARENT), WM_MDIREFRESHMENU, 0, 0);
1503 /* Call hooks */
1505 if (HOOK_CallHooks( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0, TRUE )) return FALSE;
1507 is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;
1509 if (is_child)
1511 if (!USER_IsExitingThread( GetCurrentThreadId() ))
1512 send_parent_notify( hwnd, WM_DESTROY );
1514 else if (!GetWindow( hwnd, GW_OWNER ))
1516 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
1517 /* FIXME: clean up palette - see "Internals" p.352 */
1520 if (!IsWindow(hwnd)) return TRUE;
1522 if (USER_Driver.pResetSelectionOwner)
1523 USER_Driver.pResetSelectionOwner( hwnd, FALSE ); /* before the window is unmapped */
1525 /* Hide the window */
1527 if (!ShowWindow( hwnd, SW_HIDE ))
1529 if (hwnd == GetActiveWindow()) WINPOS_ActivateOtherWindow( hwnd );
1531 if (!IsWindow(hwnd)) return TRUE;
1533 /* Recursively destroy owned windows */
1535 if (!is_child)
1537 for (;;)
1539 int i, got_one = 0;
1540 HWND *list = WIN_ListChildren( GetDesktopWindow() );
1541 if (list)
1543 for (i = 0; list[i]; i++)
1545 if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1546 if (WIN_IsCurrentThread( list[i] ))
1548 DestroyWindow( list[i] );
1549 got_one = 1;
1550 continue;
1552 WIN_SetOwner( list[i], 0 );
1554 HeapFree( GetProcessHeap(), 0, list );
1556 if (!got_one) break;
1560 /* Send destroy messages */
1562 WIN_SendDestroyMsg( hwnd );
1563 if (!IsWindow( hwnd )) return TRUE;
1565 if (GetClipboardOwner() == hwnd)
1566 CLIPBOARD_ReleaseOwner();
1568 /* Unlink now so we won't bother with the children later on */
1570 WIN_UnlinkWindow( hwnd );
1572 /* Destroy the window storage */
1574 WIN_DestroyWindow( hwnd );
1575 return TRUE;
1579 /***********************************************************************
1580 * CloseWindow (USER32.@)
1582 BOOL WINAPI CloseWindow( HWND hwnd )
1584 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1585 ShowWindow( hwnd, SW_MINIMIZE );
1586 return TRUE;
1590 /***********************************************************************
1591 * OpenIcon (USER32.@)
1593 BOOL WINAPI OpenIcon( HWND hwnd )
1595 if (!IsIconic( hwnd )) return FALSE;
1596 ShowWindow( hwnd, SW_SHOWNORMAL );
1597 return TRUE;
1601 /***********************************************************************
1602 * WIN_FindWindow
1604 * Implementation of FindWindow() and FindWindowEx().
1606 static HWND WIN_FindWindow( HWND parent, HWND child, ATOM className, LPCWSTR title )
1608 HWND *list = NULL;
1609 HWND retvalue = 0;
1610 int i = 0, len = 0;
1611 WCHAR *buffer = NULL;
1613 if (!parent) parent = GetDesktopWindow();
1614 if (title)
1616 len = strlenW(title) + 1; /* one extra char to check for chars beyond the end */
1617 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1620 if (!(list = list_window_children( parent, className, 0 ))) goto done;
1622 if (child)
1624 child = WIN_GetFullHandle( child );
1625 while (list[i] && list[i] != child) i++;
1626 if (!list[i]) goto done;
1627 i++; /* start from next window */
1630 if (title)
1632 while (list[i])
1634 if (GetWindowTextW( list[i], buffer, len + 1 ) && !strcmpiW( buffer, title )) break;
1635 i++;
1638 retvalue = list[i];
1640 done:
1641 if (list) HeapFree( GetProcessHeap(), 0, list );
1642 if (buffer) HeapFree( GetProcessHeap(), 0, buffer );
1643 return retvalue;
1648 /***********************************************************************
1649 * FindWindowA (USER32.@)
1651 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1653 HWND ret = FindWindowExA( 0, 0, className, title );
1654 if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1655 return ret;
1659 /***********************************************************************
1660 * FindWindowExA (USER32.@)
1662 HWND WINAPI FindWindowExA( HWND parent, HWND child,
1663 LPCSTR className, LPCSTR title )
1665 ATOM atom = 0;
1666 LPWSTR buffer;
1667 HWND hwnd;
1668 INT len;
1670 if (className)
1672 /* If the atom doesn't exist, then no class */
1673 /* with this name exists either. */
1674 if (!(atom = GlobalFindAtomA( className )))
1676 SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1677 return 0;
1680 if (!title) return WIN_FindWindow( parent, child, atom, NULL );
1682 len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
1683 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
1684 MultiByteToWideChar( CP_ACP, 0, title, -1, buffer, len );
1685 hwnd = WIN_FindWindow( parent, child, atom, buffer );
1686 HeapFree( GetProcessHeap(), 0, buffer );
1687 return hwnd;
1691 /***********************************************************************
1692 * FindWindowExW (USER32.@)
1694 HWND WINAPI FindWindowExW( HWND parent, HWND child,
1695 LPCWSTR className, LPCWSTR title )
1697 ATOM atom = 0;
1699 if (className)
1701 /* If the atom doesn't exist, then no class */
1702 /* with this name exists either. */
1703 if (!(atom = GlobalFindAtomW( className )))
1705 SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1706 return 0;
1709 return WIN_FindWindow( parent, child, atom, title );
1713 /***********************************************************************
1714 * FindWindowW (USER32.@)
1716 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
1718 return FindWindowExW( 0, 0, className, title );
1722 /**********************************************************************
1723 * GetDesktopWindow (USER32.@)
1725 HWND WINAPI GetDesktopWindow(void)
1727 if (pWndDesktop) return pWndDesktop->hwndSelf;
1728 ERR( "Wine init error: either you're trying to use an invalid native USER.EXE config, or some graphics/GUI libraries or DLLs didn't initialize properly. Aborting.\n" );
1729 ExitProcess(1);
1730 return 0;
1734 /*******************************************************************
1735 * EnableWindow (USER32.@)
1737 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
1739 WND *wndPtr;
1740 BOOL retvalue;
1741 LONG style;
1742 HWND full_handle;
1744 if (is_broadcast(hwnd))
1746 SetLastError( ERROR_INVALID_PARAMETER );
1747 return FALSE;
1750 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
1751 return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
1753 hwnd = full_handle;
1755 TRACE("( %p, %d )\n", hwnd, enable);
1757 if (!(wndPtr = WIN_GetPtr( hwnd ))) return FALSE;
1758 style = wndPtr->dwStyle;
1759 retvalue = ((style & WS_DISABLED) != 0);
1760 WIN_ReleasePtr( wndPtr );
1762 if (enable && retvalue)
1764 WIN_SetStyle( hwnd, style & ~WS_DISABLED );
1765 SendMessageA( hwnd, WM_ENABLE, TRUE, 0 );
1767 else if (!enable && !retvalue)
1769 HWND focus_wnd, capture_wnd;
1771 SendMessageA( hwnd, WM_CANCELMODE, 0, 0);
1773 WIN_SetStyle( hwnd, style | WS_DISABLED );
1775 focus_wnd = GetFocus();
1776 if (hwnd == focus_wnd || IsChild(hwnd, focus_wnd))
1777 SetFocus( 0 ); /* A disabled window can't have the focus */
1779 capture_wnd = GetCapture();
1780 if (hwnd == capture_wnd || IsChild(hwnd, capture_wnd))
1781 ReleaseCapture(); /* A disabled window can't capture the mouse */
1783 SendMessageA( hwnd, WM_ENABLE, FALSE, 0 );
1785 return retvalue;
1789 /***********************************************************************
1790 * IsWindowEnabled (USER32.@)
1792 BOOL WINAPI IsWindowEnabled(HWND hWnd)
1794 return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
1798 /***********************************************************************
1799 * IsWindowUnicode (USER32.@)
1801 BOOL WINAPI IsWindowUnicode( HWND hwnd )
1803 WND * wndPtr;
1804 BOOL retvalue;
1806 if (!(wndPtr = WIN_FindWndPtr(hwnd))) return FALSE;
1807 retvalue = (WINPROC_GetProcType( wndPtr->winproc ) == WIN_PROC_32W);
1808 WIN_ReleaseWndPtr(wndPtr);
1809 return retvalue;
1813 /**********************************************************************
1814 * GetWindowWord (USER32.@)
1816 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
1818 if (offset >= 0)
1820 WORD retvalue = 0;
1821 WND *wndPtr = WIN_GetPtr( hwnd );
1822 if (!wndPtr)
1824 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1825 return 0;
1827 if (wndPtr == WND_OTHER_PROCESS)
1829 SERVER_START_REQ( set_window_info )
1831 req->handle = hwnd;
1832 req->flags = 0; /* don't set anything, just retrieve */
1833 req->extra_offset = offset;
1834 req->extra_size = sizeof(retvalue);
1835 if (!wine_server_call_err( req ))
1836 memcpy( &retvalue, &reply->old_extra_value, sizeof(retvalue) );
1838 SERVER_END_REQ;
1839 return retvalue;
1841 if (offset > (int)(wndPtr->cbWndExtra - sizeof(WORD)))
1843 WARN("Invalid offset %d\n", offset );
1844 SetLastError( ERROR_INVALID_INDEX );
1846 else memcpy( &retvalue, (char *)wndPtr->wExtra + offset, sizeof(retvalue) );
1847 WIN_ReleasePtr( wndPtr );
1848 return retvalue;
1851 switch(offset)
1853 case GWL_HWNDPARENT:
1854 return GetWindowLongW( hwnd, offset );
1855 case GWL_ID:
1856 case GWL_HINSTANCE:
1858 LONG ret = GetWindowLongW( hwnd, offset );
1859 if (HIWORD(ret))
1860 WARN("%d: discards high bits of 0x%08lx!\n", offset, ret );
1861 return LOWORD(ret);
1863 default:
1864 WARN("Invalid offset %d\n", offset );
1865 return 0;
1870 /**********************************************************************
1871 * SetWindowWord (USER32.@)
1873 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
1875 WORD retval = 0;
1876 WND * wndPtr;
1878 switch(offset)
1880 case GWL_ID:
1881 case GWL_HINSTANCE:
1882 case GWL_HWNDPARENT:
1883 return SetWindowLongW( hwnd, offset, (UINT)newval );
1884 default:
1885 if (offset < 0)
1887 WARN("Invalid offset %d\n", offset );
1888 SetLastError( ERROR_INVALID_INDEX );
1889 return 0;
1893 wndPtr = WIN_GetPtr( hwnd );
1894 if (wndPtr == WND_OTHER_PROCESS)
1896 if (IsWindow(hwnd))
1897 FIXME( "set %d <- %x not supported yet on other process window %p\n",
1898 offset, newval, hwnd );
1899 wndPtr = NULL;
1901 if (!wndPtr)
1903 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1904 return 0;
1907 if (offset > (int)(wndPtr->cbWndExtra - sizeof(WORD)))
1909 WARN("Invalid offset %d\n", offset );
1910 WIN_ReleasePtr(wndPtr);
1911 SetLastError( ERROR_INVALID_INDEX );
1912 return 0;
1915 SERVER_START_REQ( set_window_info )
1917 req->handle = hwnd;
1918 req->flags = SET_WIN_EXTRA;
1919 req->extra_offset = offset;
1920 req->extra_size = sizeof(newval);
1921 memcpy( &req->extra_value, &newval, sizeof(newval) );
1922 if (!wine_server_call_err( req ))
1924 void *ptr = (char *)wndPtr->wExtra + offset;
1925 memcpy( &retval, ptr, sizeof(retval) );
1926 memcpy( ptr, &newval, sizeof(newval) );
1929 SERVER_END_REQ;
1930 WIN_ReleasePtr( wndPtr );
1931 return retval;
1935 /**********************************************************************
1936 * WIN_GetWindowLong
1938 * Helper function for GetWindowLong().
1940 static LONG WIN_GetWindowLong( HWND hwnd, INT offset, WINDOWPROCTYPE type )
1942 LONG retvalue = 0;
1943 WND *wndPtr;
1945 if (offset == GWL_HWNDPARENT)
1947 HWND parent = GetAncestor( hwnd, GA_PARENT );
1948 if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
1949 return (LONG)parent;
1952 if (!(wndPtr = WIN_GetPtr( hwnd )))
1954 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1955 return 0;
1958 if (wndPtr == WND_OTHER_PROCESS)
1960 if (offset == GWL_WNDPROC)
1962 SetLastError( ERROR_ACCESS_DENIED );
1963 return 0;
1965 SERVER_START_REQ( set_window_info )
1967 req->handle = hwnd;
1968 req->flags = 0; /* don't set anything, just retrieve */
1969 req->extra_offset = (offset >= 0) ? offset : -1;
1970 req->extra_size = (offset >= 0) ? sizeof(retvalue) : 0;
1971 if (!wine_server_call_err( req ))
1973 switch(offset)
1975 case GWL_STYLE: retvalue = reply->old_style; break;
1976 case GWL_EXSTYLE: retvalue = reply->old_ex_style; break;
1977 case GWL_ID: retvalue = reply->old_id; break;
1978 case GWL_HINSTANCE: retvalue = (ULONG_PTR)reply->old_instance; break;
1979 case GWL_USERDATA: retvalue = (ULONG_PTR)reply->old_user_data; break;
1980 default:
1981 if (offset >= 0) retvalue = reply->old_extra_value;
1982 else SetLastError( ERROR_INVALID_INDEX );
1983 break;
1987 SERVER_END_REQ;
1988 return retvalue;
1991 /* now we have a valid wndPtr */
1993 if (offset >= 0)
1995 if (offset > (int)(wndPtr->cbWndExtra - sizeof(LONG)))
1998 * Some programs try to access last element from 16 bit
1999 * code using illegal offset value. Hopefully this is
2000 * what those programs really expect.
2002 if (type == WIN_PROC_16 &&
2003 wndPtr->cbWndExtra >= 4 &&
2004 offset == wndPtr->cbWndExtra - sizeof(WORD))
2006 INT offset2 = wndPtr->cbWndExtra - sizeof(LONG);
2008 ERR( "- replaced invalid offset %d with %d\n",
2009 offset, offset2 );
2011 retvalue = *(LONG *)(((char *)wndPtr->wExtra) + offset2);
2012 WIN_ReleasePtr( wndPtr );
2013 return retvalue;
2015 WARN("Invalid offset %d\n", offset );
2016 WIN_ReleasePtr( wndPtr );
2017 SetLastError( ERROR_INVALID_INDEX );
2018 return 0;
2020 retvalue = *(LONG *)(((char *)wndPtr->wExtra) + offset);
2021 /* Special case for dialog window procedure */
2022 if ((offset == DWL_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
2023 retvalue = (LONG)WINPROC_GetProc( (WNDPROC)retvalue, type );
2024 WIN_ReleasePtr( wndPtr );
2025 return retvalue;
2028 switch(offset)
2030 case GWL_USERDATA: retvalue = wndPtr->userdata; break;
2031 case GWL_STYLE: retvalue = wndPtr->dwStyle; break;
2032 case GWL_EXSTYLE: retvalue = wndPtr->dwExStyle; break;
2033 case GWL_ID: retvalue = (LONG)wndPtr->wIDmenu; break;
2034 case GWL_WNDPROC: retvalue = (LONG)WINPROC_GetProc( wndPtr->winproc, type ); break;
2035 case GWL_HINSTANCE: retvalue = (LONG)wndPtr->hInstance; break;
2036 default:
2037 WARN("Unknown offset %d\n", offset );
2038 SetLastError( ERROR_INVALID_INDEX );
2039 break;
2041 WIN_ReleasePtr(wndPtr);
2042 return retvalue;
2046 /**********************************************************************
2047 * WIN_SetWindowLong
2049 * Helper function for SetWindowLong().
2051 * 0 is the failure code. However, in the case of failure SetLastError
2052 * must be set to distinguish between a 0 return value and a failure.
2054 static LONG WIN_SetWindowLong( HWND hwnd, INT offset, LONG newval,
2055 WINDOWPROCTYPE type )
2057 STYLESTRUCT style;
2058 BOOL ok;
2059 LONG retval = 0;
2060 WND *wndPtr;
2062 TRACE( "%p %d %lx %x\n", hwnd, offset, newval, type );
2064 if (is_broadcast(hwnd))
2066 SetLastError( ERROR_INVALID_PARAMETER );
2067 return FALSE;
2069 if (!WIN_IsCurrentProcess( hwnd ))
2071 if (offset == GWL_WNDPROC)
2073 SetLastError( ERROR_ACCESS_DENIED );
2074 return 0;
2076 return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, offset, newval );
2079 wndPtr = WIN_GetPtr( hwnd );
2080 if (wndPtr->hwndSelf == GetDesktopWindow())
2082 /* can't change anything on the desktop window */
2083 WIN_ReleasePtr( wndPtr );
2084 SetLastError( ERROR_ACCESS_DENIED );
2085 return 0;
2088 /* first some special cases */
2089 switch( offset )
2091 case GWL_STYLE:
2092 case GWL_EXSTYLE:
2093 style.styleOld =
2094 offset == GWL_STYLE ? wndPtr->dwStyle : wndPtr->dwExStyle;
2095 style.styleNew = newval;
2096 WIN_ReleasePtr( wndPtr );
2097 SendMessageW( hwnd, WM_STYLECHANGING, offset, (LPARAM)&style );
2098 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2099 newval = style.styleNew;
2100 break;
2101 case GWL_HWNDPARENT:
2102 if (wndPtr->parent == GetDesktopWindow())
2104 WIN_ReleasePtr( wndPtr );
2105 return (LONG)WIN_SetOwner( hwnd, (HWND)newval );
2107 else
2109 WIN_ReleasePtr( wndPtr );
2110 return (LONG)SetParent( hwnd, (HWND)newval );
2112 case GWL_WNDPROC:
2113 retval = (LONG)WINPROC_GetProc( wndPtr->winproc, type );
2114 WINPROC_SetProc( &wndPtr->winproc, (WNDPROC)newval, type, WIN_PROC_WINDOW );
2115 WIN_ReleasePtr( wndPtr );
2116 return retval;
2117 case GWL_ID:
2118 case GWL_HINSTANCE:
2119 case GWL_USERDATA:
2120 break;
2121 case DWL_DLGPROC:
2122 if ((wndPtr->cbWndExtra + sizeof(LONG) >= DWL_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
2124 WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWL_DLGPROC);
2125 retval = (LONG)WINPROC_GetProc( *ptr, type );
2126 WINPROC_SetProc( ptr, (WNDPROC)newval, type, WIN_PROC_WINDOW );
2127 WIN_ReleasePtr( wndPtr );
2128 return retval;
2130 /* fall through */
2131 default:
2132 if (offset < 0 || offset > (int)(wndPtr->cbWndExtra - sizeof(LONG)))
2134 WARN("Invalid offset %d\n", offset );
2135 WIN_ReleasePtr( wndPtr );
2136 SetLastError( ERROR_INVALID_INDEX );
2137 return 0;
2139 else
2141 LONG *ptr = (LONG *)((char *)wndPtr->wExtra + offset);
2142 if (*ptr == newval) /* already set to the same value */
2144 WIN_ReleasePtr( wndPtr );
2145 return newval;
2148 break;
2151 SERVER_START_REQ( set_window_info )
2153 req->handle = hwnd;
2154 req->extra_offset = -1;
2155 switch(offset)
2157 case GWL_STYLE:
2158 req->flags = SET_WIN_STYLE;
2159 req->style = newval;
2160 break;
2161 case GWL_EXSTYLE:
2162 req->flags = SET_WIN_EXSTYLE;
2163 req->ex_style = newval;
2164 break;
2165 case GWL_ID:
2166 req->flags = SET_WIN_ID;
2167 req->id = newval;
2168 break;
2169 case GWL_HINSTANCE:
2170 req->flags = SET_WIN_INSTANCE;
2171 req->instance = (void *)newval;
2172 break;
2173 case GWL_USERDATA:
2174 req->flags = SET_WIN_USERDATA;
2175 req->user_data = (void *)newval;
2176 break;
2177 default:
2178 req->flags = SET_WIN_EXTRA;
2179 req->extra_offset = offset;
2180 req->extra_size = sizeof(newval);
2181 memcpy( &req->extra_value, &newval, sizeof(newval) );
2183 if ((ok = !wine_server_call_err( req )))
2185 switch(offset)
2187 case GWL_STYLE:
2188 wndPtr->dwStyle = newval;
2189 retval = reply->old_style;
2190 break;
2191 case GWL_EXSTYLE:
2192 wndPtr->dwExStyle = newval;
2193 retval = reply->old_ex_style;
2194 break;
2195 case GWL_ID:
2196 wndPtr->wIDmenu = newval;
2197 retval = reply->old_id;
2198 break;
2199 case GWL_HINSTANCE:
2200 wndPtr->hInstance = (HINSTANCE)newval;
2201 retval = (ULONG_PTR)reply->old_instance;
2202 break;
2203 case GWL_USERDATA:
2204 wndPtr->userdata = newval;
2205 retval = (ULONG_PTR)reply->old_user_data;
2206 break;
2207 default:
2209 void *ptr = (char *)wndPtr->wExtra + offset;
2210 memcpy( &retval, ptr, sizeof(retval) );
2211 memcpy( ptr, &newval, sizeof(newval) );
2213 break;
2217 SERVER_END_REQ;
2218 WIN_ReleasePtr( wndPtr );
2220 if (!ok) return 0;
2222 if (offset == GWL_STYLE && USER_Driver.pSetWindowStyle)
2223 USER_Driver.pSetWindowStyle( hwnd, retval );
2225 if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2226 SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2228 return retval;
2232 /**********************************************************************
2233 * GetWindowLong (USER.135)
2235 LONG WINAPI GetWindowLong16( HWND16 hwnd, INT16 offset )
2237 return WIN_GetWindowLong( WIN_Handle32(hwnd), offset, WIN_PROC_16 );
2241 /**********************************************************************
2242 * GetWindowLongA (USER32.@)
2244 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2246 return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32A );
2250 /**********************************************************************
2251 * GetWindowLongW (USER32.@)
2253 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2255 return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32W );
2259 /**********************************************************************
2260 * SetWindowLong (USER.136)
2262 LONG WINAPI SetWindowLong16( HWND16 hwnd, INT16 offset, LONG newval )
2264 return WIN_SetWindowLong( WIN_Handle32(hwnd), offset, newval, WIN_PROC_16 );
2268 /**********************************************************************
2269 * SetWindowLongA (USER32.@)
2271 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2273 return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32A );
2277 /**********************************************************************
2278 * SetWindowLongW (USER32.@) Set window attribute
2280 * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2281 * value in a window's extra memory.
2283 * The _hwnd_ parameter specifies the window. is the handle to a
2284 * window that has extra memory. The _newval_ parameter contains the
2285 * new attribute or extra memory value. If positive, the _offset_
2286 * parameter is the byte-addressed location in the window's extra
2287 * memory to set. If negative, _offset_ specifies the window
2288 * attribute to set, and should be one of the following values:
2290 * GWL_EXSTYLE The window's extended window style
2292 * GWL_STYLE The window's window style.
2294 * GWL_WNDPROC Pointer to the window's window procedure.
2296 * GWL_HINSTANCE The window's pplication instance handle.
2298 * GWL_ID The window's identifier.
2300 * GWL_USERDATA The window's user-specified data.
2302 * If the window is a dialog box, the _offset_ parameter can be one of
2303 * the following values:
2305 * DWL_DLGPROC The address of the window's dialog box procedure.
2307 * DWL_MSGRESULT The return value of a message
2308 * that the dialog box procedure processed.
2310 * DWL_USER Application specific information.
2312 * RETURNS
2314 * If successful, returns the previous value located at _offset_. Otherwise,
2315 * returns 0.
2317 * NOTES
2319 * Extra memory for a window class is specified by a nonzero cbWndExtra
2320 * parameter of the WNDCLASS structure passed to RegisterClass() at the
2321 * time of class creation.
2323 * Using GWL_WNDPROC to set a new window procedure effectively creates
2324 * a window subclass. Use CallWindowProc() in the new windows procedure
2325 * to pass messages to the superclass's window procedure.
2327 * The user data is reserved for use by the application which created
2328 * the window.
2330 * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2331 * instead, call the EnableWindow() function to change the window's
2332 * disabled state.
2334 * Do not use GWL_HWNDPARENT to reset the window's parent, use
2335 * SetParent() instead.
2337 * Win95:
2338 * When offset is GWL_STYLE and the calling app's ver is 4.0,
2339 * it sends WM_STYLECHANGING before changing the settings
2340 * and WM_STYLECHANGED afterwards.
2341 * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2343 LONG WINAPI SetWindowLongW(
2344 HWND hwnd, /* [in] window to alter */
2345 INT offset, /* [in] offset, in bytes, of location to alter */
2346 LONG newval /* [in] new value of location */
2348 return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32W );
2352 /*******************************************************************
2353 * GetWindowTextA (USER32.@)
2355 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2357 WCHAR *buffer;
2359 if (WIN_IsCurrentProcess( hwnd ))
2360 return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2362 /* when window belongs to other process, don't send a message */
2363 if (nMaxCount <= 0) return 0;
2364 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2365 get_server_window_text( hwnd, buffer, nMaxCount );
2366 if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2367 lpString[nMaxCount-1] = 0;
2368 HeapFree( GetProcessHeap(), 0, buffer );
2369 return strlen(lpString);
2373 /*******************************************************************
2374 * InternalGetWindowText (USER32.@)
2376 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2378 WND *win;
2380 if (nMaxCount <= 0) return 0;
2381 if (!(win = WIN_GetPtr( hwnd ))) return 0;
2382 if (win != WND_OTHER_PROCESS)
2384 if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2385 else lpString[0] = 0;
2386 WIN_ReleasePtr( win );
2388 else
2390 get_server_window_text( hwnd, lpString, nMaxCount );
2392 return strlenW(lpString);
2396 /*******************************************************************
2397 * GetWindowTextW (USER32.@)
2399 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2401 if (WIN_IsCurrentProcess( hwnd ))
2402 return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2404 /* when window belongs to other process, don't send a message */
2405 if (nMaxCount <= 0) return 0;
2406 get_server_window_text( hwnd, lpString, nMaxCount );
2407 return strlenW(lpString);
2411 /*******************************************************************
2412 * SetWindowText (USER32.@)
2413 * SetWindowTextA (USER32.@)
2415 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2417 if (is_broadcast(hwnd))
2419 SetLastError( ERROR_INVALID_PARAMETER );
2420 return FALSE;
2422 if (!WIN_IsCurrentProcess( hwnd ))
2424 FIXME( "cannot set text %s of other process window %p\n", debugstr_a(lpString), hwnd );
2425 SetLastError( ERROR_ACCESS_DENIED );
2426 return FALSE;
2428 return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2432 /*******************************************************************
2433 * SetWindowTextW (USER32.@)
2435 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2437 if (is_broadcast(hwnd))
2439 SetLastError( ERROR_INVALID_PARAMETER );
2440 return FALSE;
2442 if (!WIN_IsCurrentProcess( hwnd ))
2444 FIXME( "cannot set text %s of other process window %p\n", debugstr_w(lpString), hwnd );
2445 SetLastError( ERROR_ACCESS_DENIED );
2446 return FALSE;
2448 return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2452 /*******************************************************************
2453 * GetWindowTextLengthA (USER32.@)
2455 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2457 return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2460 /*******************************************************************
2461 * GetWindowTextLengthW (USER32.@)
2463 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2465 return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2469 /*******************************************************************
2470 * IsWindow (USER32.@)
2472 BOOL WINAPI IsWindow( HWND hwnd )
2474 WND *ptr;
2475 BOOL ret;
2477 if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2479 if (ptr != WND_OTHER_PROCESS)
2481 WIN_ReleasePtr( ptr );
2482 return TRUE;
2485 /* check other processes */
2486 SERVER_START_REQ( get_window_info )
2488 req->handle = hwnd;
2489 ret = !wine_server_call_err( req );
2491 SERVER_END_REQ;
2492 return ret;
2496 /***********************************************************************
2497 * GetWindowThreadProcessId (USER32.@)
2499 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2501 WND *ptr;
2502 DWORD tid = 0;
2504 if (!(ptr = WIN_GetPtr( hwnd )))
2506 SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2507 return 0;
2510 if (ptr != WND_OTHER_PROCESS)
2512 /* got a valid window */
2513 tid = ptr->tid;
2514 if (process) *process = GetCurrentProcessId();
2515 WIN_ReleasePtr( ptr );
2516 return tid;
2519 /* check other processes */
2520 SERVER_START_REQ( get_window_info )
2522 req->handle = hwnd;
2523 if (!wine_server_call_err( req ))
2525 tid = (DWORD)reply->tid;
2526 if (process) *process = (DWORD)reply->pid;
2529 SERVER_END_REQ;
2530 return tid;
2534 /*****************************************************************
2535 * GetParent (USER32.@)
2537 HWND WINAPI GetParent( HWND hwnd )
2539 WND *wndPtr;
2540 HWND retvalue = 0;
2542 if (!(wndPtr = WIN_GetPtr( hwnd )))
2544 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2545 return 0;
2547 if (wndPtr == WND_OTHER_PROCESS)
2549 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2550 if (style & (WS_POPUP | WS_CHILD))
2552 SERVER_START_REQ( get_window_tree )
2554 req->handle = hwnd;
2555 if (!wine_server_call_err( req ))
2557 if (style & WS_POPUP) retvalue = reply->owner;
2558 else if (style & WS_CHILD) retvalue = reply->parent;
2561 SERVER_END_REQ;
2564 else
2566 if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2567 else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2568 WIN_ReleasePtr( wndPtr );
2570 return retvalue;
2574 /*****************************************************************
2575 * GetAncestor (USER32.@)
2577 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2579 WND *win;
2580 HWND *list, ret = 0;
2582 switch(type)
2584 case GA_PARENT:
2585 if (!(win = WIN_GetPtr( hwnd )))
2587 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2588 return 0;
2590 if (win != WND_OTHER_PROCESS)
2592 ret = win->parent;
2593 WIN_ReleasePtr( win );
2595 else /* need to query the server */
2597 SERVER_START_REQ( get_window_tree )
2599 req->handle = hwnd;
2600 if (!wine_server_call_err( req )) ret = reply->parent;
2602 SERVER_END_REQ;
2604 break;
2606 case GA_ROOT:
2607 if (!(list = WIN_ListParents( hwnd ))) return 0;
2609 if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd ); /* top-level window */
2610 else
2612 int count = 2;
2613 while (list[count]) count++;
2614 ret = list[count - 2]; /* get the one before the desktop */
2616 HeapFree( GetProcessHeap(), 0, list );
2617 break;
2619 case GA_ROOTOWNER:
2620 if ((ret = WIN_GetFullHandle( hwnd )) == GetDesktopWindow()) return 0;
2621 for (;;)
2623 HWND parent = GetParent( ret );
2624 if (!parent) break;
2625 ret = parent;
2627 break;
2629 return ret;
2633 /*****************************************************************
2634 * SetParent (USER32.@)
2636 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2638 WND *wndPtr;
2639 HWND retvalue, full_handle;
2640 BOOL was_visible;
2642 if (is_broadcast(hwnd) || is_broadcast(parent))
2644 SetLastError(ERROR_INVALID_PARAMETER);
2645 return 0;
2648 if (!parent) parent = GetDesktopWindow();
2649 else parent = WIN_GetFullHandle( parent );
2651 if (!IsWindow( parent ))
2653 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2654 return 0;
2657 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2658 return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2660 hwnd = full_handle;
2662 if (USER_Driver.pSetParent)
2663 return USER_Driver.pSetParent( hwnd, parent );
2665 /* Windows hides the window first, then shows it again
2666 * including the WM_SHOWWINDOW messages and all */
2667 was_visible = ShowWindow( hwnd, SW_HIDE );
2669 if (!IsWindow( parent )) return 0;
2670 if (!(wndPtr = WIN_GetPtr(hwnd)) || wndPtr == WND_OTHER_PROCESS) return 0;
2672 retvalue = wndPtr->parent; /* old parent */
2673 if (parent != retvalue)
2675 WIN_LinkWindow( hwnd, parent, HWND_TOP );
2677 if (parent != GetDesktopWindow()) /* a child window */
2679 if (!(wndPtr->dwStyle & WS_CHILD))
2681 HMENU menu = (HMENU)SetWindowLongW( hwnd, GWL_ID, 0 );
2682 if (menu) DestroyMenu( menu );
2686 WIN_ReleasePtr( wndPtr );
2688 /* SetParent additionally needs to make hwnd the topmost window
2689 in the x-order and send the expected WM_WINDOWPOSCHANGING and
2690 WM_WINDOWPOSCHANGED notification messages.
2692 SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0,
2693 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | (was_visible ? SWP_SHOWWINDOW : 0) );
2694 /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
2695 * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
2696 return retvalue;
2700 /*******************************************************************
2701 * IsChild (USER32.@)
2703 BOOL WINAPI IsChild( HWND parent, HWND child )
2705 HWND *list = WIN_ListParents( child );
2706 int i;
2707 BOOL ret;
2709 if (!list) return FALSE;
2710 parent = WIN_GetFullHandle( parent );
2711 for (i = 0; list[i]; i++) if (list[i] == parent) break;
2712 ret = (list[i] != 0);
2713 HeapFree( GetProcessHeap(), 0, list );
2714 return ret;
2718 /***********************************************************************
2719 * IsWindowVisible (USER32.@)
2721 BOOL WINAPI IsWindowVisible( HWND hwnd )
2723 HWND *list;
2724 BOOL retval;
2725 int i;
2727 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2728 if (!(list = WIN_ListParents( hwnd ))) return TRUE;
2729 for (i = 0; list[i]; i++)
2730 if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2731 retval = !list[i];
2732 HeapFree( GetProcessHeap(), 0, list );
2733 return retval;
2737 /***********************************************************************
2738 * WIN_IsWindowDrawable
2740 * hwnd is drawable when it is visible, all parents are not
2741 * minimized, and it is itself not minimized unless we are
2742 * trying to draw its default class icon.
2744 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2746 HWND *list;
2747 BOOL retval;
2748 int i;
2749 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2751 if (!(style & WS_VISIBLE)) return FALSE;
2752 if ((style & WS_MINIMIZE) && icon && GetClassLongA( hwnd, GCL_HICON )) return FALSE;
2754 if (!(list = WIN_ListParents( hwnd ))) return TRUE;
2755 for (i = 0; list[i]; i++)
2756 if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2757 break;
2758 retval = !list[i];
2759 HeapFree( GetProcessHeap(), 0, list );
2760 return retval;
2764 /*******************************************************************
2765 * GetTopWindow (USER32.@)
2767 HWND WINAPI GetTopWindow( HWND hwnd )
2769 if (!hwnd) hwnd = GetDesktopWindow();
2770 return GetWindow( hwnd, GW_CHILD );
2774 /*******************************************************************
2775 * GetWindow (USER32.@)
2777 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2779 HWND retval = 0;
2781 if (rel == GW_OWNER) /* this one may be available locally */
2783 WND *wndPtr = WIN_GetPtr( hwnd );
2784 if (!wndPtr)
2786 SetLastError( ERROR_INVALID_HANDLE );
2787 return 0;
2789 if (wndPtr != WND_OTHER_PROCESS)
2791 retval = wndPtr->owner;
2792 WIN_ReleasePtr( wndPtr );
2793 return retval;
2795 /* else fall through to server call */
2798 SERVER_START_REQ( get_window_tree )
2800 req->handle = hwnd;
2801 if (!wine_server_call_err( req ))
2803 switch(rel)
2805 case GW_HWNDFIRST:
2806 retval = reply->first_sibling;
2807 break;
2808 case GW_HWNDLAST:
2809 retval = reply->last_sibling;
2810 break;
2811 case GW_HWNDNEXT:
2812 retval = reply->next_sibling;
2813 break;
2814 case GW_HWNDPREV:
2815 retval = reply->prev_sibling;
2816 break;
2817 case GW_OWNER:
2818 retval = reply->owner;
2819 break;
2820 case GW_CHILD:
2821 retval = reply->first_child;
2822 break;
2826 SERVER_END_REQ;
2827 return retval;
2831 /***********************************************************************
2832 * WIN_InternalShowOwnedPopups
2834 * Internal version of ShowOwnedPopups; Wine functions should use this
2835 * to avoid interfering with application calls to ShowOwnedPopups
2836 * and to make sure the application can't prevent showing/hiding.
2838 * Set unmanagedOnly to TRUE to show/hide unmanaged windows only.
2842 BOOL WIN_InternalShowOwnedPopups( HWND owner, BOOL fShow, BOOL unmanagedOnly )
2844 int count = 0;
2845 WND *pWnd;
2846 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2848 if (!win_array) return TRUE;
2851 * Show windows Lowest first, Highest last to preserve Z-Order
2853 while (win_array[count]) count++;
2854 while (--count >= 0)
2856 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2857 if (!(pWnd = WIN_FindWndPtr( win_array[count] ))) continue;
2859 if (pWnd->dwStyle & WS_POPUP)
2861 if (fShow)
2863 /* check in window was flagged for showing in previous WIN_InternalShowOwnedPopups call */
2864 if (pWnd->flags & WIN_NEEDS_INTERNALSOP)
2867 * Call ShowWindow directly because an application can intercept WM_SHOWWINDOW messages
2869 ShowWindow(pWnd->hwndSelf,SW_SHOW);
2870 pWnd->flags &= ~WIN_NEEDS_INTERNALSOP; /* remove the flag */
2873 else
2875 if ( IsWindowVisible(pWnd->hwndSelf) && /* hide only if window is visible */
2876 !( pWnd->flags & WIN_NEEDS_INTERNALSOP ) && /* don't hide if previous call already did it */
2877 !( unmanagedOnly && (pWnd->dwExStyle & WS_EX_MANAGED) ) ) /* don't hide managed windows if unmanagedOnly is TRUE */
2880 * Call ShowWindow directly because an application can intercept WM_SHOWWINDOW messages
2882 ShowWindow(pWnd->hwndSelf,SW_HIDE);
2883 /* flag the window for showing on next WIN_InternalShowOwnedPopups call */
2884 pWnd->flags |= WIN_NEEDS_INTERNALSOP;
2888 WIN_ReleaseWndPtr( pWnd );
2890 HeapFree( GetProcessHeap(), 0, win_array );
2892 return TRUE;
2895 /*******************************************************************
2896 * ShowOwnedPopups (USER32.@)
2898 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2900 int count = 0;
2901 WND *pWnd;
2902 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2904 if (!win_array) return TRUE;
2906 while (win_array[count]) count++;
2907 while (--count >= 0)
2909 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2910 if (!(pWnd = WIN_FindWndPtr( win_array[count] ))) continue;
2912 if (pWnd->dwStyle & WS_POPUP)
2914 if (fShow)
2916 if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2918 /* In Windows, ShowOwnedPopups(TRUE) generates
2919 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
2920 * regardless of the state of the owner
2922 SendMessageA(pWnd->hwndSelf, WM_SHOWWINDOW, SW_SHOW, SW_PARENTOPENING);
2923 pWnd->flags &= ~WIN_NEEDS_SHOW_OWNEDPOPUP;
2926 else
2928 if (IsWindowVisible(pWnd->hwndSelf))
2930 /* In Windows, ShowOwnedPopups(FALSE) generates
2931 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
2932 * regardless of the state of the owner
2934 SendMessageA(pWnd->hwndSelf, WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
2935 pWnd->flags |= WIN_NEEDS_SHOW_OWNEDPOPUP;
2939 WIN_ReleaseWndPtr( pWnd );
2941 HeapFree( GetProcessHeap(), 0, win_array );
2942 return TRUE;
2946 /*******************************************************************
2947 * GetLastActivePopup (USER32.@)
2949 HWND WINAPI GetLastActivePopup( HWND hwnd )
2951 HWND retval = hwnd;
2953 SERVER_START_REQ( get_window_info )
2955 req->handle = hwnd;
2956 if (!wine_server_call_err( req )) retval = reply->last_active;
2958 SERVER_END_REQ;
2959 return retval;
2963 /*******************************************************************
2964 * WIN_ListParents
2966 * Build an array of all parents of a given window, starting with
2967 * the immediate parent. The array must be freed with HeapFree.
2968 * Returns NULL if window is a top-level window.
2970 HWND *WIN_ListParents( HWND hwnd )
2972 WND *win;
2973 HWND current, *list;
2974 int pos = 0, size = 16, count = 0;
2976 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
2978 current = hwnd;
2979 for (;;)
2981 if (!(win = WIN_GetPtr( current ))) goto empty;
2982 if (win == WND_OTHER_PROCESS) break; /* need to do it the hard way */
2983 list[pos] = win->parent;
2984 WIN_ReleasePtr( win );
2985 if (!(current = list[pos]))
2987 if (!pos) goto empty;
2988 return list;
2990 if (++pos == size - 1)
2992 /* need to grow the list */
2993 HWND *new_list = HeapReAlloc( GetProcessHeap(), 0, list, (size+16) * sizeof(HWND) );
2994 if (!new_list) goto empty;
2995 list = new_list;
2996 size += 16;
3000 /* at least one parent belongs to another process, have to query the server */
3002 for (;;)
3004 count = 0;
3005 SERVER_START_REQ( get_window_parents )
3007 req->handle = hwnd;
3008 wine_server_set_reply( req, list, (size-1) * sizeof(HWND) );
3009 if (!wine_server_call( req )) count = reply->count;
3011 SERVER_END_REQ;
3012 if (!count) goto empty;
3013 if (size > count)
3015 list[count] = 0;
3016 return list;
3018 HeapFree( GetProcessHeap(), 0, list );
3019 size = count + 1;
3020 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
3023 empty:
3024 HeapFree( GetProcessHeap(), 0, list );
3025 return NULL;
3029 /*******************************************************************
3030 * WIN_ListChildren
3032 * Build an array of the children of a given window. The array must be
3033 * freed with HeapFree. Returns NULL when no windows are found.
3035 HWND *WIN_ListChildren( HWND hwnd )
3037 return list_window_children( hwnd, 0, 0 );
3041 /*******************************************************************
3042 * EnumWindows (USER32.@)
3044 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
3046 HWND *list;
3047 BOOL ret = TRUE;
3048 int i, iWndsLocks;
3050 /* We have to build a list of all windows first, to avoid */
3051 /* unpleasant side-effects, for instance if the callback */
3052 /* function changes the Z-order of the windows. */
3054 if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
3056 /* Now call the callback function for every window */
3058 iWndsLocks = WIN_SuspendWndsLock();
3059 for (i = 0; list[i]; i++)
3061 /* Make sure that the window still exists */
3062 if (!IsWindow( list[i] )) continue;
3063 if (!(ret = lpEnumFunc( list[i], lParam ))) break;
3065 WIN_RestoreWndsLock(iWndsLocks);
3066 HeapFree( GetProcessHeap(), 0, list );
3067 return ret;
3071 /**********************************************************************
3072 * EnumThreadWindows (USER32.@)
3074 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
3076 HWND *list;
3077 int i, iWndsLocks;
3079 if (!(list = list_window_children( GetDesktopWindow(), 0, id ))) return TRUE;
3081 /* Now call the callback function for every window */
3083 iWndsLocks = WIN_SuspendWndsLock();
3084 for (i = 0; list[i]; i++)
3085 if (!func( list[i], lParam )) break;
3086 WIN_RestoreWndsLock(iWndsLocks);
3087 HeapFree( GetProcessHeap(), 0, list );
3088 return TRUE;
3092 /**********************************************************************
3093 * WIN_EnumChildWindows
3095 * Helper function for EnumChildWindows().
3097 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
3099 HWND *childList;
3100 BOOL ret = FALSE;
3102 for ( ; *list; list++)
3104 /* Make sure that the window still exists */
3105 if (!IsWindow( *list )) continue;
3106 /* skip owned windows */
3107 if (GetWindow( *list, GW_OWNER )) continue;
3108 /* Build children list first */
3109 childList = WIN_ListChildren( *list );
3111 ret = func( *list, lParam );
3113 if (childList)
3115 if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
3116 HeapFree( GetProcessHeap(), 0, childList );
3118 if (!ret) return FALSE;
3120 return TRUE;
3124 /**********************************************************************
3125 * EnumChildWindows (USER32.@)
3127 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
3129 HWND *list;
3130 int iWndsLocks;
3132 if (!(list = WIN_ListChildren( parent ))) return FALSE;
3133 iWndsLocks = WIN_SuspendWndsLock();
3134 WIN_EnumChildWindows( list, func, lParam );
3135 WIN_RestoreWndsLock(iWndsLocks);
3136 HeapFree( GetProcessHeap(), 0, list );
3137 return TRUE;
3141 /*******************************************************************
3142 * AnyPopup (USER.52)
3144 BOOL16 WINAPI AnyPopup16(void)
3146 return AnyPopup();
3150 /*******************************************************************
3151 * AnyPopup (USER32.@)
3153 BOOL WINAPI AnyPopup(void)
3155 int i;
3156 BOOL retvalue;
3157 HWND *list = WIN_ListChildren( GetDesktopWindow() );
3159 if (!list) return FALSE;
3160 for (i = 0; list[i]; i++)
3162 if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
3164 retvalue = (list[i] != 0);
3165 HeapFree( GetProcessHeap(), 0, list );
3166 return retvalue;
3170 /*******************************************************************
3171 * FlashWindow (USER32.@)
3173 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3175 WND *wndPtr = WIN_FindWndPtr(hWnd);
3177 TRACE("%p\n", hWnd);
3179 if (!wndPtr) return FALSE;
3180 hWnd = wndPtr->hwndSelf; /* make it a full handle */
3182 if (wndPtr->dwStyle & WS_MINIMIZE)
3184 if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
3186 HDC hDC = GetDC(hWnd);
3188 if (!SendMessageW( hWnd, WM_ERASEBKGND, (WPARAM)hDC, 0 ))
3189 wndPtr->flags |= WIN_NEEDS_ERASEBKGND;
3191 ReleaseDC( hWnd, hDC );
3192 wndPtr->flags |= WIN_NCACTIVATED;
3194 else
3196 RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
3197 wndPtr->flags &= ~WIN_NCACTIVATED;
3199 WIN_ReleaseWndPtr(wndPtr);
3200 return TRUE;
3202 else
3204 WPARAM16 wparam;
3205 if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3206 else wparam = (hWnd == GetForegroundWindow());
3208 WIN_ReleaseWndPtr(wndPtr);
3209 SendMessageW( hWnd, WM_NCACTIVATE, wparam, (LPARAM)0 );
3210 return wparam;
3214 /*******************************************************************
3215 * FlashWindowEx (USER32.@)
3217 BOOL WINAPI FlashWindowEx( PFLASHWINFO pfwi )
3219 FIXME("%p\n", pfwi);
3220 return TRUE;
3223 /*******************************************************************
3224 * GetWindowContextHelpId (USER32.@)
3226 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3228 DWORD retval;
3229 WND *wnd = WIN_FindWndPtr( hwnd );
3230 if (!wnd) return 0;
3231 retval = wnd->helpContext;
3232 WIN_ReleaseWndPtr(wnd);
3233 return retval;
3237 /*******************************************************************
3238 * SetWindowContextHelpId (USER32.@)
3240 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3242 WND *wnd = WIN_FindWndPtr( hwnd );
3243 if (!wnd) return FALSE;
3244 wnd->helpContext = id;
3245 WIN_ReleaseWndPtr(wnd);
3246 return TRUE;
3250 /*******************************************************************
3251 * DragDetect (USER32.@)
3253 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3255 MSG msg;
3256 RECT rect;
3258 rect.left = pt.x - wDragWidth;
3259 rect.right = pt.x + wDragWidth;
3261 rect.top = pt.y - wDragHeight;
3262 rect.bottom = pt.y + wDragHeight;
3264 SetCapture(hWnd);
3266 while(1)
3268 while(PeekMessageA(&msg ,0 ,WM_MOUSEFIRST ,WM_MOUSELAST ,PM_REMOVE))
3270 if( msg.message == WM_LBUTTONUP )
3272 ReleaseCapture();
3273 return 0;
3275 if( msg.message == WM_MOUSEMOVE )
3277 POINT tmp;
3278 tmp.x = LOWORD(msg.lParam);
3279 tmp.y = HIWORD(msg.lParam);
3280 if( !PtInRect( &rect, tmp ))
3282 ReleaseCapture();
3283 return 1;
3287 WaitMessage();
3289 return 0;
3292 /******************************************************************************
3293 * GetWindowModuleFileNameA (USER32.@)
3295 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR lpszFileName, UINT cchFileNameMax)
3297 FIXME("GetWindowModuleFileNameA(hwnd %p, lpszFileName %p, cchFileNameMax %u) stub!\n",
3298 hwnd, lpszFileName, cchFileNameMax);
3299 return 0;
3302 /******************************************************************************
3303 * GetWindowModuleFileNameW (USER32.@)
3305 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR lpszFileName, UINT cchFileNameMax)
3307 FIXME("GetWindowModuleFileNameW(hwnd %p, lpszFileName %p, cchFileNameMax %u) stub!\n",
3308 hwnd, lpszFileName, cchFileNameMax);
3309 return 0;
3312 /******************************************************************************
3313 * GetWindowInfo (USER32.@)
3314 * hwnd: in
3315 * pwi: out.
3316 * MS Documentation mentions that pwi->cbSize must be set to SIZEOF(WINDOWINFO)
3317 * this may be because this structure changed over time. If this is the
3318 * the case, then please: FIXME.
3319 * Using the structure described in MSDN for 98/ME/NT(4.0 SP3)/2000/XP.
3321 BOOL WINAPI GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3323 if (!pwi) return FALSE;
3324 if (pwi->cbSize != sizeof(WINDOWINFO))
3326 FIXME("windowinfo->cbSize != sizeof(WINDOWINFO). Please report\n");
3327 return FALSE;
3329 if (!IsWindow(hwnd)) return FALSE;
3331 GetWindowRect(hwnd, &pwi->rcWindow);
3332 GetClientRect(hwnd, &pwi->rcClient);
3333 /* translate to screen coordinates */
3334 MapWindowPoints(hwnd, 0, (LPPOINT)&pwi->rcClient, 2);
3336 pwi->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
3337 pwi->dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3338 pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3340 pwi->cxWindowBorders = pwi->rcClient.left - pwi->rcWindow.left;
3341 pwi->cyWindowBorders = pwi->rcWindow.bottom - pwi->rcClient.bottom;
3343 pwi->atomWindowType = GetClassLongW( hwnd, GCW_ATOM );
3344 pwi->wCreatorVersion = 0x0400;
3346 return TRUE;