Make WINEDLLOVERRIDES also match for *dll.
[wine/multimedia.git] / windows / win.c
blob658289b9dd3e3b79fda181ce4853ccd21d088e21
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) >> 1)
49 #define USER_HANDLE_TO_INDEX(hwnd) ((LOWORD(hwnd) - FIRST_USER_HANDLE) >> 1)
51 /**********************************************************************/
53 /* Desktop window */
54 static WND *pWndDesktop = NULL;
56 static WORD wDragWidth = 4;
57 static WORD wDragHeight= 3;
59 static void *user_handles[NB_USER_HANDLES];
61 /***********************************************************************
62 * create_window_handle
64 * Create a window handle with the server.
66 static WND *create_window_handle( HWND parent, HWND owner, ATOM atom,
67 HINSTANCE instance, WINDOWPROCTYPE type )
69 WORD index;
70 WND *win;
71 struct tagCLASS *class = NULL;
72 user_handle_t handle = 0;
73 int extra_bytes = 0;
75 /* if 16-bit instance, map to module handle */
76 if (instance && !HIWORD(instance))
77 instance = HINSTANCE_32(GetExePtr(HINSTANCE_16(instance)));
79 SERVER_START_REQ( create_window )
81 req->parent = parent;
82 req->owner = owner;
83 req->atom = atom;
84 req->instance = instance;
85 if (!wine_server_call_err( req ))
87 handle = reply->handle;
88 extra_bytes = reply->extra;
89 class = reply->class_ptr;
92 SERVER_END_REQ;
94 if (!handle)
96 WARN( "error %ld creating window\n", GetLastError() );
97 return NULL;
100 if (!(win = HeapAlloc( GetProcessHeap(), 0, sizeof(WND) + extra_bytes - sizeof(win->wExtra) )))
102 SERVER_START_REQ( destroy_window )
104 req->handle = handle;
105 wine_server_call( req );
107 SERVER_END_REQ;
108 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
109 return NULL;
112 USER_Lock();
114 index = USER_HANDLE_TO_INDEX(handle);
115 assert( index < NB_USER_HANDLES );
116 user_handles[index] = win;
117 win->hwndSelf = handle;
118 win->dwMagic = WND_MAGIC;
119 win->irefCount = 1;
120 win->cbWndExtra = extra_bytes;
121 memset( win->wExtra, 0, extra_bytes );
122 CLASS_AddWindow( class, win, type );
123 return win;
127 /***********************************************************************
128 * free_window_handle
130 * Free a window handle.
132 static WND *free_window_handle( HWND hwnd )
134 WND *ptr;
135 WORD index = USER_HANDLE_TO_INDEX(hwnd);
137 if (index >= NB_USER_HANDLES) return NULL;
138 USER_Lock();
139 if ((ptr = user_handles[index]))
141 SERVER_START_REQ( destroy_window )
143 req->handle = hwnd;
144 if (!wine_server_call_err( req ))
145 user_handles[index] = NULL;
146 else
147 ptr = NULL;
149 SERVER_END_REQ;
151 USER_Unlock();
152 if (ptr) HeapFree( GetProcessHeap(), 0, ptr );
153 return ptr;
157 /*******************************************************************
158 * list_window_children
160 * Build an array of the children of a given window. The array must be
161 * freed with HeapFree. Returns NULL when no windows are found.
163 static HWND *list_window_children( HWND hwnd, ATOM atom, DWORD tid )
165 HWND *list;
166 int size = 32;
168 for (;;)
170 int count = 0;
172 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) break;
174 SERVER_START_REQ( get_window_children )
176 req->parent = hwnd;
177 req->atom = atom;
178 req->tid = tid;
179 wine_server_set_reply( req, list, (size-1) * sizeof(HWND) );
180 if (!wine_server_call( req )) count = reply->count;
182 SERVER_END_REQ;
183 if (count && count < size)
185 list[count] = 0;
186 return list;
188 HeapFree( GetProcessHeap(), 0, list );
189 if (!count) break;
190 size = count + 1; /* restart with a large enough buffer */
192 return NULL;
196 /*******************************************************************
197 * send_parent_notify
199 static void send_parent_notify( HWND hwnd, UINT msg )
201 if ((GetWindowLongW( hwnd, GWL_STYLE ) & (WS_CHILD | WS_POPUP)) == WS_CHILD &&
202 !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOPARENTNOTIFY))
203 SendMessageW( GetParent(hwnd), WM_PARENTNOTIFY,
204 MAKEWPARAM( msg, GetWindowLongPtrW( hwnd, GWLP_ID )), (LPARAM)hwnd );
208 /*******************************************************************
209 * get_server_window_text
211 * Retrieve the window text from the server.
213 static void get_server_window_text( HWND hwnd, LPWSTR text, INT count )
215 size_t len = 0;
217 SERVER_START_REQ( get_window_text )
219 req->handle = hwnd;
220 wine_server_set_reply( req, text, (count - 1) * sizeof(WCHAR) );
221 if (!wine_server_call_err( req )) len = wine_server_reply_size(reply);
223 SERVER_END_REQ;
224 text[len / sizeof(WCHAR)] = 0;
228 /***********************************************************************
229 * WIN_GetPtr
231 * Return a pointer to the WND structure if local to the process,
232 * or WND_OTHER_PROCESS if handle may be valid in other process.
233 * If ret value is a valid pointer, it must be released with WIN_ReleasePtr.
235 WND *WIN_GetPtr( HWND hwnd )
237 WND * ptr;
238 WORD index = USER_HANDLE_TO_INDEX(hwnd);
240 if (index >= NB_USER_HANDLES) return NULL;
242 USER_Lock();
243 if ((ptr = user_handles[index]))
245 if (ptr->dwMagic == WND_MAGIC && (!HIWORD(hwnd) || hwnd == ptr->hwndSelf))
246 return ptr;
247 ptr = NULL;
249 else ptr = WND_OTHER_PROCESS;
250 USER_Unlock();
251 return ptr;
255 /***********************************************************************
256 * WIN_IsCurrentProcess
258 * Check whether a given window belongs to the current process (and return the full handle).
260 HWND WIN_IsCurrentProcess( HWND hwnd )
262 WND *ptr;
263 HWND ret;
265 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS) return 0;
266 ret = ptr->hwndSelf;
267 WIN_ReleasePtr( ptr );
268 return ret;
272 /***********************************************************************
273 * WIN_IsCurrentThread
275 * Check whether a given window belongs to the current thread (and return the full handle).
277 HWND WIN_IsCurrentThread( HWND hwnd )
279 WND *ptr;
280 HWND ret = 0;
282 if ((ptr = WIN_GetPtr( hwnd )) && ptr != WND_OTHER_PROCESS)
284 if (ptr->tid == GetCurrentThreadId()) ret = ptr->hwndSelf;
285 WIN_ReleasePtr( ptr );
287 return ret;
291 /***********************************************************************
292 * WIN_Handle32
294 * Convert a 16-bit window handle to a full 32-bit handle.
296 HWND WIN_Handle32( HWND16 hwnd16 )
298 WND *ptr;
299 HWND hwnd = (HWND)(ULONG_PTR)hwnd16;
301 if (hwnd16 <= 1 || hwnd16 == 0xffff) return hwnd;
302 /* do sign extension for -2 and -3 */
303 if (hwnd16 >= (HWND16)-3) return (HWND)(LONG_PTR)(INT16)hwnd16;
305 if (!(ptr = WIN_GetPtr( hwnd ))) return hwnd;
307 if (ptr != WND_OTHER_PROCESS)
309 hwnd = ptr->hwndSelf;
310 WIN_ReleasePtr( ptr );
312 else /* may belong to another process */
314 SERVER_START_REQ( get_window_info )
316 req->handle = hwnd;
317 if (!wine_server_call_err( req )) hwnd = reply->full_handle;
319 SERVER_END_REQ;
321 return hwnd;
325 /***********************************************************************
326 * WIN_FindWndPtr
328 * Return a pointer to the WND structure corresponding to a HWND.
330 WND * WIN_FindWndPtr( HWND hwnd )
332 WND * ptr;
334 if (!hwnd) return NULL;
336 if ((ptr = WIN_GetPtr( hwnd )))
338 if (ptr != WND_OTHER_PROCESS)
340 /* increment destruction monitoring */
341 ptr->irefCount++;
342 return ptr;
344 if (IsWindow( hwnd )) /* check other processes */
346 ERR( "window %p belongs to other process\n", hwnd );
347 /* DbgBreakPoint(); */
350 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
351 return NULL;
355 /***********************************************************************
356 * WIN_ReleaseWndPtr
358 * Release the pointer to the WND structure.
360 void WIN_ReleaseWndPtr(WND *wndPtr)
362 if(!wndPtr) return;
364 /* Decrement destruction monitoring value */
365 wndPtr->irefCount--;
366 /* Check if it's time to release the memory */
367 if(wndPtr->irefCount == 0 && !wndPtr->dwMagic)
369 /* Release memory */
370 free_window_handle( wndPtr->hwndSelf );
372 else if(wndPtr->irefCount < 0)
374 /* This else if is useful to monitor the WIN_ReleaseWndPtr function */
375 ERR("forgot a Lock on %p somewhere\n",wndPtr);
377 /* unlock all WND structures for thread safeness */
378 USER_Unlock();
382 /***********************************************************************
383 * WIN_UnlinkWindow
385 * Remove a window from the siblings linked list.
387 void WIN_UnlinkWindow( HWND hwnd )
389 WIN_LinkWindow( hwnd, 0, 0 );
393 /***********************************************************************
394 * WIN_LinkWindow
396 * Insert a window into the siblings linked list.
397 * The window is inserted after the specified window, which can also
398 * be specified as HWND_TOP or HWND_BOTTOM.
399 * If parent is 0, window is unlinked from the tree.
401 void WIN_LinkWindow( HWND hwnd, HWND parent, HWND hwndInsertAfter )
403 WND *wndPtr = WIN_GetPtr( hwnd );
405 if (!wndPtr) return;
406 if (wndPtr == WND_OTHER_PROCESS)
408 if (IsWindow(hwnd)) ERR(" cannot link other process window %p\n", hwnd );
409 return;
412 SERVER_START_REQ( link_window )
414 req->handle = hwnd;
415 req->parent = parent;
416 req->previous = hwndInsertAfter;
417 if (!wine_server_call( req ))
419 if (reply->full_parent) wndPtr->parent = reply->full_parent;
423 SERVER_END_REQ;
424 WIN_ReleasePtr( wndPtr );
428 /***********************************************************************
429 * WIN_SetOwner
431 * Change the owner of a window.
433 HWND WIN_SetOwner( HWND hwnd, HWND owner )
435 WND *win = WIN_GetPtr( hwnd );
436 HWND ret = 0;
438 if (!win) return 0;
439 if (win == WND_OTHER_PROCESS)
441 if (IsWindow(hwnd)) ERR( "cannot set owner %p on other process window %p\n", owner, hwnd );
442 return 0;
444 SERVER_START_REQ( set_window_owner )
446 req->handle = hwnd;
447 req->owner = owner;
448 if (!wine_server_call( req ))
450 win->owner = reply->full_owner;
451 ret = reply->prev_owner;
454 SERVER_END_REQ;
455 WIN_ReleasePtr( win );
456 return ret;
460 /***********************************************************************
461 * WIN_SetStyle
463 * Change the style of a window.
465 LONG WIN_SetStyle( HWND hwnd, LONG style )
467 BOOL ok;
468 LONG ret = 0;
469 WND *win = WIN_GetPtr( hwnd );
471 if (!win) return 0;
472 if (win == WND_OTHER_PROCESS)
474 if (IsWindow(hwnd))
475 ERR( "cannot set style %lx on other process window %p\n", style, hwnd );
476 return 0;
478 if (style == win->dwStyle)
480 WIN_ReleasePtr( win );
481 return style;
483 SERVER_START_REQ( set_window_info )
485 req->handle = hwnd;
486 req->flags = SET_WIN_STYLE;
487 req->style = style;
488 req->extra_offset = -1;
489 if ((ok = !wine_server_call( req )))
491 ret = reply->old_style;
492 win->dwStyle = style;
495 SERVER_END_REQ;
496 WIN_ReleasePtr( win );
497 if (ok && USER_Driver.pSetWindowStyle) USER_Driver.pSetWindowStyle( hwnd, ret );
498 return ret;
502 /***********************************************************************
503 * WIN_SetExStyle
505 * Change the extended style of a window.
507 LONG WIN_SetExStyle( HWND hwnd, LONG style )
509 LONG ret = 0;
510 WND *win = WIN_GetPtr( hwnd );
512 if (!win) return 0;
513 if (win == WND_OTHER_PROCESS)
515 if (IsWindow(hwnd))
516 ERR( "cannot set exstyle %lx on other process window %p\n", style, hwnd );
517 return 0;
519 if (style == win->dwExStyle)
521 WIN_ReleasePtr( win );
522 return style;
524 SERVER_START_REQ( set_window_info )
526 req->handle = hwnd;
527 req->flags = SET_WIN_EXSTYLE;
528 req->ex_style = style;
529 req->extra_offset = -1;
530 if (!wine_server_call( req ))
532 ret = reply->old_ex_style;
533 win->dwExStyle = style;
536 SERVER_END_REQ;
537 WIN_ReleasePtr( win );
538 return ret;
542 /***********************************************************************
543 * WIN_GetRectangles
545 * Get the window and client rectangles.
547 BOOL WIN_GetRectangles( HWND hwnd, RECT *rectWindow, RECT *rectClient )
549 WND *win = WIN_GetPtr( hwnd );
550 BOOL ret = TRUE;
552 if (!win) return FALSE;
553 if (win == WND_OTHER_PROCESS)
555 SERVER_START_REQ( get_window_rectangles )
557 req->handle = hwnd;
558 if ((ret = !wine_server_call( req )))
560 if (rectWindow)
562 rectWindow->left = reply->window.left;
563 rectWindow->top = reply->window.top;
564 rectWindow->right = reply->window.right;
565 rectWindow->bottom = reply->window.bottom;
567 if (rectClient)
569 rectClient->left = reply->client.left;
570 rectClient->top = reply->client.top;
571 rectClient->right = reply->client.right;
572 rectClient->bottom = reply->client.bottom;
576 SERVER_END_REQ;
578 else
580 if (rectWindow) *rectWindow = win->rectWindow;
581 if (rectClient) *rectClient = win->rectClient;
582 WIN_ReleasePtr( win );
584 return ret;
588 /***********************************************************************
589 * WIN_DestroyWindow
591 * Destroy storage associated to a window. "Internals" p.358
593 LRESULT WIN_DestroyWindow( HWND hwnd )
595 WND *wndPtr;
596 HWND *list;
598 TRACE("%p\n", hwnd );
600 if (!(hwnd = WIN_IsCurrentThread( hwnd )))
602 ERR( "window doesn't belong to current thread\n" );
603 return 0;
606 /* free child windows */
607 if ((list = WIN_ListChildren( hwnd )))
609 int i;
610 for (i = 0; list[i]; i++)
612 if (WIN_IsCurrentThread( list[i] )) WIN_DestroyWindow( list[i] );
613 else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
615 HeapFree( GetProcessHeap(), 0, list );
619 * Clear the update region to make sure no WM_PAINT messages will be
620 * generated for this window while processing the WM_NCDESTROY.
622 RedrawWindow( hwnd, NULL, 0,
623 RDW_VALIDATE | RDW_NOFRAME | RDW_NOERASE | RDW_NOINTERNALPAINT | RDW_NOCHILDREN);
626 * Send the WM_NCDESTROY to the window being destroyed.
628 SendMessageA( hwnd, WM_NCDESTROY, 0, 0);
630 /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
632 WINPOS_CheckInternalPos( hwnd );
633 if( hwnd == GetCapture()) ReleaseCapture();
635 /* free resources associated with the window */
637 TIMER_RemoveWindowTimers( hwnd );
639 if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
641 if (!(wndPtr->dwStyle & WS_CHILD))
643 HMENU menu = (HMENU)SetWindowLongPtrW( hwnd, GWLP_ID, 0 );
644 if (menu) DestroyMenu( menu );
646 if (wndPtr->hSysMenu)
648 DestroyMenu( wndPtr->hSysMenu );
649 wndPtr->hSysMenu = 0;
651 DCE_FreeWindowDCE( hwnd ); /* Always do this to catch orphaned DCs */
652 USER_Driver.pDestroyWindow( hwnd );
653 WINPROC_FreeProc( wndPtr->winproc, WIN_PROC_WINDOW );
654 wndPtr->class = NULL;
655 wndPtr->dwMagic = 0; /* Mark it as invalid */
656 WIN_ReleaseWndPtr( wndPtr );
657 return 0;
660 /***********************************************************************
661 * WIN_DestroyThreadWindows
663 * Destroy all children of 'wnd' owned by the current thread.
664 * Return TRUE if something was done.
666 void WIN_DestroyThreadWindows( HWND hwnd )
668 HWND *list;
669 int i;
671 if (!(list = WIN_ListChildren( hwnd ))) return;
672 for (i = 0; list[i]; i++)
674 if (WIN_IsCurrentThread( list[i] ))
675 DestroyWindow( list[i] );
676 else
677 WIN_DestroyThreadWindows( list[i] );
679 HeapFree( GetProcessHeap(), 0, list );
682 /***********************************************************************
683 * WIN_CreateDesktopWindow
685 * Create the desktop window.
687 BOOL WIN_CreateDesktopWindow(void)
689 HWND hwndDesktop;
690 CREATESTRUCTA cs;
692 TRACE("Creating desktop window\n");
694 if (!WINPOS_CreateInternalPosAtom()) return FALSE;
696 pWndDesktop = create_window_handle( 0, 0, LOWORD(DESKTOP_CLASS_ATOM), 0, WIN_PROC_32W );
697 if (!pWndDesktop) return FALSE;
698 hwndDesktop = pWndDesktop->hwndSelf;
700 pWndDesktop->tid = 0; /* nobody owns the desktop */
701 pWndDesktop->parent = 0;
702 pWndDesktop->owner = 0;
703 pWndDesktop->text = NULL;
704 pWndDesktop->hrgnUpdate = 0;
705 pWndDesktop->pVScroll = NULL;
706 pWndDesktop->pHScroll = NULL;
707 pWndDesktop->helpContext = 0;
708 pWndDesktop->flags = 0;
709 pWndDesktop->hSysMenu = 0;
711 cs.lpCreateParams = NULL;
712 cs.hInstance = 0;
713 cs.hMenu = 0;
714 cs.hwndParent = 0;
715 cs.x = 0;
716 cs.y = 0;
717 cs.cx = GetSystemMetrics( SM_CXSCREEN );
718 cs.cy = GetSystemMetrics( SM_CYSCREEN );
719 cs.style = pWndDesktop->dwStyle;
720 cs.dwExStyle = pWndDesktop->dwExStyle;
721 cs.lpszName = NULL;
722 cs.lpszClass = DESKTOP_CLASS_ATOM;
724 SERVER_START_REQ( set_window_info )
726 req->handle = hwndDesktop;
727 req->flags = 0; /* don't set anything, just retrieve */
728 req->extra_offset = -1;
729 wine_server_call( req );
730 pWndDesktop->dwStyle = reply->old_style;
731 pWndDesktop->dwExStyle = reply->old_ex_style;
732 pWndDesktop->hInstance = (HINSTANCE)reply->old_instance;
733 pWndDesktop->userdata = (ULONG_PTR)reply->old_user_data;
734 pWndDesktop->wIDmenu = reply->old_id;
736 SERVER_END_REQ;
738 if (!USER_Driver.pCreateWindow( hwndDesktop, &cs, FALSE ))
740 WIN_ReleaseWndPtr( pWndDesktop );
741 return FALSE;
744 pWndDesktop->flags |= WIN_NEEDS_ERASEBKGND;
745 WIN_ReleaseWndPtr( pWndDesktop );
746 return TRUE;
750 /***********************************************************************
751 * WIN_FixCoordinates
753 * Fix the coordinates - Helper for WIN_CreateWindowEx.
754 * returns default show mode in sw.
755 * Note: the feature presented as undocumented *is* in the MSDN since 1993.
757 static void WIN_FixCoordinates( CREATESTRUCTA *cs, INT *sw)
759 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16 ||
760 cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16)
762 if (cs->style & (WS_CHILD | WS_POPUP))
764 if (cs->dwExStyle & WS_EX_MDICHILD)
766 POINT pos[2];
768 MDI_CalcDefaultChildPos(cs->hwndParent, -1, pos, 0);
770 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16)
772 cs->x = pos[0].x;
773 cs->y = pos[0].y;
775 if (cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16 || !cs->cx)
776 cs->cx = pos[1].x;
777 if (cs->cy == CW_USEDEFAULT || cs->cy == CW_USEDEFAULT16 || !cs->cy)
778 cs->cy = pos[1].y;
780 else
782 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16)
783 cs->x = cs->y = 0;
784 if (cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16)
785 cs->cx = cs->cy = 0;
788 else /* overlapped window */
790 STARTUPINFOA info;
792 GetStartupInfoA( &info );
794 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16)
796 /* Never believe Microsoft's documentation... CreateWindowEx doc says
797 * that if an overlapped window is created with WS_VISIBLE style bit
798 * set and the x parameter is set to CW_USEDEFAULT, the system ignores
799 * the y parameter. However, disassembling NT implementation (WIN32K.SYS)
800 * reveals that
802 * 1) not only it checks for CW_USEDEFAULT but also for CW_USEDEFAULT16
803 * 2) it does not ignore the y parameter as the docs claim; instead, it
804 * uses it as second parameter to ShowWindow() unless y is either
805 * CW_USEDEFAULT or CW_USEDEFAULT16.
807 * The fact that we didn't do 2) caused bogus windows pop up when wine
808 * was running apps that were using this obscure feature. Example -
809 * calc.exe that comes with Win98 (only Win98, it's different from
810 * the one that comes with Win95 and NT)
812 if (cs->y != CW_USEDEFAULT && cs->y != CW_USEDEFAULT16) *sw = cs->y;
813 cs->x = (info.dwFlags & STARTF_USEPOSITION) ? info.dwX : 0;
814 cs->y = (info.dwFlags & STARTF_USEPOSITION) ? info.dwY : 0;
817 if (cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16)
819 if (info.dwFlags & STARTF_USESIZE)
821 cs->cx = info.dwXSize;
822 cs->cy = info.dwYSize;
824 else /* if no other hint from the app, pick 3/4 of the screen real estate */
826 RECT r;
827 SystemParametersInfoA( SPI_GETWORKAREA, 0, &r, 0);
828 cs->cx = (((r.right - r.left) * 3) / 4) - cs->x;
829 cs->cy = (((r.bottom - r.top) * 3) / 4) - cs->y;
834 else
836 /* neither x nor cx are default. Check the y values .
837 * In the trace we see Outlook and Outlook Express using
838 * cy set to CW_USEDEFAULT when opening the address book.
840 if (cs->cy == CW_USEDEFAULT || cs->cy == CW_USEDEFAULT16) {
841 RECT r;
842 FIXME("Strange use of CW_USEDEFAULT in nHeight\n");
843 SystemParametersInfoA( SPI_GETWORKAREA, 0, &r, 0);
844 cs->cy = (((r.bottom - r.top) * 3) / 4) - cs->y;
849 /***********************************************************************
850 * dump_window_styles
852 static void dump_window_styles( DWORD style, DWORD exstyle )
854 TRACE( "style:" );
855 if(style & WS_POPUP) TRACE(" WS_POPUP");
856 if(style & WS_CHILD) TRACE(" WS_CHILD");
857 if(style & WS_MINIMIZE) TRACE(" WS_MINIMIZE");
858 if(style & WS_VISIBLE) TRACE(" WS_VISIBLE");
859 if(style & WS_DISABLED) TRACE(" WS_DISABLED");
860 if(style & WS_CLIPSIBLINGS) TRACE(" WS_CLIPSIBLINGS");
861 if(style & WS_CLIPCHILDREN) TRACE(" WS_CLIPCHILDREN");
862 if(style & WS_MAXIMIZE) TRACE(" WS_MAXIMIZE");
863 if((style & WS_CAPTION) == WS_CAPTION) TRACE(" WS_CAPTION");
864 else
866 if(style & WS_BORDER) TRACE(" WS_BORDER");
867 if(style & WS_DLGFRAME) TRACE(" WS_DLGFRAME");
869 if(style & WS_VSCROLL) TRACE(" WS_VSCROLL");
870 if(style & WS_HSCROLL) TRACE(" WS_HSCROLL");
871 if(style & WS_SYSMENU) TRACE(" WS_SYSMENU");
872 if(style & WS_THICKFRAME) TRACE(" WS_THICKFRAME");
873 if(style & WS_GROUP) TRACE(" WS_GROUP");
874 if(style & WS_TABSTOP) TRACE(" WS_TABSTOP");
875 if(style & WS_MINIMIZEBOX) TRACE(" WS_MINIMIZEBOX");
876 if(style & WS_MAXIMIZEBOX) TRACE(" WS_MAXIMIZEBOX");
878 /* FIXME: Add dumping of BS_/ES_/SBS_/LBS_/CBS_/DS_/etc. styles */
879 #define DUMPED_STYLES \
880 (WS_POPUP | \
881 WS_CHILD | \
882 WS_MINIMIZE | \
883 WS_VISIBLE | \
884 WS_DISABLED | \
885 WS_CLIPSIBLINGS | \
886 WS_CLIPCHILDREN | \
887 WS_MAXIMIZE | \
888 WS_BORDER | \
889 WS_DLGFRAME | \
890 WS_VSCROLL | \
891 WS_HSCROLL | \
892 WS_SYSMENU | \
893 WS_THICKFRAME | \
894 WS_GROUP | \
895 WS_TABSTOP | \
896 WS_MINIMIZEBOX | \
897 WS_MAXIMIZEBOX)
899 if(style & ~DUMPED_STYLES) TRACE(" %08lx", style & ~DUMPED_STYLES);
900 TRACE("\n");
901 #undef DUMPED_STYLES
903 TRACE( "exstyle:" );
904 if(exstyle & WS_EX_DLGMODALFRAME) TRACE(" WS_EX_DLGMODALFRAME");
905 if(exstyle & WS_EX_DRAGDETECT) TRACE(" WS_EX_DRAGDETECT");
906 if(exstyle & WS_EX_NOPARENTNOTIFY) TRACE(" WS_EX_NOPARENTNOTIFY");
907 if(exstyle & WS_EX_TOPMOST) TRACE(" WS_EX_TOPMOST");
908 if(exstyle & WS_EX_ACCEPTFILES) TRACE(" WS_EX_ACCEPTFILES");
909 if(exstyle & WS_EX_TRANSPARENT) TRACE(" WS_EX_TRANSPARENT");
910 if(exstyle & WS_EX_MDICHILD) TRACE(" WS_EX_MDICHILD");
911 if(exstyle & WS_EX_TOOLWINDOW) TRACE(" WS_EX_TOOLWINDOW");
912 if(exstyle & WS_EX_WINDOWEDGE) TRACE(" WS_EX_WINDOWEDGE");
913 if(exstyle & WS_EX_CLIENTEDGE) TRACE(" WS_EX_CLIENTEDGE");
914 if(exstyle & WS_EX_CONTEXTHELP) TRACE(" WS_EX_CONTEXTHELP");
915 if(exstyle & WS_EX_RIGHT) TRACE(" WS_EX_RIGHT");
916 if(exstyle & WS_EX_RTLREADING) TRACE(" WS_EX_RTLREADING");
917 if(exstyle & WS_EX_LEFTSCROLLBAR) TRACE(" WS_EX_LEFTSCROLLBAR");
918 if(exstyle & WS_EX_CONTROLPARENT) TRACE(" WS_EX_CONTROLPARENT");
919 if(exstyle & WS_EX_STATICEDGE) TRACE(" WS_EX_STATICEDGE");
920 if(exstyle & WS_EX_APPWINDOW) TRACE(" WS_EX_APPWINDOW");
921 if(exstyle & WS_EX_LAYERED) TRACE(" WS_EX_LAYERED");
923 #define DUMPED_EX_STYLES \
924 (WS_EX_DLGMODALFRAME | \
925 WS_EX_DRAGDETECT | \
926 WS_EX_NOPARENTNOTIFY | \
927 WS_EX_TOPMOST | \
928 WS_EX_ACCEPTFILES | \
929 WS_EX_TRANSPARENT | \
930 WS_EX_MDICHILD | \
931 WS_EX_TOOLWINDOW | \
932 WS_EX_WINDOWEDGE | \
933 WS_EX_CLIENTEDGE | \
934 WS_EX_CONTEXTHELP | \
935 WS_EX_RIGHT | \
936 WS_EX_RTLREADING | \
937 WS_EX_LEFTSCROLLBAR | \
938 WS_EX_CONTROLPARENT | \
939 WS_EX_STATICEDGE | \
940 WS_EX_APPWINDOW | \
941 WS_EX_LAYERED)
943 if(exstyle & ~DUMPED_EX_STYLES) TRACE(" %08lx", exstyle & ~DUMPED_EX_STYLES);
944 TRACE("\n");
945 #undef DUMPED_EX_STYLES
949 /***********************************************************************
950 * WIN_CreateWindowEx
952 * Implementation of CreateWindowEx().
954 static HWND WIN_CreateWindowEx( CREATESTRUCTA *cs, ATOM classAtom,
955 WINDOWPROCTYPE type )
957 INT sw = SW_SHOW;
958 WND *wndPtr;
959 HWND hwnd, parent, owner, top_child = 0;
960 BOOL unicode = (type == WIN_PROC_32W);
962 TRACE("%s %s ex=%08lx style=%08lx %d,%d %dx%d parent=%p menu=%p inst=%p params=%p\n",
963 (type == WIN_PROC_32W) ? debugstr_w((LPWSTR)cs->lpszName) : debugstr_a(cs->lpszName),
964 (type == WIN_PROC_32W) ? debugstr_w((LPWSTR)cs->lpszClass) : debugstr_a(cs->lpszClass),
965 cs->dwExStyle, cs->style, cs->x, cs->y, cs->cx, cs->cy,
966 cs->hwndParent, cs->hMenu, cs->hInstance, cs->lpCreateParams );
968 if(TRACE_ON(win)) dump_window_styles( cs->style, cs->dwExStyle );
970 TRACE("winproc type is %d (%s)\n", type, (type == WIN_PROC_16) ? "WIN_PROC_16" :
971 ((type == WIN_PROC_32A) ? "WIN_PROC_32A" : "WIN_PROC_32W") );
973 /* Fix the styles for MDI children */
974 if (cs->dwExStyle & WS_EX_MDICHILD)
976 MDICREATESTRUCTA mdi_cs;
977 UINT flags = 0;
979 wndPtr = WIN_GetPtr(cs->hwndParent);
980 if (wndPtr && wndPtr != WND_OTHER_PROCESS)
982 flags = wndPtr->flags;
983 WIN_ReleasePtr(wndPtr);
986 if (!(flags & WIN_ISMDICLIENT))
988 WARN("WS_EX_MDICHILD, but parent %p is not MDIClient\n", cs->hwndParent);
989 return 0;
992 /* cs->lpCreateParams of WM_[NC]CREATE is different for MDI children.
993 * MDICREATESTRUCT members have the originally passed values.
995 * Note: we rely on the fact that MDICREATESTRUCTA and MDICREATESTRUCTW
996 * have the same layout.
998 mdi_cs.szClass = cs->lpszClass;
999 mdi_cs.szTitle = cs->lpszName;
1000 mdi_cs.hOwner = cs->hInstance;
1001 mdi_cs.x = cs->x;
1002 mdi_cs.y = cs->y;
1003 mdi_cs.cx = cs->cx;
1004 mdi_cs.cy = cs->cy;
1005 mdi_cs.style = cs->style;
1006 mdi_cs.lParam = (LPARAM)cs->lpCreateParams;
1008 cs->lpCreateParams = (LPVOID)&mdi_cs;
1010 if (GetWindowLongW(cs->hwndParent, GWL_STYLE) & MDIS_ALLCHILDSTYLES)
1012 if (cs->style & WS_POPUP)
1014 TRACE("WS_POPUP with MDIS_ALLCHILDSTYLES is not allowed\n");
1015 return 0;
1017 cs->style |= WS_CHILD | WS_CLIPSIBLINGS;
1019 else
1021 cs->style &= ~WS_POPUP;
1022 cs->style |= WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION |
1023 WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
1026 top_child = GetWindow(cs->hwndParent, GW_CHILD);
1028 if (top_child)
1030 /* Restore current maximized child */
1031 if((cs->style & WS_VISIBLE) && IsZoomed(top_child))
1033 TRACE("Restoring current maximized child %p\n", top_child);
1034 SendMessageW( top_child, WM_SETREDRAW, FALSE, 0 );
1035 ShowWindow(top_child, SW_RESTORE);
1036 SendMessageW( top_child, WM_SETREDRAW, TRUE, 0 );
1041 /* Find the parent window */
1043 parent = GetDesktopWindow();
1044 owner = 0;
1046 if (cs->hwndParent == HWND_MESSAGE)
1048 /* native ole32.OleInitialize uses HWND_MESSAGE to create the
1049 * message window (style: WS_POPUP|WS_DISABLED)
1051 FIXME("Parent is HWND_MESSAGE\n");
1053 else if (cs->hwndParent)
1055 /* Make sure parent is valid */
1056 if (!IsWindow( cs->hwndParent ))
1058 WARN("Bad parent %p\n", cs->hwndParent );
1059 return 0;
1061 if ((cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
1062 parent = WIN_GetFullHandle(cs->hwndParent);
1063 else
1064 owner = GetAncestor( cs->hwndParent, GA_ROOT );
1066 else if ((cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
1068 WARN("No parent for child window\n" );
1069 return 0; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
1072 WIN_FixCoordinates(cs, &sw); /* fix default coordinates */
1074 /* Correct the window styles.
1076 * It affects both the style loaded into the WIN structure and
1077 * passed in the CREATESTRUCT to the WM_[NC]CREATE.
1079 * WS_EX_WINDOWEDGE appears to be enforced based on the other styles, so
1080 * why does the user get to set it?
1083 /* This has been tested for WS_CHILD | WS_VISIBLE. It has not been
1084 * tested for WS_POPUP
1086 if ((cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
1087 ((!(cs->dwExStyle & WS_EX_STATICEDGE)) &&
1088 (cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
1089 cs->dwExStyle |= WS_EX_WINDOWEDGE;
1090 else
1091 cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
1093 if (!(cs->style & WS_CHILD))
1095 cs->style |= WS_CLIPSIBLINGS;
1096 if (!(cs->style & WS_POPUP))
1097 cs->style |= WS_CAPTION;
1100 /* Create the window structure */
1102 if (!(wndPtr = create_window_handle( parent, owner, classAtom, cs->hInstance, type )))
1104 TRACE("out of memory\n" );
1105 return 0;
1107 hwnd = wndPtr->hwndSelf;
1109 /* Fill the window structure */
1111 wndPtr->tid = GetCurrentThreadId();
1112 wndPtr->owner = owner;
1113 wndPtr->parent = parent;
1114 wndPtr->hInstance = cs->hInstance;
1115 wndPtr->text = NULL;
1116 wndPtr->hrgnUpdate = 0;
1117 wndPtr->dwStyle = cs->style & ~WS_VISIBLE;
1118 wndPtr->dwExStyle = cs->dwExStyle;
1119 wndPtr->wIDmenu = 0;
1120 wndPtr->helpContext = 0;
1121 wndPtr->flags = (type == WIN_PROC_16) ? 0 : WIN_ISWIN32;
1122 wndPtr->pVScroll = NULL;
1123 wndPtr->pHScroll = NULL;
1124 wndPtr->userdata = 0;
1125 wndPtr->hIcon = 0;
1126 wndPtr->hIconSmall = 0;
1127 wndPtr->hSysMenu = (wndPtr->dwStyle & WS_SYSMENU) ? MENU_GetSysMenu( hwnd, 0 ) : 0;
1129 if (!(cs->style & (WS_CHILD | WS_POPUP)))
1130 wndPtr->flags |= WIN_NEED_SIZE;
1132 SERVER_START_REQ( set_window_info )
1134 req->handle = hwnd;
1135 req->flags = SET_WIN_STYLE | SET_WIN_EXSTYLE | SET_WIN_INSTANCE;
1136 req->style = wndPtr->dwStyle;
1137 req->ex_style = wndPtr->dwExStyle;
1138 req->instance = (void *)wndPtr->hInstance;
1139 req->extra_offset = -1;
1140 wine_server_call( req );
1142 SERVER_END_REQ;
1144 /* Get class or window DC if needed */
1146 if (wndPtr->clsStyle & CS_OWNDC) wndPtr->dce = DCE_AllocDCE(hwnd,DCE_WINDOW_DC);
1148 /* Set the window menu */
1150 if (((wndPtr->dwStyle & (WS_CAPTION|WS_CHILD)) == WS_CAPTION) ||
1151 (wndPtr->dwExStyle & WS_EX_APPWINDOW))
1153 if (cs->hMenu) MENU_SetMenu(hwnd, cs->hMenu);
1154 else
1156 LPCSTR menuName = (LPCSTR)GetClassLongA( hwnd, GCL_MENUNAME );
1157 if (menuName)
1159 if (HIWORD(cs->hInstance))
1160 cs->hMenu = LoadMenuA(cs->hInstance,menuName);
1161 else
1162 cs->hMenu = HMENU_32(LoadMenu16(HINSTANCE_16(cs->hInstance),menuName));
1164 if (cs->hMenu) MENU_SetMenu( hwnd, cs->hMenu );
1168 else SetWindowLongPtrW( hwnd, GWLP_ID, (ULONG_PTR)cs->hMenu );
1169 WIN_ReleaseWndPtr( wndPtr );
1171 if (!USER_Driver.pCreateWindow( hwnd, cs, unicode))
1173 WIN_DestroyWindow( hwnd );
1174 return 0;
1177 /* Notify the parent window only */
1179 send_parent_notify( hwnd, WM_CREATE );
1180 if (!IsWindow( hwnd )) return 0;
1182 if (cs->style & WS_VISIBLE)
1184 if (cs->style & WS_MAXIMIZE)
1185 sw = SW_SHOWMAXIMIZED;
1186 else if (cs->style & WS_MINIMIZE)
1187 sw = SW_SHOWMINIMIZED;
1189 ShowWindow( hwnd, sw );
1190 if (cs->dwExStyle & WS_EX_MDICHILD)
1192 SendMessageW(cs->hwndParent, WM_MDIREFRESHMENU, 0, 0);
1193 /* ShowWindow won't activate child windows */
1194 SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE );
1198 /* Call WH_SHELL hook */
1200 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1201 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0, TRUE );
1203 TRACE("created window %p\n", hwnd);
1204 return hwnd;
1208 /***********************************************************************
1209 * CreateWindow (USER.41)
1211 HWND16 WINAPI CreateWindow16( LPCSTR className, LPCSTR windowName,
1212 DWORD style, INT16 x, INT16 y, INT16 width,
1213 INT16 height, HWND16 parent, HMENU16 menu,
1214 HINSTANCE16 instance, LPVOID data )
1216 return CreateWindowEx16( 0, className, windowName, style,
1217 x, y, width, height, parent, menu, instance, data );
1221 /***********************************************************************
1222 * CreateWindowEx (USER.452)
1224 HWND16 WINAPI CreateWindowEx16( DWORD exStyle, LPCSTR className,
1225 LPCSTR windowName, DWORD style, INT16 x,
1226 INT16 y, INT16 width, INT16 height,
1227 HWND16 parent, HMENU16 menu,
1228 HINSTANCE16 instance, LPVOID data )
1230 ATOM classAtom;
1231 CREATESTRUCTA cs;
1232 char buffer[256];
1234 /* Find the class atom */
1236 if (HIWORD(className))
1238 if (!(classAtom = GlobalFindAtomA( className )))
1240 ERR( "bad class name %s\n", debugstr_a(className) );
1241 return 0;
1244 else
1246 classAtom = LOWORD(className);
1247 if (!GlobalGetAtomNameA( classAtom, buffer, sizeof(buffer) ))
1249 ERR( "bad atom %x\n", classAtom);
1250 return 0;
1252 className = buffer;
1255 /* Fix the coordinates */
1257 cs.x = (x == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)x;
1258 cs.y = (y == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)y;
1259 cs.cx = (width == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)width;
1260 cs.cy = (height == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)height;
1262 /* Create the window */
1264 cs.lpCreateParams = data;
1265 cs.hInstance = HINSTANCE_32(instance);
1266 cs.hMenu = HMENU_32(menu);
1267 cs.hwndParent = WIN_Handle32( parent );
1268 cs.style = style;
1269 cs.lpszName = windowName;
1270 cs.lpszClass = className;
1271 cs.dwExStyle = exStyle;
1273 return HWND_16( WIN_CreateWindowEx( &cs, classAtom, WIN_PROC_16 ));
1277 /***********************************************************************
1278 * CreateWindowExA (USER32.@)
1280 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1281 LPCSTR windowName, DWORD style, INT x,
1282 INT y, INT width, INT height,
1283 HWND parent, HMENU menu,
1284 HINSTANCE instance, LPVOID data )
1286 ATOM classAtom;
1287 CREATESTRUCTA cs;
1288 char buffer[256];
1290 /* Find the class atom */
1292 if (HIWORD(className))
1294 if (!(classAtom = GlobalFindAtomA( className )))
1296 ERR( "bad class name %s\n", debugstr_a(className) );
1297 return 0;
1300 else
1302 classAtom = LOWORD(className);
1303 if (!GlobalGetAtomNameA( classAtom, buffer, sizeof(buffer) ))
1305 ERR( "bad atom %x\n", classAtom);
1306 return 0;
1308 className = buffer;
1311 /* Create the window */
1313 cs.lpCreateParams = data;
1314 cs.hInstance = instance;
1315 cs.hMenu = menu;
1316 cs.hwndParent = parent;
1317 cs.x = x;
1318 cs.y = y;
1319 cs.cx = width;
1320 cs.cy = height;
1321 cs.style = style;
1322 cs.lpszName = windowName;
1323 cs.lpszClass = className;
1324 cs.dwExStyle = exStyle;
1326 return WIN_CreateWindowEx( &cs, classAtom, WIN_PROC_32A );
1330 /***********************************************************************
1331 * CreateWindowExW (USER32.@)
1333 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1334 LPCWSTR windowName, DWORD style, INT x,
1335 INT y, INT width, INT height,
1336 HWND parent, HMENU menu,
1337 HINSTANCE instance, LPVOID data )
1339 ATOM classAtom;
1340 CREATESTRUCTW cs;
1341 WCHAR buffer[256];
1343 /* Find the class atom */
1345 if (HIWORD(className))
1347 if (!(classAtom = GlobalFindAtomW( className )))
1349 ERR( "bad class name %s\n", debugstr_w(className) );
1350 return 0;
1353 else
1355 classAtom = LOWORD(className);
1356 if (!GlobalGetAtomNameW( classAtom, buffer, sizeof(buffer)/sizeof(WCHAR) ))
1358 ERR( "bad atom %x\n", classAtom);
1359 return 0;
1361 className = buffer;
1364 /* Create the window */
1366 cs.lpCreateParams = data;
1367 cs.hInstance = instance;
1368 cs.hMenu = menu;
1369 cs.hwndParent = parent;
1370 cs.x = x;
1371 cs.y = y;
1372 cs.cx = width;
1373 cs.cy = height;
1374 cs.style = style;
1375 cs.lpszName = windowName;
1376 cs.lpszClass = className;
1377 cs.dwExStyle = exStyle;
1379 /* Note: we rely on the fact that CREATESTRUCTA and */
1380 /* CREATESTRUCTW have the same layout. */
1381 return WIN_CreateWindowEx( (CREATESTRUCTA *)&cs, classAtom, WIN_PROC_32W );
1385 /***********************************************************************
1386 * WIN_SendDestroyMsg
1388 static void WIN_SendDestroyMsg( HWND hwnd )
1390 GUITHREADINFO info;
1392 if (GetGUIThreadInfo( GetCurrentThreadId(), &info ))
1394 if (hwnd == info.hwndCaret) DestroyCaret();
1395 if (hwnd == info.hwndActive) WINPOS_ActivateOtherWindow( hwnd );
1397 if (USER_Driver.pResetSelectionOwner)
1398 USER_Driver.pResetSelectionOwner( hwnd, TRUE );
1401 * Send the WM_DESTROY to the window.
1403 SendMessageA( hwnd, WM_DESTROY, 0, 0);
1406 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1407 * make sure that the window still exists when we come back.
1409 if (IsWindow(hwnd))
1411 HWND* pWndArray;
1412 int i;
1414 if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1416 /* start from the end (FIXME: is this needed?) */
1417 for (i = 0; pWndArray[i]; i++) ;
1419 while (--i >= 0)
1421 if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1423 HeapFree( GetProcessHeap(), 0, pWndArray );
1425 else
1426 WARN("\tdestroyed itself while in WM_DESTROY!\n");
1430 /***********************************************************************
1431 * DestroyWindow (USER32.@)
1433 BOOL WINAPI DestroyWindow( HWND hwnd )
1435 BOOL is_child;
1437 if (!(hwnd = WIN_IsCurrentThread( hwnd )) || (hwnd == GetDesktopWindow()))
1439 SetLastError( ERROR_ACCESS_DENIED );
1440 return FALSE;
1443 TRACE("(%p)\n", hwnd);
1445 /* Call hooks */
1447 if (HOOK_CallHooks( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0, TRUE )) return FALSE;
1449 if (MENU_IsMenuActive() == hwnd)
1450 EndMenu();
1452 is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;
1454 if (is_child)
1456 if (!USER_IsExitingThread( GetCurrentThreadId() ))
1457 send_parent_notify( hwnd, WM_DESTROY );
1459 else if (!GetWindow( hwnd, GW_OWNER ))
1461 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
1462 /* FIXME: clean up palette - see "Internals" p.352 */
1465 if (!IsWindow(hwnd)) return TRUE;
1467 if (USER_Driver.pResetSelectionOwner)
1468 USER_Driver.pResetSelectionOwner( hwnd, FALSE ); /* before the window is unmapped */
1470 /* Hide the window */
1472 /* Only child windows receive WM_SHOWWINDOW in DestroyWindow() */
1473 if (is_child)
1474 ShowWindow( hwnd, SW_HIDE );
1475 else
1476 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE |
1477 SWP_NOZORDER | SWP_NOACTIVATE | SWP_HIDEWINDOW );
1479 if (!IsWindow(hwnd)) return TRUE;
1481 /* Recursively destroy owned windows */
1483 if (!is_child)
1485 for (;;)
1487 int i, got_one = 0;
1488 HWND *list = WIN_ListChildren( GetDesktopWindow() );
1489 if (list)
1491 for (i = 0; list[i]; i++)
1493 if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1494 if (WIN_IsCurrentThread( list[i] ))
1496 DestroyWindow( list[i] );
1497 got_one = 1;
1498 continue;
1500 WIN_SetOwner( list[i], 0 );
1502 HeapFree( GetProcessHeap(), 0, list );
1504 if (!got_one) break;
1508 /* Send destroy messages */
1510 WIN_SendDestroyMsg( hwnd );
1511 if (!IsWindow( hwnd )) return TRUE;
1513 if (GetClipboardOwner() == hwnd)
1514 CLIPBOARD_ReleaseOwner();
1516 /* Unlink now so we won't bother with the children later on */
1518 WIN_UnlinkWindow( hwnd );
1520 /* Destroy the window storage */
1522 WIN_DestroyWindow( hwnd );
1523 return TRUE;
1527 /***********************************************************************
1528 * CloseWindow (USER32.@)
1530 BOOL WINAPI CloseWindow( HWND hwnd )
1532 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1533 ShowWindow( hwnd, SW_MINIMIZE );
1534 return TRUE;
1538 /***********************************************************************
1539 * OpenIcon (USER32.@)
1541 BOOL WINAPI OpenIcon( HWND hwnd )
1543 if (!IsIconic( hwnd )) return FALSE;
1544 ShowWindow( hwnd, SW_SHOWNORMAL );
1545 return TRUE;
1549 /***********************************************************************
1550 * WIN_FindWindow
1552 * Implementation of FindWindow() and FindWindowEx().
1554 static HWND WIN_FindWindow( HWND parent, HWND child, ATOM className, LPCWSTR title )
1556 HWND *list = NULL;
1557 HWND retvalue = 0;
1558 int i = 0, len = 0;
1559 WCHAR *buffer = NULL;
1561 if (!parent) parent = GetDesktopWindow();
1562 if (title)
1564 len = strlenW(title) + 1; /* one extra char to check for chars beyond the end */
1565 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1568 if (!(list = list_window_children( parent, className, 0 ))) goto done;
1570 if (child)
1572 child = WIN_GetFullHandle( child );
1573 while (list[i] && list[i] != child) i++;
1574 if (!list[i]) goto done;
1575 i++; /* start from next window */
1578 if (title)
1580 while (list[i])
1582 if (GetWindowTextW( list[i], buffer, len + 1 ) && !strcmpiW( buffer, title )) break;
1583 i++;
1586 retvalue = list[i];
1588 done:
1589 if (list) HeapFree( GetProcessHeap(), 0, list );
1590 if (buffer) HeapFree( GetProcessHeap(), 0, buffer );
1591 return retvalue;
1596 /***********************************************************************
1597 * FindWindowA (USER32.@)
1599 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1601 HWND ret = FindWindowExA( 0, 0, className, title );
1602 if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1603 return ret;
1607 /***********************************************************************
1608 * FindWindowExA (USER32.@)
1610 HWND WINAPI FindWindowExA( HWND parent, HWND child,
1611 LPCSTR className, LPCSTR title )
1613 ATOM atom = 0;
1614 LPWSTR buffer;
1615 HWND hwnd;
1616 INT len;
1618 if (className)
1620 /* If the atom doesn't exist, then no class */
1621 /* with this name exists either. */
1622 if (!(atom = GlobalFindAtomA( className )))
1624 SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1625 return 0;
1628 if (!title) return WIN_FindWindow( parent, child, atom, NULL );
1630 len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
1631 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
1632 MultiByteToWideChar( CP_ACP, 0, title, -1, buffer, len );
1633 hwnd = WIN_FindWindow( parent, child, atom, buffer );
1634 HeapFree( GetProcessHeap(), 0, buffer );
1635 return hwnd;
1639 /***********************************************************************
1640 * FindWindowExW (USER32.@)
1642 HWND WINAPI FindWindowExW( HWND parent, HWND child,
1643 LPCWSTR className, LPCWSTR title )
1645 ATOM atom = 0;
1647 if (className)
1649 /* If the atom doesn't exist, then no class */
1650 /* with this name exists either. */
1651 if (!(atom = GlobalFindAtomW( className )))
1653 SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1654 return 0;
1657 return WIN_FindWindow( parent, child, atom, title );
1661 /***********************************************************************
1662 * FindWindowW (USER32.@)
1664 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
1666 return FindWindowExW( 0, 0, className, title );
1670 /**********************************************************************
1671 * GetDesktopWindow (USER32.@)
1673 HWND WINAPI GetDesktopWindow(void)
1675 if (pWndDesktop) return pWndDesktop->hwndSelf;
1676 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" );
1677 ExitProcess(1);
1678 return 0;
1682 /*******************************************************************
1683 * EnableWindow (USER32.@)
1685 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
1687 WND *wndPtr;
1688 BOOL retvalue;
1689 LONG style;
1690 HWND full_handle;
1692 if (is_broadcast(hwnd))
1694 SetLastError( ERROR_INVALID_PARAMETER );
1695 return FALSE;
1698 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
1699 return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
1701 hwnd = full_handle;
1703 TRACE("( %p, %d )\n", hwnd, enable);
1705 if (!(wndPtr = WIN_GetPtr( hwnd ))) return FALSE;
1706 style = wndPtr->dwStyle;
1707 retvalue = ((style & WS_DISABLED) != 0);
1708 WIN_ReleasePtr( wndPtr );
1710 if (enable && retvalue)
1712 WIN_SetStyle( hwnd, style & ~WS_DISABLED );
1713 SendMessageA( hwnd, WM_ENABLE, TRUE, 0 );
1715 else if (!enable && !retvalue)
1717 HWND capture_wnd;
1719 SendMessageA( hwnd, WM_CANCELMODE, 0, 0);
1721 WIN_SetStyle( hwnd, style | WS_DISABLED );
1723 if (hwnd == GetFocus())
1724 SetFocus( 0 ); /* A disabled window can't have the focus */
1726 capture_wnd = GetCapture();
1727 if (hwnd == capture_wnd || IsChild(hwnd, capture_wnd))
1728 ReleaseCapture(); /* A disabled window can't capture the mouse */
1730 SendMessageA( hwnd, WM_ENABLE, FALSE, 0 );
1732 return retvalue;
1736 /***********************************************************************
1737 * IsWindowEnabled (USER32.@)
1739 BOOL WINAPI IsWindowEnabled(HWND hWnd)
1741 return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
1745 /***********************************************************************
1746 * IsWindowUnicode (USER32.@)
1748 BOOL WINAPI IsWindowUnicode( HWND hwnd )
1750 WND * wndPtr;
1751 BOOL retvalue;
1753 if (!(wndPtr = WIN_FindWndPtr(hwnd))) return FALSE;
1754 retvalue = (WINPROC_GetProcType( wndPtr->winproc ) == WIN_PROC_32W);
1755 WIN_ReleaseWndPtr(wndPtr);
1756 return retvalue;
1760 /**********************************************************************
1761 * GetWindowWord (USER32.@)
1763 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
1765 if (offset >= 0)
1767 WORD retvalue = 0;
1768 WND *wndPtr = WIN_GetPtr( hwnd );
1769 if (!wndPtr)
1771 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1772 return 0;
1774 if (wndPtr == WND_OTHER_PROCESS)
1776 SERVER_START_REQ( set_window_info )
1778 req->handle = hwnd;
1779 req->flags = 0; /* don't set anything, just retrieve */
1780 req->extra_offset = offset;
1781 req->extra_size = sizeof(retvalue);
1782 if (!wine_server_call_err( req ))
1783 memcpy( &retvalue, &reply->old_extra_value, sizeof(retvalue) );
1785 SERVER_END_REQ;
1786 return retvalue;
1788 if (offset > (int)(wndPtr->cbWndExtra - sizeof(WORD)))
1790 WARN("Invalid offset %d\n", offset );
1791 SetLastError( ERROR_INVALID_INDEX );
1793 else memcpy( &retvalue, (char *)wndPtr->wExtra + offset, sizeof(retvalue) );
1794 WIN_ReleasePtr( wndPtr );
1795 return retvalue;
1798 switch(offset)
1800 case GWLP_HWNDPARENT:
1801 return GetWindowLongPtrW( hwnd, offset );
1802 case GWLP_ID:
1803 case GWLP_HINSTANCE:
1805 LONG_PTR ret = GetWindowLongPtrW( hwnd, offset );
1806 if (HIWORD(ret))
1807 WARN("%d: discards high bits of 0x%08lx!\n", offset, ret );
1808 return LOWORD(ret);
1810 default:
1811 WARN("Invalid offset %d\n", offset );
1812 return 0;
1817 /**********************************************************************
1818 * SetWindowWord (USER32.@)
1820 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
1822 WORD retval = 0;
1823 WND * wndPtr;
1825 switch(offset)
1827 case GWLP_ID:
1828 case GWLP_HINSTANCE:
1829 case GWLP_HWNDPARENT:
1830 return SetWindowLongPtrW( hwnd, offset, (ULONG_PTR)newval );
1831 default:
1832 if (offset < 0)
1834 WARN("Invalid offset %d\n", offset );
1835 SetLastError( ERROR_INVALID_INDEX );
1836 return 0;
1840 wndPtr = WIN_GetPtr( hwnd );
1841 if (wndPtr == WND_OTHER_PROCESS)
1843 if (IsWindow(hwnd))
1844 FIXME( "set %d <- %x not supported yet on other process window %p\n",
1845 offset, newval, hwnd );
1846 wndPtr = NULL;
1848 if (!wndPtr)
1850 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1851 return 0;
1854 if (offset > (int)(wndPtr->cbWndExtra - sizeof(WORD)))
1856 WARN("Invalid offset %d\n", offset );
1857 WIN_ReleasePtr(wndPtr);
1858 SetLastError( ERROR_INVALID_INDEX );
1859 return 0;
1862 SERVER_START_REQ( set_window_info )
1864 req->handle = hwnd;
1865 req->flags = SET_WIN_EXTRA;
1866 req->extra_offset = offset;
1867 req->extra_size = sizeof(newval);
1868 memcpy( &req->extra_value, &newval, sizeof(newval) );
1869 if (!wine_server_call_err( req ))
1871 void *ptr = (char *)wndPtr->wExtra + offset;
1872 memcpy( &retval, ptr, sizeof(retval) );
1873 memcpy( ptr, &newval, sizeof(newval) );
1876 SERVER_END_REQ;
1877 WIN_ReleasePtr( wndPtr );
1878 return retval;
1882 /**********************************************************************
1883 * WIN_GetWindowLong
1885 * Helper function for GetWindowLong().
1887 static LONG_PTR WIN_GetWindowLong( HWND hwnd, INT offset, WINDOWPROCTYPE type )
1889 LONG_PTR retvalue = 0;
1890 WND *wndPtr;
1892 if (offset == GWLP_HWNDPARENT)
1894 HWND parent = GetAncestor( hwnd, GA_PARENT );
1895 if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
1896 return (ULONG_PTR)parent;
1899 if (!(wndPtr = WIN_GetPtr( hwnd )))
1901 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1902 return 0;
1905 if (wndPtr == WND_OTHER_PROCESS)
1907 if (offset == GWLP_WNDPROC)
1909 SetLastError( ERROR_ACCESS_DENIED );
1910 return 0;
1912 SERVER_START_REQ( set_window_info )
1914 req->handle = hwnd;
1915 req->flags = 0; /* don't set anything, just retrieve */
1916 req->extra_offset = (offset >= 0) ? offset : -1;
1917 req->extra_size = (offset >= 0) ? sizeof(retvalue) : 0;
1918 if (!wine_server_call_err( req ))
1920 switch(offset)
1922 case GWL_STYLE: retvalue = reply->old_style; break;
1923 case GWL_EXSTYLE: retvalue = reply->old_ex_style; break;
1924 case GWLP_ID: retvalue = reply->old_id; break;
1925 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)reply->old_instance; break;
1926 case GWLP_USERDATA: retvalue = (ULONG_PTR)reply->old_user_data; break;
1927 default:
1928 if (offset >= 0) retvalue = reply->old_extra_value;
1929 else SetLastError( ERROR_INVALID_INDEX );
1930 break;
1934 SERVER_END_REQ;
1935 return retvalue;
1938 /* now we have a valid wndPtr */
1940 if (offset >= 0)
1942 if (offset > (int)(wndPtr->cbWndExtra - sizeof(LONG)))
1945 * Some programs try to access last element from 16 bit
1946 * code using illegal offset value. Hopefully this is
1947 * what those programs really expect.
1949 if (type == WIN_PROC_16 &&
1950 wndPtr->cbWndExtra >= 4 &&
1951 offset == wndPtr->cbWndExtra - sizeof(WORD))
1953 INT offset2 = wndPtr->cbWndExtra - sizeof(LONG);
1955 ERR( "- replaced invalid offset %d with %d\n",
1956 offset, offset2 );
1958 retvalue = *(LONG *)(((char *)wndPtr->wExtra) + offset2);
1959 WIN_ReleasePtr( wndPtr );
1960 return retvalue;
1962 WARN("Invalid offset %d\n", offset );
1963 WIN_ReleasePtr( wndPtr );
1964 SetLastError( ERROR_INVALID_INDEX );
1965 return 0;
1967 retvalue = *(LONG *)(((char *)wndPtr->wExtra) + offset);
1968 /* Special case for dialog window procedure */
1969 if ((offset == DWL_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
1970 retvalue = (LONG)WINPROC_GetProc( (WNDPROC)retvalue, type );
1971 WIN_ReleasePtr( wndPtr );
1972 return retvalue;
1975 switch(offset)
1977 case GWLP_USERDATA: retvalue = wndPtr->userdata; break;
1978 case GWL_STYLE: retvalue = wndPtr->dwStyle; break;
1979 case GWL_EXSTYLE: retvalue = wndPtr->dwExStyle; break;
1980 case GWLP_ID: retvalue = (ULONG_PTR)wndPtr->wIDmenu; break;
1981 case GWLP_WNDPROC: retvalue = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, type ); break;
1982 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hInstance; break;
1983 default:
1984 WARN("Unknown offset %d\n", offset );
1985 SetLastError( ERROR_INVALID_INDEX );
1986 break;
1988 WIN_ReleasePtr(wndPtr);
1989 return retvalue;
1993 /**********************************************************************
1994 * WIN_SetWindowLong
1996 * Helper function for SetWindowLong().
1998 * 0 is the failure code. However, in the case of failure SetLastError
1999 * must be set to distinguish between a 0 return value and a failure.
2001 static LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, LONG_PTR newval,
2002 WINDOWPROCTYPE type )
2004 STYLESTRUCT style;
2005 BOOL ok;
2006 LONG retval = 0;
2007 WND *wndPtr;
2009 TRACE( "%p %d %lx %x\n", hwnd, offset, newval, type );
2011 if (is_broadcast(hwnd))
2013 SetLastError( ERROR_INVALID_PARAMETER );
2014 return FALSE;
2016 if (!WIN_IsCurrentProcess( hwnd ))
2018 if (offset == GWLP_WNDPROC)
2020 SetLastError( ERROR_ACCESS_DENIED );
2021 return 0;
2023 return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, offset, newval );
2026 wndPtr = WIN_GetPtr( hwnd );
2027 if (wndPtr->hwndSelf == GetDesktopWindow())
2029 /* can't change anything on the desktop window */
2030 WIN_ReleasePtr( wndPtr );
2031 SetLastError( ERROR_ACCESS_DENIED );
2032 return 0;
2035 /* first some special cases */
2036 switch( offset )
2038 case GWL_STYLE:
2039 case GWL_EXSTYLE:
2040 style.styleOld =
2041 offset == GWL_STYLE ? wndPtr->dwStyle : wndPtr->dwExStyle;
2042 style.styleNew = newval;
2043 WIN_ReleasePtr( wndPtr );
2044 SendMessageW( hwnd, WM_STYLECHANGING, offset, (LPARAM)&style );
2045 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2046 newval = style.styleNew;
2047 break;
2048 case GWLP_HWNDPARENT:
2049 if (wndPtr->parent == GetDesktopWindow())
2051 WIN_ReleasePtr( wndPtr );
2052 return (ULONG_PTR)WIN_SetOwner( hwnd, (HWND)newval );
2054 else
2056 WIN_ReleasePtr( wndPtr );
2057 return (ULONG_PTR)SetParent( hwnd, (HWND)newval );
2059 case GWLP_WNDPROC:
2060 retval = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, type );
2061 WINPROC_SetProc( &wndPtr->winproc, (WNDPROC)newval, type, WIN_PROC_WINDOW );
2062 WIN_ReleasePtr( wndPtr );
2063 return retval;
2064 case GWLP_ID:
2065 case GWLP_HINSTANCE:
2066 case GWLP_USERDATA:
2067 break;
2068 case DWLP_DLGPROC:
2069 if ((wndPtr->cbWndExtra + sizeof(LONG) >= DWLP_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
2071 WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWLP_DLGPROC);
2072 retval = (ULONG_PTR)WINPROC_GetProc( *ptr, type );
2073 WINPROC_SetProc( ptr, (WNDPROC)newval, type, WIN_PROC_WINDOW );
2074 WIN_ReleasePtr( wndPtr );
2075 return retval;
2077 /* fall through */
2078 default:
2079 if (offset < 0 || offset > (int)(wndPtr->cbWndExtra - sizeof(LONG)))
2081 WARN("Invalid offset %d\n", offset );
2082 WIN_ReleasePtr( wndPtr );
2083 SetLastError( ERROR_INVALID_INDEX );
2084 return 0;
2086 else
2088 LONG_PTR *ptr = (LONG_PTR *)((char *)wndPtr->wExtra + offset);
2089 if (*ptr == newval) /* already set to the same value */
2091 WIN_ReleasePtr( wndPtr );
2092 return newval;
2095 break;
2098 SERVER_START_REQ( set_window_info )
2100 req->handle = hwnd;
2101 req->extra_offset = -1;
2102 switch(offset)
2104 case GWL_STYLE:
2105 req->flags = SET_WIN_STYLE;
2106 req->style = newval;
2107 break;
2108 case GWL_EXSTYLE:
2109 req->flags = SET_WIN_EXSTYLE;
2110 req->ex_style = newval;
2111 break;
2112 case GWLP_ID:
2113 req->flags = SET_WIN_ID;
2114 req->id = newval;
2115 break;
2116 case GWLP_HINSTANCE:
2117 req->flags = SET_WIN_INSTANCE;
2118 req->instance = (void *)newval;
2119 break;
2120 case GWLP_USERDATA:
2121 req->flags = SET_WIN_USERDATA;
2122 req->user_data = (void *)newval;
2123 break;
2124 default:
2125 req->flags = SET_WIN_EXTRA;
2126 req->extra_offset = offset;
2127 req->extra_size = sizeof(newval);
2128 memcpy( &req->extra_value, &newval, sizeof(newval) );
2130 if ((ok = !wine_server_call_err( req )))
2132 switch(offset)
2134 case GWL_STYLE:
2135 wndPtr->dwStyle = newval;
2136 retval = reply->old_style;
2137 break;
2138 case GWL_EXSTYLE:
2139 wndPtr->dwExStyle = newval;
2140 retval = reply->old_ex_style;
2141 break;
2142 case GWLP_ID:
2143 wndPtr->wIDmenu = newval;
2144 retval = reply->old_id;
2145 break;
2146 case GWLP_HINSTANCE:
2147 wndPtr->hInstance = (HINSTANCE)newval;
2148 retval = (ULONG_PTR)reply->old_instance;
2149 break;
2150 case GWLP_USERDATA:
2151 wndPtr->userdata = newval;
2152 retval = (ULONG_PTR)reply->old_user_data;
2153 break;
2154 default:
2156 void *ptr = (char *)wndPtr->wExtra + offset;
2157 memcpy( &retval, ptr, sizeof(retval) );
2158 memcpy( ptr, &newval, sizeof(newval) );
2160 break;
2164 SERVER_END_REQ;
2165 WIN_ReleasePtr( wndPtr );
2167 if (!ok) return 0;
2169 if (offset == GWL_STYLE && USER_Driver.pSetWindowStyle)
2170 USER_Driver.pSetWindowStyle( hwnd, retval );
2172 if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2173 SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2175 return retval;
2179 /**********************************************************************
2180 * GetWindowLong (USER.135)
2182 LONG WINAPI GetWindowLong16( HWND16 hwnd, INT16 offset )
2184 return WIN_GetWindowLong( WIN_Handle32(hwnd), offset, WIN_PROC_16 );
2188 /**********************************************************************
2189 * GetWindowLongA (USER32.@)
2191 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2193 return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32A );
2197 /**********************************************************************
2198 * GetWindowLongW (USER32.@)
2200 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2202 return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32W );
2206 /**********************************************************************
2207 * SetWindowLong (USER.136)
2209 LONG WINAPI SetWindowLong16( HWND16 hwnd, INT16 offset, LONG newval )
2211 return WIN_SetWindowLong( WIN_Handle32(hwnd), offset, newval, WIN_PROC_16 );
2215 /**********************************************************************
2216 * SetWindowLongA (USER32.@)
2218 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2220 return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32A );
2224 /**********************************************************************
2225 * SetWindowLongW (USER32.@) Set window attribute
2227 * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2228 * value in a window's extra memory.
2230 * The _hwnd_ parameter specifies the window. is the handle to a
2231 * window that has extra memory. The _newval_ parameter contains the
2232 * new attribute or extra memory value. If positive, the _offset_
2233 * parameter is the byte-addressed location in the window's extra
2234 * memory to set. If negative, _offset_ specifies the window
2235 * attribute to set, and should be one of the following values:
2237 * GWL_EXSTYLE The window's extended window style
2239 * GWL_STYLE The window's window style.
2241 * GWLP_WNDPROC Pointer to the window's window procedure.
2243 * GWLP_HINSTANCE The window's pplication instance handle.
2245 * GWLP_ID The window's identifier.
2247 * GWLP_USERDATA The window's user-specified data.
2249 * If the window is a dialog box, the _offset_ parameter can be one of
2250 * the following values:
2252 * DWLP_DLGPROC The address of the window's dialog box procedure.
2254 * DWLP_MSGRESULT The return value of a message
2255 * that the dialog box procedure processed.
2257 * DWLP_USER Application specific information.
2259 * RETURNS
2261 * If successful, returns the previous value located at _offset_. Otherwise,
2262 * returns 0.
2264 * NOTES
2266 * Extra memory for a window class is specified by a nonzero cbWndExtra
2267 * parameter of the WNDCLASS structure passed to RegisterClass() at the
2268 * time of class creation.
2270 * Using GWL_WNDPROC to set a new window procedure effectively creates
2271 * a window subclass. Use CallWindowProc() in the new windows procedure
2272 * to pass messages to the superclass's window procedure.
2274 * The user data is reserved for use by the application which created
2275 * the window.
2277 * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2278 * instead, call the EnableWindow() function to change the window's
2279 * disabled state.
2281 * Do not use GWL_HWNDPARENT to reset the window's parent, use
2282 * SetParent() instead.
2284 * Win95:
2285 * When offset is GWL_STYLE and the calling app's ver is 4.0,
2286 * it sends WM_STYLECHANGING before changing the settings
2287 * and WM_STYLECHANGED afterwards.
2288 * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2290 LONG WINAPI SetWindowLongW(
2291 HWND hwnd, /* [in] window to alter */
2292 INT offset, /* [in] offset, in bytes, of location to alter */
2293 LONG newval /* [in] new value of location */
2295 return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32W );
2299 /*******************************************************************
2300 * GetWindowTextA (USER32.@)
2302 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2304 WCHAR *buffer;
2306 if (WIN_IsCurrentProcess( hwnd ))
2307 return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2309 /* when window belongs to other process, don't send a message */
2310 if (nMaxCount <= 0) return 0;
2311 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2312 get_server_window_text( hwnd, buffer, nMaxCount );
2313 if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2314 lpString[nMaxCount-1] = 0;
2315 HeapFree( GetProcessHeap(), 0, buffer );
2316 return strlen(lpString);
2320 /*******************************************************************
2321 * InternalGetWindowText (USER32.@)
2323 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2325 WND *win;
2327 if (nMaxCount <= 0) return 0;
2328 if (!(win = WIN_GetPtr( hwnd ))) return 0;
2329 if (win != WND_OTHER_PROCESS)
2331 if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2332 else lpString[0] = 0;
2333 WIN_ReleasePtr( win );
2335 else
2337 get_server_window_text( hwnd, lpString, nMaxCount );
2339 return strlenW(lpString);
2343 /*******************************************************************
2344 * GetWindowTextW (USER32.@)
2346 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2348 if (WIN_IsCurrentProcess( hwnd ))
2349 return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2351 /* when window belongs to other process, don't send a message */
2352 if (nMaxCount <= 0) return 0;
2353 get_server_window_text( hwnd, lpString, nMaxCount );
2354 return strlenW(lpString);
2358 /*******************************************************************
2359 * SetWindowText (USER32.@)
2360 * SetWindowTextA (USER32.@)
2362 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2364 if (is_broadcast(hwnd))
2366 SetLastError( ERROR_INVALID_PARAMETER );
2367 return FALSE;
2369 if (!WIN_IsCurrentProcess( hwnd ))
2371 FIXME( "cannot set text %s of other process window %p\n", debugstr_a(lpString), hwnd );
2372 SetLastError( ERROR_ACCESS_DENIED );
2373 return FALSE;
2375 return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2379 /*******************************************************************
2380 * SetWindowTextW (USER32.@)
2382 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2384 if (is_broadcast(hwnd))
2386 SetLastError( ERROR_INVALID_PARAMETER );
2387 return FALSE;
2389 if (!WIN_IsCurrentProcess( hwnd ))
2391 FIXME( "cannot set text %s of other process window %p\n", debugstr_w(lpString), hwnd );
2392 SetLastError( ERROR_ACCESS_DENIED );
2393 return FALSE;
2395 return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2399 /*******************************************************************
2400 * GetWindowTextLengthA (USER32.@)
2402 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2404 return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2407 /*******************************************************************
2408 * GetWindowTextLengthW (USER32.@)
2410 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2412 return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2416 /*******************************************************************
2417 * IsWindow (USER32.@)
2419 BOOL WINAPI IsWindow( HWND hwnd )
2421 WND *ptr;
2422 BOOL ret;
2424 if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2426 if (ptr != WND_OTHER_PROCESS)
2428 WIN_ReleasePtr( ptr );
2429 return TRUE;
2432 /* check other processes */
2433 SERVER_START_REQ( get_window_info )
2435 req->handle = hwnd;
2436 ret = !wine_server_call_err( req );
2438 SERVER_END_REQ;
2439 return ret;
2443 /***********************************************************************
2444 * GetWindowThreadProcessId (USER32.@)
2446 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2448 WND *ptr;
2449 DWORD tid = 0;
2451 if (!(ptr = WIN_GetPtr( hwnd )))
2453 SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2454 return 0;
2457 if (ptr != WND_OTHER_PROCESS)
2459 /* got a valid window */
2460 tid = ptr->tid;
2461 if (process) *process = GetCurrentProcessId();
2462 WIN_ReleasePtr( ptr );
2463 return tid;
2466 /* check other processes */
2467 SERVER_START_REQ( get_window_info )
2469 req->handle = hwnd;
2470 if (!wine_server_call_err( req ))
2472 tid = (DWORD)reply->tid;
2473 if (process) *process = (DWORD)reply->pid;
2476 SERVER_END_REQ;
2477 return tid;
2481 /*****************************************************************
2482 * GetParent (USER32.@)
2484 HWND WINAPI GetParent( HWND hwnd )
2486 WND *wndPtr;
2487 HWND retvalue = 0;
2489 if (!(wndPtr = WIN_GetPtr( hwnd )))
2491 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2492 return 0;
2494 if (wndPtr == WND_OTHER_PROCESS)
2496 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2497 if (style & (WS_POPUP | WS_CHILD))
2499 SERVER_START_REQ( get_window_tree )
2501 req->handle = hwnd;
2502 if (!wine_server_call_err( req ))
2504 if (style & WS_POPUP) retvalue = reply->owner;
2505 else if (style & WS_CHILD) retvalue = reply->parent;
2508 SERVER_END_REQ;
2511 else
2513 if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2514 else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2515 WIN_ReleasePtr( wndPtr );
2517 return retvalue;
2521 /*****************************************************************
2522 * GetAncestor (USER32.@)
2524 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2526 WND *win;
2527 HWND *list, ret = 0;
2529 switch(type)
2531 case GA_PARENT:
2532 if (!(win = WIN_GetPtr( hwnd )))
2534 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2535 return 0;
2537 if (win != WND_OTHER_PROCESS)
2539 ret = win->parent;
2540 WIN_ReleasePtr( win );
2542 else /* need to query the server */
2544 SERVER_START_REQ( get_window_tree )
2546 req->handle = hwnd;
2547 if (!wine_server_call_err( req )) ret = reply->parent;
2549 SERVER_END_REQ;
2551 break;
2553 case GA_ROOT:
2554 if (!(list = WIN_ListParents( hwnd ))) return 0;
2556 if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd ); /* top-level window */
2557 else
2559 int count = 2;
2560 while (list[count]) count++;
2561 ret = list[count - 2]; /* get the one before the desktop */
2563 HeapFree( GetProcessHeap(), 0, list );
2564 break;
2566 case GA_ROOTOWNER:
2567 if ((ret = WIN_GetFullHandle( hwnd )) == GetDesktopWindow()) return 0;
2568 for (;;)
2570 HWND parent = GetParent( ret );
2571 if (!parent) break;
2572 ret = parent;
2574 break;
2576 return ret;
2580 /*****************************************************************
2581 * SetParent (USER32.@)
2583 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2585 WND *wndPtr;
2586 HWND retvalue, full_handle;
2587 BOOL was_visible;
2589 if (is_broadcast(hwnd) || is_broadcast(parent))
2591 SetLastError(ERROR_INVALID_PARAMETER);
2592 return 0;
2595 if (!parent) parent = GetDesktopWindow();
2596 else parent = WIN_GetFullHandle( parent );
2598 if (!IsWindow( parent ))
2600 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2601 return 0;
2604 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2605 return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2607 hwnd = full_handle;
2609 if (USER_Driver.pSetParent)
2610 return USER_Driver.pSetParent( hwnd, parent );
2612 /* Windows hides the window first, then shows it again
2613 * including the WM_SHOWWINDOW messages and all */
2614 was_visible = ShowWindow( hwnd, SW_HIDE );
2616 if (!IsWindow( parent )) return 0;
2617 if (!(wndPtr = WIN_GetPtr(hwnd)) || wndPtr == WND_OTHER_PROCESS) return 0;
2619 retvalue = wndPtr->parent; /* old parent */
2620 if (parent != retvalue)
2622 WIN_LinkWindow( hwnd, parent, HWND_TOP );
2624 if (parent != GetDesktopWindow()) /* a child window */
2626 if (!(wndPtr->dwStyle & WS_CHILD))
2628 HMENU menu = (HMENU)SetWindowLongPtrW( hwnd, GWLP_ID, 0 );
2629 if (menu) DestroyMenu( menu );
2633 WIN_ReleasePtr( wndPtr );
2635 /* SetParent additionally needs to make hwnd the topmost window
2636 in the x-order and send the expected WM_WINDOWPOSCHANGING and
2637 WM_WINDOWPOSCHANGED notification messages.
2639 SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0,
2640 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | (was_visible ? SWP_SHOWWINDOW : 0) );
2641 /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
2642 * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
2643 return retvalue;
2647 /*******************************************************************
2648 * IsChild (USER32.@)
2650 BOOL WINAPI IsChild( HWND parent, HWND child )
2652 HWND *list = WIN_ListParents( child );
2653 int i;
2654 BOOL ret;
2656 if (!list) return FALSE;
2657 parent = WIN_GetFullHandle( parent );
2658 for (i = 0; list[i]; i++) if (list[i] == parent) break;
2659 ret = (list[i] != 0);
2660 HeapFree( GetProcessHeap(), 0, list );
2661 return ret;
2665 /***********************************************************************
2666 * IsWindowVisible (USER32.@)
2668 BOOL WINAPI IsWindowVisible( HWND hwnd )
2670 HWND *list;
2671 BOOL retval;
2672 int i;
2674 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2675 if (!(list = WIN_ListParents( hwnd ))) return TRUE;
2676 for (i = 0; list[i]; i++)
2677 if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2678 retval = !list[i];
2679 HeapFree( GetProcessHeap(), 0, list );
2680 return retval;
2684 /***********************************************************************
2685 * WIN_IsWindowDrawable
2687 * hwnd is drawable when it is visible, all parents are not
2688 * minimized, and it is itself not minimized unless we are
2689 * trying to draw its default class icon.
2691 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2693 HWND *list;
2694 BOOL retval;
2695 int i;
2696 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2698 if (!(style & WS_VISIBLE)) return FALSE;
2699 if ((style & WS_MINIMIZE) && icon && GetClassLongA( hwnd, GCL_HICON )) return FALSE;
2701 if (!(list = WIN_ListParents( hwnd ))) return TRUE;
2702 for (i = 0; list[i]; i++)
2703 if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2704 break;
2705 retval = !list[i];
2706 HeapFree( GetProcessHeap(), 0, list );
2707 return retval;
2711 /*******************************************************************
2712 * GetTopWindow (USER32.@)
2714 HWND WINAPI GetTopWindow( HWND hwnd )
2716 if (!hwnd) hwnd = GetDesktopWindow();
2717 return GetWindow( hwnd, GW_CHILD );
2721 /*******************************************************************
2722 * GetWindow (USER32.@)
2724 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2726 HWND retval = 0;
2728 if (rel == GW_OWNER) /* this one may be available locally */
2730 WND *wndPtr = WIN_GetPtr( hwnd );
2731 if (!wndPtr)
2733 SetLastError( ERROR_INVALID_HANDLE );
2734 return 0;
2736 if (wndPtr != WND_OTHER_PROCESS)
2738 retval = wndPtr->owner;
2739 WIN_ReleasePtr( wndPtr );
2740 return retval;
2742 /* else fall through to server call */
2745 SERVER_START_REQ( get_window_tree )
2747 req->handle = hwnd;
2748 if (!wine_server_call_err( req ))
2750 switch(rel)
2752 case GW_HWNDFIRST:
2753 retval = reply->first_sibling;
2754 break;
2755 case GW_HWNDLAST:
2756 retval = reply->last_sibling;
2757 break;
2758 case GW_HWNDNEXT:
2759 retval = reply->next_sibling;
2760 break;
2761 case GW_HWNDPREV:
2762 retval = reply->prev_sibling;
2763 break;
2764 case GW_OWNER:
2765 retval = reply->owner;
2766 break;
2767 case GW_CHILD:
2768 retval = reply->first_child;
2769 break;
2773 SERVER_END_REQ;
2774 return retval;
2778 /***********************************************************************
2779 * WIN_InternalShowOwnedPopups
2781 * Internal version of ShowOwnedPopups; Wine functions should use this
2782 * to avoid interfering with application calls to ShowOwnedPopups
2783 * and to make sure the application can't prevent showing/hiding.
2785 * Set unmanagedOnly to TRUE to show/hide unmanaged windows only.
2789 BOOL WIN_InternalShowOwnedPopups( HWND owner, BOOL fShow, BOOL unmanagedOnly )
2791 int count = 0;
2792 WND *pWnd;
2793 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2795 if (!win_array) return TRUE;
2798 * Show windows Lowest first, Highest last to preserve Z-Order
2800 while (win_array[count]) count++;
2801 while (--count >= 0)
2803 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2804 if (!(pWnd = WIN_FindWndPtr( win_array[count] ))) continue;
2806 if (pWnd->dwStyle & WS_POPUP)
2808 if (fShow)
2810 /* check in window was flagged for showing in previous WIN_InternalShowOwnedPopups call */
2811 if (pWnd->flags & WIN_NEEDS_INTERNALSOP)
2814 * Call ShowWindow directly because an application can intercept WM_SHOWWINDOW messages
2816 ShowWindow(pWnd->hwndSelf,SW_SHOW);
2817 pWnd->flags &= ~WIN_NEEDS_INTERNALSOP; /* remove the flag */
2820 else
2822 if ( IsWindowVisible(pWnd->hwndSelf) && /* hide only if window is visible */
2823 !( pWnd->flags & WIN_NEEDS_INTERNALSOP ) && /* don't hide if previous call already did it */
2824 !( unmanagedOnly && (pWnd->dwExStyle & WS_EX_MANAGED) ) ) /* don't hide managed windows if unmanagedOnly is TRUE */
2827 * Call ShowWindow directly because an application can intercept WM_SHOWWINDOW messages
2829 ShowWindow(pWnd->hwndSelf,SW_HIDE);
2830 /* flag the window for showing on next WIN_InternalShowOwnedPopups call */
2831 pWnd->flags |= WIN_NEEDS_INTERNALSOP;
2835 WIN_ReleaseWndPtr( pWnd );
2837 HeapFree( GetProcessHeap(), 0, win_array );
2839 return TRUE;
2842 /*******************************************************************
2843 * ShowOwnedPopups (USER32.@)
2845 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2847 int count = 0;
2848 WND *pWnd;
2849 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2851 if (!win_array) return TRUE;
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 if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2865 /* In Windows, ShowOwnedPopups(TRUE) generates
2866 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
2867 * regardless of the state of the owner
2869 SendMessageA(pWnd->hwndSelf, WM_SHOWWINDOW, SW_SHOW, SW_PARENTOPENING);
2870 pWnd->flags &= ~WIN_NEEDS_SHOW_OWNEDPOPUP;
2873 else
2875 if (IsWindowVisible(pWnd->hwndSelf))
2877 /* In Windows, ShowOwnedPopups(FALSE) generates
2878 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
2879 * regardless of the state of the owner
2881 SendMessageA(pWnd->hwndSelf, WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
2882 pWnd->flags |= WIN_NEEDS_SHOW_OWNEDPOPUP;
2886 WIN_ReleaseWndPtr( pWnd );
2888 HeapFree( GetProcessHeap(), 0, win_array );
2889 return TRUE;
2893 /*******************************************************************
2894 * GetLastActivePopup (USER32.@)
2896 HWND WINAPI GetLastActivePopup( HWND hwnd )
2898 HWND retval = hwnd;
2900 SERVER_START_REQ( get_window_info )
2902 req->handle = hwnd;
2903 if (!wine_server_call_err( req )) retval = reply->last_active;
2905 SERVER_END_REQ;
2906 return retval;
2910 /*******************************************************************
2911 * WIN_ListParents
2913 * Build an array of all parents of a given window, starting with
2914 * the immediate parent. The array must be freed with HeapFree.
2915 * Returns NULL if window is a top-level window.
2917 HWND *WIN_ListParents( HWND hwnd )
2919 WND *win;
2920 HWND current, *list;
2921 int pos = 0, size = 16, count = 0;
2923 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
2925 current = hwnd;
2926 for (;;)
2928 if (!(win = WIN_GetPtr( current ))) goto empty;
2929 if (win == WND_OTHER_PROCESS) break; /* need to do it the hard way */
2930 list[pos] = win->parent;
2931 WIN_ReleasePtr( win );
2932 if (!(current = list[pos]))
2934 if (!pos) goto empty;
2935 return list;
2937 if (++pos == size - 1)
2939 /* need to grow the list */
2940 HWND *new_list = HeapReAlloc( GetProcessHeap(), 0, list, (size+16) * sizeof(HWND) );
2941 if (!new_list) goto empty;
2942 list = new_list;
2943 size += 16;
2947 /* at least one parent belongs to another process, have to query the server */
2949 for (;;)
2951 count = 0;
2952 SERVER_START_REQ( get_window_parents )
2954 req->handle = hwnd;
2955 wine_server_set_reply( req, list, (size-1) * sizeof(HWND) );
2956 if (!wine_server_call( req )) count = reply->count;
2958 SERVER_END_REQ;
2959 if (!count) goto empty;
2960 if (size > count)
2962 list[count] = 0;
2963 return list;
2965 HeapFree( GetProcessHeap(), 0, list );
2966 size = count + 1;
2967 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
2970 empty:
2971 HeapFree( GetProcessHeap(), 0, list );
2972 return NULL;
2976 /*******************************************************************
2977 * WIN_ListChildren
2979 * Build an array of the children of a given window. The array must be
2980 * freed with HeapFree. Returns NULL when no windows are found.
2982 HWND *WIN_ListChildren( HWND hwnd )
2984 return list_window_children( hwnd, 0, 0 );
2988 /*******************************************************************
2989 * EnumWindows (USER32.@)
2991 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
2993 HWND *list;
2994 BOOL ret = TRUE;
2995 int i, iWndsLocks;
2997 /* We have to build a list of all windows first, to avoid */
2998 /* unpleasant side-effects, for instance if the callback */
2999 /* function changes the Z-order of the windows. */
3001 if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
3003 /* Now call the callback function for every window */
3005 iWndsLocks = WIN_SuspendWndsLock();
3006 for (i = 0; list[i]; i++)
3008 /* Make sure that the window still exists */
3009 if (!IsWindow( list[i] )) continue;
3010 if (!(ret = lpEnumFunc( list[i], lParam ))) break;
3012 WIN_RestoreWndsLock(iWndsLocks);
3013 HeapFree( GetProcessHeap(), 0, list );
3014 return ret;
3018 /**********************************************************************
3019 * EnumThreadWindows (USER32.@)
3021 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
3023 HWND *list;
3024 int i, iWndsLocks;
3026 if (!(list = list_window_children( GetDesktopWindow(), 0, id ))) return TRUE;
3028 /* Now call the callback function for every window */
3030 iWndsLocks = WIN_SuspendWndsLock();
3031 for (i = 0; list[i]; i++)
3032 if (!func( list[i], lParam )) break;
3033 WIN_RestoreWndsLock(iWndsLocks);
3034 HeapFree( GetProcessHeap(), 0, list );
3035 return TRUE;
3039 /**********************************************************************
3040 * WIN_EnumChildWindows
3042 * Helper function for EnumChildWindows().
3044 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
3046 HWND *childList;
3047 BOOL ret = FALSE;
3049 for ( ; *list; list++)
3051 /* Make sure that the window still exists */
3052 if (!IsWindow( *list )) continue;
3053 /* skip owned windows */
3054 if (GetWindow( *list, GW_OWNER )) continue;
3055 /* Build children list first */
3056 childList = WIN_ListChildren( *list );
3058 ret = func( *list, lParam );
3060 if (childList)
3062 if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
3063 HeapFree( GetProcessHeap(), 0, childList );
3065 if (!ret) return FALSE;
3067 return TRUE;
3071 /**********************************************************************
3072 * EnumChildWindows (USER32.@)
3074 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
3076 HWND *list;
3077 int iWndsLocks;
3079 if (!(list = WIN_ListChildren( parent ))) return FALSE;
3080 iWndsLocks = WIN_SuspendWndsLock();
3081 WIN_EnumChildWindows( list, func, lParam );
3082 WIN_RestoreWndsLock(iWndsLocks);
3083 HeapFree( GetProcessHeap(), 0, list );
3084 return TRUE;
3088 /*******************************************************************
3089 * AnyPopup (USER.52)
3091 BOOL16 WINAPI AnyPopup16(void)
3093 return AnyPopup();
3097 /*******************************************************************
3098 * AnyPopup (USER32.@)
3100 BOOL WINAPI AnyPopup(void)
3102 int i;
3103 BOOL retvalue;
3104 HWND *list = WIN_ListChildren( GetDesktopWindow() );
3106 if (!list) return FALSE;
3107 for (i = 0; list[i]; i++)
3109 if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
3111 retvalue = (list[i] != 0);
3112 HeapFree( GetProcessHeap(), 0, list );
3113 return retvalue;
3117 /*******************************************************************
3118 * FlashWindow (USER32.@)
3120 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3122 WND *wndPtr = WIN_FindWndPtr(hWnd);
3124 TRACE("%p\n", hWnd);
3126 if (!wndPtr) return FALSE;
3127 hWnd = wndPtr->hwndSelf; /* make it a full handle */
3129 if (wndPtr->dwStyle & WS_MINIMIZE)
3131 if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
3133 HDC hDC = GetDC(hWnd);
3135 if (!SendMessageW( hWnd, WM_ERASEBKGND, (WPARAM)hDC, 0 ))
3136 wndPtr->flags |= WIN_NEEDS_ERASEBKGND;
3138 ReleaseDC( hWnd, hDC );
3139 wndPtr->flags |= WIN_NCACTIVATED;
3141 else
3143 RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
3144 wndPtr->flags &= ~WIN_NCACTIVATED;
3146 WIN_ReleaseWndPtr(wndPtr);
3147 return TRUE;
3149 else
3151 WPARAM16 wparam;
3152 if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3153 else wparam = (hWnd == GetForegroundWindow());
3155 WIN_ReleaseWndPtr(wndPtr);
3156 SendMessageW( hWnd, WM_NCACTIVATE, wparam, (LPARAM)0 );
3157 return wparam;
3161 /*******************************************************************
3162 * FlashWindowEx (USER32.@)
3164 BOOL WINAPI FlashWindowEx( PFLASHWINFO pfwi )
3166 FIXME("%p\n", pfwi);
3167 return TRUE;
3170 /*******************************************************************
3171 * GetWindowContextHelpId (USER32.@)
3173 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3175 DWORD retval;
3176 WND *wnd = WIN_FindWndPtr( hwnd );
3177 if (!wnd) return 0;
3178 retval = wnd->helpContext;
3179 WIN_ReleaseWndPtr(wnd);
3180 return retval;
3184 /*******************************************************************
3185 * SetWindowContextHelpId (USER32.@)
3187 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3189 WND *wnd = WIN_FindWndPtr( hwnd );
3190 if (!wnd) return FALSE;
3191 wnd->helpContext = id;
3192 WIN_ReleaseWndPtr(wnd);
3193 return TRUE;
3197 /*******************************************************************
3198 * DragDetect (USER32.@)
3200 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3202 MSG msg;
3203 RECT rect;
3205 rect.left = pt.x - wDragWidth;
3206 rect.right = pt.x + wDragWidth;
3208 rect.top = pt.y - wDragHeight;
3209 rect.bottom = pt.y + wDragHeight;
3211 SetCapture(hWnd);
3213 while(1)
3215 while(PeekMessageA(&msg ,0 ,WM_MOUSEFIRST ,WM_MOUSELAST ,PM_REMOVE))
3217 if( msg.message == WM_LBUTTONUP )
3219 ReleaseCapture();
3220 return 0;
3222 if( msg.message == WM_MOUSEMOVE )
3224 POINT tmp;
3225 tmp.x = LOWORD(msg.lParam);
3226 tmp.y = HIWORD(msg.lParam);
3227 if( !PtInRect( &rect, tmp ))
3229 ReleaseCapture();
3230 return 1;
3234 WaitMessage();
3236 return 0;
3239 /******************************************************************************
3240 * GetWindowModuleFileNameA (USER32.@)
3242 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR lpszFileName, UINT cchFileNameMax)
3244 FIXME("GetWindowModuleFileNameA(hwnd %p, lpszFileName %p, cchFileNameMax %u) stub!\n",
3245 hwnd, lpszFileName, cchFileNameMax);
3246 return 0;
3249 /******************************************************************************
3250 * GetWindowModuleFileNameW (USER32.@)
3252 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR lpszFileName, UINT cchFileNameMax)
3254 FIXME("GetWindowModuleFileNameW(hwnd %p, lpszFileName %p, cchFileNameMax %u) stub!\n",
3255 hwnd, lpszFileName, cchFileNameMax);
3256 return 0;
3259 /******************************************************************************
3260 * GetWindowInfo (USER32.@)
3262 * Note: tests show that Windows doesn't check cbSize of the structure.
3264 BOOL WINAPI GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3266 if (!pwi) return FALSE;
3267 if (!IsWindow(hwnd)) return FALSE;
3269 GetWindowRect(hwnd, &pwi->rcWindow);
3270 GetClientRect(hwnd, &pwi->rcClient);
3271 /* translate to screen coordinates */
3272 MapWindowPoints(hwnd, 0, (LPPOINT)&pwi->rcClient, 2);
3274 pwi->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
3275 pwi->dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3276 pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3278 pwi->cxWindowBorders = pwi->rcClient.left - pwi->rcWindow.left;
3279 pwi->cyWindowBorders = pwi->rcWindow.bottom - pwi->rcClient.bottom;
3281 pwi->atomWindowType = GetClassLongW( hwnd, GCW_ATOM );
3282 pwi->wCreatorVersion = 0x0400;
3284 return TRUE;
3287 /******************************************************************************
3288 * SwitchDesktop (USER32.@)
3290 * NOTES: Sets the current input or interactive desktop.
3292 BOOL WINAPI SwitchDesktop( HDESK hDesktop)
3294 FIXME("SwitchDesktop(hwnd %p) stub!\n", hDesktop);
3295 return TRUE;