A couple of optimizations.
[wine/multimedia.git] / windows / win.c
blob40db2bc68ae35760cbd414d9ba0ed7537b681a17
1 /*
2 * Window related functions
4 * Copyright 1993, 1994 Alexandre Julliard
5 */
7 #include <assert.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include "windef.h"
11 #include "wine/winbase16.h"
12 #include "wine/winuser16.h"
13 #include "wine/server.h"
14 #include "wine/unicode.h"
15 #include "win.h"
16 #include "heap.h"
17 #include "user.h"
18 #include "dce.h"
19 #include "controls.h"
20 #include "cursoricon.h"
21 #include "hook.h"
22 #include "message.h"
23 #include "queue.h"
24 #include "task.h"
25 #include "winpos.h"
26 #include "winerror.h"
27 #include "stackframe.h"
28 #include "debugtools.h"
30 DEFAULT_DEBUG_CHANNEL(win);
31 DECLARE_DEBUG_CHANNEL(msg);
33 #define NB_USER_HANDLES (LAST_USER_HANDLE - FIRST_USER_HANDLE + 1)
35 /**********************************************************************/
37 /* Desktop window */
38 static WND *pWndDesktop = NULL;
40 static WORD wDragWidth = 4;
41 static WORD wDragHeight= 3;
43 static void *user_handles[NB_USER_HANDLES];
45 /* thread safeness */
46 extern SYSLEVEL USER_SysLevel; /* FIXME */
48 /***********************************************************************
49 * WIN_SuspendWndsLock
51 * Suspend the lock on WND structures.
52 * Returns the number of locks suspended
54 int WIN_SuspendWndsLock( void )
56 int isuspendedLocks = _ConfirmSysLevel( &USER_SysLevel );
57 int count = isuspendedLocks;
59 while ( count-- > 0 )
60 _LeaveSysLevel( &USER_SysLevel );
62 return isuspendedLocks;
65 /***********************************************************************
66 * WIN_RestoreWndsLock
68 * Restore the suspended locks on WND structures
70 void WIN_RestoreWndsLock( int ipreviousLocks )
72 while ( ipreviousLocks-- > 0 )
73 _EnterSysLevel( &USER_SysLevel );
76 /***********************************************************************
77 * create_window_handle
79 * Create a window handle with the server.
81 static WND *create_window_handle( HWND parent, HWND owner, ATOM atom, INT size )
83 BOOL res;
84 user_handle_t handle = 0;
85 WORD index;
86 WND *win = HeapAlloc( GetProcessHeap(), 0, size );
88 if (!win) return NULL;
90 USER_Lock();
92 SERVER_START_REQ( create_window )
94 req->parent = parent;
95 req->owner = owner;
96 req->atom = atom;
97 if ((res = !SERVER_CALL_ERR())) handle = req->handle;
99 SERVER_END_REQ;
101 if (!res)
103 USER_Unlock();
104 HeapFree( GetProcessHeap(), 0, win );
105 return NULL;
107 index = LOWORD(handle) - FIRST_USER_HANDLE;
108 assert( index < NB_USER_HANDLES );
109 user_handles[index] = win;
110 win->hwndSelf = handle;
111 win->dwMagic = WND_MAGIC;
112 win->irefCount = 1;
113 return win;
117 /***********************************************************************
118 * free_window_handle
120 * Free a window handle.
122 static WND *free_window_handle( HWND hwnd )
124 WND *ptr;
125 WORD index = LOWORD(hwnd) - FIRST_USER_HANDLE;
127 if (index >= NB_USER_HANDLES) return NULL;
128 USER_Lock();
129 if ((ptr = user_handles[index]))
131 SERVER_START_REQ( destroy_window )
133 req->handle = hwnd;
134 if (!SERVER_CALL_ERR())
135 user_handles[index] = NULL;
136 else
137 ptr = NULL;
139 SERVER_END_REQ;
141 USER_Unlock();
142 if (ptr) HeapFree( GetProcessHeap(), 0, ptr );
143 return ptr;
147 /*******************************************************************
148 * list_window_children
150 * Build an array of the children of a given window. The array must be
151 * freed with HeapFree. Returns NULL when no windows are found.
153 static HWND *list_window_children( HWND hwnd, ATOM atom, DWORD tid )
155 HWND *list = NULL;
157 SERVER_START_VAR_REQ( get_window_children, REQUEST_MAX_VAR_SIZE )
159 req->parent = hwnd;
160 req->atom = atom;
161 req->tid = (void *)tid;
162 if (!SERVER_CALL())
164 user_handle_t *data = server_data_ptr(req);
165 int i, count = server_data_size(req) / sizeof(*data);
166 if (count && ((list = HeapAlloc( GetProcessHeap(), 0, (count + 1) * sizeof(HWND) ))))
168 for (i = 0; i < count; i++) list[i] = data[i];
169 list[i] = 0;
173 SERVER_END_VAR_REQ;
174 return list;
178 /*******************************************************************
179 * send_parent_notify
181 static void send_parent_notify( HWND hwnd, UINT msg )
183 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD)) return;
184 if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOPARENTNOTIFY) return;
185 SendMessageW( GetParent(hwnd), WM_PARENTNOTIFY,
186 MAKEWPARAM( msg, GetWindowLongW( hwnd, GWL_ID )), (LPARAM)hwnd );
190 /***********************************************************************
191 * WIN_GetPtr
193 * Return a pointer to the WND structure if local to the process,
194 * or WND_OTHER_PROCESS is handle may be valid in other process.
195 * If ret value is a valid pointer, it must be released with WIN_ReleasePtr.
197 WND *WIN_GetPtr( HWND hwnd )
199 WND * ptr;
200 WORD index = LOWORD(hwnd) - FIRST_USER_HANDLE;
202 if (index >= NB_USER_HANDLES) return NULL;
204 USER_Lock();
205 if ((ptr = user_handles[index]))
207 if (ptr->dwMagic == WND_MAGIC && (!HIWORD(hwnd) || hwnd == ptr->hwndSelf))
208 return ptr;
209 ptr = NULL;
211 else ptr = WND_OTHER_PROCESS;
212 USER_Unlock();
213 return ptr;
217 /***********************************************************************
218 * WIN_IsCurrentProcess
220 * Check whether a given window belongs to the current process (and return the full handle).
222 HWND WIN_IsCurrentProcess( HWND hwnd )
224 WND *ptr;
225 HWND ret;
227 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS) return 0;
228 ret = ptr->hwndSelf;
229 WIN_ReleasePtr( ptr );
230 return ret;
234 /***********************************************************************
235 * WIN_IsCurrentThread
237 * Check whether a given window belongs to the current thread (and return the full handle).
239 HWND WIN_IsCurrentThread( HWND hwnd )
241 WND *ptr;
242 HWND ret = 0;
244 if ((ptr = WIN_GetPtr( hwnd )) && ptr != WND_OTHER_PROCESS)
246 if (ptr->tid == GetCurrentThreadId()) ret = ptr->hwndSelf;
247 WIN_ReleasePtr( ptr );
249 return ret;
253 /***********************************************************************
254 * WIN_Handle32
256 * Convert a 16-bit window handle to a full 32-bit handle.
258 HWND WIN_Handle32( HWND16 hwnd16 )
260 WND *ptr;
261 HWND hwnd = (HWND)(ULONG_PTR)hwnd16;
263 if (hwnd16 <= 1 || hwnd16 == 0xffff) return hwnd;
264 /* do sign extension for -2 and -3 */
265 if (hwnd16 >= (HWND16)-3) return (HWND)(LONG_PTR)(INT16)hwnd16;
267 if (!(ptr = WIN_GetPtr( hwnd ))) return hwnd;
269 if (ptr != WND_OTHER_PROCESS)
271 hwnd = ptr->hwndSelf;
272 WIN_ReleasePtr( ptr );
274 else /* may belong to another process */
276 SERVER_START_REQ( get_window_info )
278 req->handle = hwnd;
279 if (!SERVER_CALL_ERR()) hwnd = req->full_handle;
281 SERVER_END_REQ;
283 return hwnd;
287 /***********************************************************************
288 * WIN_FindWndPtr
290 * Return a pointer to the WND structure corresponding to a HWND.
292 WND * WIN_FindWndPtr( HWND hwnd )
294 WND * ptr;
296 if (!hwnd) return NULL;
298 if ((ptr = WIN_GetPtr( hwnd )))
300 if (ptr != WND_OTHER_PROCESS)
302 /* increment destruction monitoring */
303 ptr->irefCount++;
304 return ptr;
306 if (IsWindow( hwnd )) /* check other processes */
308 ERR( "window %04x belongs to other process\n", hwnd );
309 /* DbgBreakPoint(); */
312 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
313 return NULL;
317 /***********************************************************************
318 * WIN_ReleaseWndPtr
320 * Release the pointer to the WND structure.
322 void WIN_ReleaseWndPtr(WND *wndPtr)
324 if(!wndPtr) return;
326 /* Decrement destruction monitoring value */
327 wndPtr->irefCount--;
328 /* Check if it's time to release the memory */
329 if(wndPtr->irefCount == 0 && !wndPtr->dwMagic)
331 /* Release memory */
332 free_window_handle( wndPtr->hwndSelf );
334 else if(wndPtr->irefCount < 0)
336 /* This else if is useful to monitor the WIN_ReleaseWndPtr function */
337 ERR("forgot a Lock on %p somewhere\n",wndPtr);
339 /* unlock all WND structures for thread safeness */
340 USER_Unlock();
344 /***********************************************************************
345 * WIN_UnlinkWindow
347 * Remove a window from the siblings linked list.
349 void WIN_UnlinkWindow( HWND hwnd )
351 WIN_LinkWindow( hwnd, 0, 0 );
355 /***********************************************************************
356 * WIN_LinkWindow
358 * Insert a window into the siblings linked list.
359 * The window is inserted after the specified window, which can also
360 * be specified as HWND_TOP or HWND_BOTTOM.
361 * If parent is 0, window is unlinked from the tree.
363 void WIN_LinkWindow( HWND hwnd, HWND parent, HWND hwndInsertAfter )
365 WND *wndPtr = WIN_GetPtr( hwnd );
367 if (!wndPtr) return;
368 if (wndPtr == WND_OTHER_PROCESS)
370 if (IsWindow(hwnd)) ERR(" cannot link other process window %x\n", hwnd );
371 return;
374 SERVER_START_REQ( link_window )
376 req->handle = hwnd;
377 req->parent = parent;
378 req->previous = hwndInsertAfter;
379 if (!SERVER_CALL())
381 if (req->full_parent && req->full_parent != wndPtr->parent)
383 wndPtr->owner = 0; /* reset owner when changing parent */
384 wndPtr->parent = req->full_parent;
389 SERVER_END_REQ;
390 WIN_ReleasePtr( wndPtr );
394 /***********************************************************************
395 * WIN_SetOwner
397 * Change the owner of a window.
399 void WIN_SetOwner( HWND hwnd, HWND owner )
401 WND *win = WIN_GetPtr( hwnd );
403 if (!win) return;
404 if (win == WND_OTHER_PROCESS)
406 if (IsWindow(hwnd)) ERR( "cannot set owner %x on other process window %x\n", owner, hwnd );
407 return;
409 SERVER_START_REQ( set_window_owner )
411 req->handle = hwnd;
412 req->owner = owner;
413 if (!SERVER_CALL()) win->owner = req->full_owner;
415 SERVER_END_REQ;
416 WIN_ReleasePtr( win );
420 /***********************************************************************
421 * WIN_SetStyle
423 * Change the style of a window.
425 LONG WIN_SetStyle( HWND hwnd, LONG style )
427 BOOL ok;
428 LONG ret = 0;
429 WND *win = WIN_GetPtr( hwnd );
431 if (!win) return 0;
432 if (win == WND_OTHER_PROCESS)
434 if (IsWindow(hwnd))
435 ERR( "cannot set style %lx on other process window %x\n", style, hwnd );
436 return 0;
438 if (style == win->dwStyle)
440 WIN_ReleasePtr( win );
441 return style;
443 SERVER_START_REQ( set_window_info )
445 req->handle = hwnd;
446 req->flags = SET_WIN_STYLE;
447 req->style = style;
448 if ((ok = !SERVER_CALL()))
450 ret = req->old_style;
451 win->dwStyle = style;
454 SERVER_END_REQ;
455 WIN_ReleasePtr( win );
456 if (ok && USER_Driver.pSetWindowStyle) USER_Driver.pSetWindowStyle( hwnd, ret );
457 return ret;
461 /***********************************************************************
462 * WIN_SetExStyle
464 * Change the extended style of a window.
466 LONG WIN_SetExStyle( HWND hwnd, LONG style )
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 exstyle %lx on other process window %x\n", style, hwnd );
476 return 0;
478 if (style == win->dwExStyle)
480 WIN_ReleasePtr( win );
481 return style;
483 SERVER_START_REQ( set_window_info )
485 req->handle = hwnd;
486 req->flags = SET_WIN_EXSTYLE;
487 req->ex_style = style;
488 if (!SERVER_CALL())
490 ret = req->old_ex_style;
491 win->dwExStyle = style;
494 SERVER_END_REQ;
495 WIN_ReleasePtr( win );
496 return ret;
500 /***********************************************************************
501 * WIN_SetRectangles
503 * Set the window and client rectangles.
505 void WIN_SetRectangles( HWND hwnd, const RECT *rectWindow, const RECT *rectClient )
507 WND *win = WIN_GetPtr( hwnd );
508 BOOL ret;
510 if (!win) return;
511 if (win == WND_OTHER_PROCESS)
513 if (IsWindow( hwnd )) ERR( "cannot set rectangles of other process window %x\n", hwnd );
514 return;
516 SERVER_START_REQ( set_window_rectangles )
518 req->handle = hwnd;
519 req->window.left = rectWindow->left;
520 req->window.top = rectWindow->top;
521 req->window.right = rectWindow->right;
522 req->window.bottom = rectWindow->bottom;
523 req->client.left = rectClient->left;
524 req->client.top = rectClient->top;
525 req->client.right = rectClient->right;
526 req->client.bottom = rectClient->bottom;
527 ret = !SERVER_CALL();
529 SERVER_END_REQ;
530 if (ret)
532 win->rectWindow = *rectWindow;
533 win->rectClient = *rectClient;
535 TRACE( "win %x window (%d,%d)-(%d,%d) client (%d,%d)-(%d,%d)\n", hwnd,
536 rectWindow->left, rectWindow->top, rectWindow->right, rectWindow->bottom,
537 rectClient->left, rectClient->top, rectClient->right, rectClient->bottom );
539 WIN_ReleasePtr( win );
543 /***********************************************************************
544 * find_child_to_repaint
546 * Find a window that needs repaint among the children of the specified window.
548 static HWND find_child_to_repaint( HWND parent )
550 int i;
551 HWND ret = 0;
552 HWND *list;
554 if (!parent) parent = GetDesktopWindow();
555 if (!(list = list_window_children( parent, 0, 0 ))) return 0;
557 for (i = 0; list[i] && !ret; i++)
559 WND *win = WIN_GetPtr( list[i] );
560 if (!win) continue; /* ignore it */
561 if (win == WND_OTHER_PROCESS)
563 /* doesn't belong to this process, but check children */
564 ret = find_child_to_repaint( list[i] );
565 continue;
567 if (!(win->dwStyle & WS_VISIBLE))
569 WIN_ReleasePtr( win );
570 continue;
572 if ((win->tid != GetCurrentThreadId()) ||
573 (!win->hrgnUpdate && !(win->flags & WIN_INTERNAL_PAINT)))
575 /* does not need repaint, check children */
576 WIN_ReleasePtr( win );
577 ret = find_child_to_repaint( list[i] );
578 continue;
581 /* now we have something */
582 ret = list[i];
583 if (!(win->dwExStyle & WS_EX_TRANSPARENT))
585 /* not transparent, we can repaint it */
586 WIN_ReleasePtr( win );
587 break;
589 WIN_ReleasePtr( win );
591 /* transparent window, look for non-transparent sibling to paint first */
592 for (i++; list[i]; i++)
594 if (!(win = WIN_GetPtr( list[i] ))) continue;
595 if (win == WND_OTHER_PROCESS) continue;
596 if (!(win->dwStyle & WS_VISIBLE))
598 WIN_ReleasePtr( win );
599 continue;
601 if (!(win->dwExStyle & WS_EX_TRANSPARENT) &&
602 (win->hrgnUpdate || (win->flags & WIN_INTERNAL_PAINT)))
604 ret = list[i];
605 WIN_ReleasePtr( win );
606 break;
608 WIN_ReleasePtr( win );
611 HeapFree( GetProcessHeap(), 0, list );
612 return ret;
616 /***********************************************************************
617 * WIN_FindWinToRepaint
619 * Find a window that needs repaint.
621 HWND WIN_FindWinToRepaint( HWND hwnd )
623 /* Note: the desktop window never gets WM_PAINT messages
624 * The real reason why is because Windows DesktopWndProc
625 * does ValidateRgn inside WM_ERASEBKGND handler.
627 if (hwnd == GetDesktopWindow()) hwnd = 0;
629 if (hwnd)
631 /* check the window itself first */
632 WND *win = WIN_FindWndPtr( hwnd );
633 if (!win) return 0;
634 if ((win->dwStyle & WS_VISIBLE) &&
635 (win->hrgnUpdate || (win->flags & WIN_INTERNAL_PAINT)))
637 WIN_ReleaseWndPtr( win );
638 return hwnd;
640 WIN_ReleaseWndPtr( win );
642 /* now check its children */
643 return find_child_to_repaint( hwnd );
647 /***********************************************************************
648 * WIN_DestroyWindow
650 * Destroy storage associated to a window. "Internals" p.358
652 LRESULT WIN_DestroyWindow( HWND hwnd )
654 WND *wndPtr;
655 HWND *list;
657 TRACE("%04x\n", hwnd );
659 if (!(hwnd = WIN_IsCurrentThread( hwnd )))
661 ERR( "window doesn't belong to current thread\n" );
662 return 0;
665 /* free child windows */
666 if ((list = WIN_ListChildren( hwnd )))
668 int i;
669 for (i = 0; list[i]; i++)
671 if (WIN_IsCurrentThread( list[i] )) WIN_DestroyWindow( list[i] );
672 else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
674 HeapFree( GetProcessHeap(), 0, list );
678 * Clear the update region to make sure no WM_PAINT messages will be
679 * generated for this window while processing the WM_NCDESTROY.
681 RedrawWindow( hwnd, NULL, 0,
682 RDW_VALIDATE | RDW_NOFRAME | RDW_NOERASE | RDW_NOINTERNALPAINT | RDW_NOCHILDREN);
685 * Send the WM_NCDESTROY to the window being destroyed.
687 SendMessageA( hwnd, WM_NCDESTROY, 0, 0);
689 /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
691 WINPOS_CheckInternalPos( hwnd );
692 if( hwnd == GetCapture()) ReleaseCapture();
694 /* free resources associated with the window */
696 TIMER_RemoveWindowTimers( hwnd );
698 if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
699 wndPtr->hmemTaskQ = 0;
701 if (!(wndPtr->dwStyle & WS_CHILD))
703 HMENU menu = (HMENU)SetWindowLongW( hwnd, GWL_ID, 0 );
704 if (menu) DestroyMenu( menu );
706 if (wndPtr->hSysMenu)
708 DestroyMenu( wndPtr->hSysMenu );
709 wndPtr->hSysMenu = 0;
711 USER_Driver.pDestroyWindow( hwnd );
712 DCE_FreeWindowDCE( hwnd ); /* Always do this to catch orphaned DCs */
713 WINPROC_FreeProc( wndPtr->winproc, WIN_PROC_WINDOW );
714 CLASS_RemoveWindow( wndPtr->class );
715 wndPtr->class = NULL;
716 wndPtr->dwMagic = 0; /* Mark it as invalid */
717 WIN_ReleaseWndPtr( wndPtr );
718 return 0;
721 /***********************************************************************
722 * WIN_DestroyThreadWindows
724 * Destroy all children of 'wnd' owned by the current thread.
725 * Return TRUE if something was done.
727 void WIN_DestroyThreadWindows( HWND hwnd )
729 HWND *list;
730 int i;
732 if (!(list = WIN_ListChildren( hwnd ))) return;
733 for (i = 0; list[i]; i++)
735 if (WIN_IsCurrentThread( list[i] ))
736 DestroyWindow( list[i] );
737 else
738 WIN_DestroyThreadWindows( list[i] );
740 HeapFree( GetProcessHeap(), 0, list );
743 /***********************************************************************
744 * WIN_CreateDesktopWindow
746 * Create the desktop window.
748 BOOL WIN_CreateDesktopWindow(void)
750 struct tagCLASS *class;
751 HWND hwndDesktop;
752 INT wndExtra;
753 DWORD clsStyle;
754 WNDPROC winproc;
755 DCE *dce;
756 CREATESTRUCTA cs;
757 RECT rect;
759 TRACE("Creating desktop window\n");
761 if (!WINPOS_CreateInternalPosAtom() ||
762 !(class = CLASS_AddWindow( (ATOM)LOWORD(DESKTOP_CLASS_ATOM), 0, WIN_PROC_32W,
763 &wndExtra, &winproc, &clsStyle, &dce )))
764 return FALSE;
766 pWndDesktop = create_window_handle( 0, 0, LOWORD(DESKTOP_CLASS_ATOM),
767 sizeof(WND) + wndExtra - sizeof(pWndDesktop->wExtra) );
768 if (!pWndDesktop) return FALSE;
769 hwndDesktop = pWndDesktop->hwndSelf;
771 pWndDesktop->tid = 0; /* nobody owns the desktop */
772 pWndDesktop->parent = 0;
773 pWndDesktop->owner = 0;
774 pWndDesktop->class = class;
775 pWndDesktop->hInstance = 0;
776 pWndDesktop->text = NULL;
777 pWndDesktop->hmemTaskQ = 0;
778 pWndDesktop->hrgnUpdate = 0;
779 pWndDesktop->hwndLastActive = hwndDesktop;
780 pWndDesktop->dwStyle = 0;
781 pWndDesktop->dwExStyle = 0;
782 pWndDesktop->clsStyle = clsStyle;
783 pWndDesktop->dce = NULL;
784 pWndDesktop->pVScroll = NULL;
785 pWndDesktop->pHScroll = NULL;
786 pWndDesktop->wIDmenu = 0;
787 pWndDesktop->helpContext = 0;
788 pWndDesktop->flags = 0;
789 pWndDesktop->hSysMenu = 0;
790 pWndDesktop->userdata = 0;
791 pWndDesktop->winproc = winproc;
792 pWndDesktop->cbWndExtra = wndExtra;
794 cs.lpCreateParams = NULL;
795 cs.hInstance = 0;
796 cs.hMenu = 0;
797 cs.hwndParent = 0;
798 cs.x = 0;
799 cs.y = 0;
800 cs.cx = GetSystemMetrics( SM_CXSCREEN );
801 cs.cy = GetSystemMetrics( SM_CYSCREEN );
802 cs.style = pWndDesktop->dwStyle;
803 cs.dwExStyle = pWndDesktop->dwExStyle;
804 cs.lpszName = NULL;
805 cs.lpszClass = DESKTOP_CLASS_ATOM;
807 SetRect( &rect, 0, 0, cs.cx, cs.cy );
808 WIN_SetRectangles( hwndDesktop, &rect, &rect );
809 WIN_SetStyle( hwndDesktop, WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS );
811 if (!USER_Driver.pCreateWindow( hwndDesktop, &cs, FALSE )) return FALSE;
813 pWndDesktop->flags |= WIN_NEEDS_ERASEBKGND;
814 WIN_ReleaseWndPtr( pWndDesktop );
815 return TRUE;
819 /***********************************************************************
820 * WIN_FixCoordinates
822 * Fix the coordinates - Helper for WIN_CreateWindowEx.
823 * returns default show mode in sw.
824 * Note: the feature presented as undocumented *is* in the MSDN since 1993.
826 static void WIN_FixCoordinates( CREATESTRUCTA *cs, INT *sw)
828 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16 ||
829 cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16)
831 if (cs->style & (WS_CHILD | WS_POPUP))
833 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16) cs->x = cs->y = 0;
834 if (cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16) cs->cx = cs->cy = 0;
836 else /* overlapped window */
838 STARTUPINFOA info;
840 GetStartupInfoA( &info );
842 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16)
844 /* Never believe Microsoft's documentation... CreateWindowEx doc says
845 * that if an overlapped window is created with WS_VISIBLE style bit
846 * set and the x parameter is set to CW_USEDEFAULT, the system ignores
847 * the y parameter. However, disassembling NT implementation (WIN32K.SYS)
848 * reveals that
850 * 1) not only it checks for CW_USEDEFAULT but also for CW_USEDEFAULT16
851 * 2) it does not ignore the y parameter as the docs claim; instead, it
852 * uses it as second parameter to ShowWindow() unless y is either
853 * CW_USEDEFAULT or CW_USEDEFAULT16.
855 * The fact that we didn't do 2) caused bogus windows pop up when wine
856 * was running apps that were using this obscure feature. Example -
857 * calc.exe that comes with Win98 (only Win98, it's different from
858 * the one that comes with Win95 and NT)
860 if (cs->y != CW_USEDEFAULT && cs->y != CW_USEDEFAULT16) *sw = cs->y;
861 cs->x = (info.dwFlags & STARTF_USEPOSITION) ? info.dwX : 0;
862 cs->y = (info.dwFlags & STARTF_USEPOSITION) ? info.dwY : 0;
865 if (cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16)
867 if (info.dwFlags & STARTF_USESIZE)
869 cs->cx = info.dwXSize;
870 cs->cy = info.dwYSize;
872 else /* if no other hint from the app, pick 3/4 of the screen real estate */
874 RECT r;
875 SystemParametersInfoA( SPI_GETWORKAREA, 0, &r, 0);
876 cs->cx = (((r.right - r.left) * 3) / 4) - cs->x;
877 cs->cy = (((r.bottom - r.top) * 3) / 4) - cs->y;
884 /***********************************************************************
885 * WIN_CreateWindowEx
887 * Implementation of CreateWindowEx().
889 static HWND WIN_CreateWindowEx( CREATESTRUCTA *cs, ATOM classAtom,
890 WINDOWPROCTYPE type )
892 INT sw = SW_SHOW;
893 struct tagCLASS *classPtr;
894 WND *wndPtr;
895 HWND hwnd, hwndLinkAfter, parent, owner;
896 INT wndExtra;
897 DWORD clsStyle;
898 WNDPROC winproc;
899 DCE *dce;
900 BOOL unicode = (type == WIN_PROC_32W);
902 TRACE("%s %s ex=%08lx style=%08lx %d,%d %dx%d parent=%04x menu=%04x inst=%08x params=%p\n",
903 (type == WIN_PROC_32W) ? debugres_w((LPWSTR)cs->lpszName) : debugres_a(cs->lpszName),
904 (type == WIN_PROC_32W) ? debugres_w((LPWSTR)cs->lpszClass) : debugres_a(cs->lpszClass),
905 cs->dwExStyle, cs->style, cs->x, cs->y, cs->cx, cs->cy,
906 cs->hwndParent, cs->hMenu, cs->hInstance, cs->lpCreateParams );
908 TRACE("winproc type is %d (%s)\n", type, (type == WIN_PROC_16) ? "WIN_PROC_16" :
909 ((type == WIN_PROC_32A) ? "WIN_PROC_32A" : "WIN_PROC_32W") );
911 /* Find the parent window */
913 parent = GetDesktopWindow();
914 owner = 0;
915 if (cs->hwndParent)
917 /* Make sure parent is valid */
918 if (!IsWindow( cs->hwndParent ))
920 WARN("Bad parent %04x\n", cs->hwndParent );
921 return 0;
923 if (cs->style & WS_CHILD) parent = WIN_GetFullHandle(cs->hwndParent);
924 else owner = GetAncestor( cs->hwndParent, GA_ROOT );
926 else if ((cs->style & WS_CHILD) && !(cs->style & WS_POPUP))
928 WARN("No parent for child window\n" );
929 return 0; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
932 /* Find the window class */
933 if (!(classPtr = CLASS_AddWindow( classAtom, cs->hInstance, type,
934 &wndExtra, &winproc, &clsStyle, &dce )))
936 WARN("Bad class '%s'\n", cs->lpszClass );
937 return 0;
940 WIN_FixCoordinates(cs, &sw); /* fix default coordinates */
942 /* Correct the window style - stage 1
944 * These are patches that appear to affect both the style loaded into the
945 * WIN structure and passed in the CreateStruct to the WM_CREATE etc.
947 * WS_EX_WINDOWEDGE appears to be enforced based on the other styles, so
948 * why does the user get to set it?
951 /* This has been tested for WS_CHILD | WS_VISIBLE. It has not been
952 * tested for WS_POPUP
954 if ((cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
955 ((!(cs->dwExStyle & WS_EX_STATICEDGE)) &&
956 (cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
957 cs->dwExStyle |= WS_EX_WINDOWEDGE;
958 else
959 cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
961 /* Create the window structure */
963 if (!(wndPtr = create_window_handle( parent, owner, classAtom,
964 sizeof(*wndPtr) + wndExtra - sizeof(wndPtr->wExtra) )))
966 TRACE("out of memory\n" );
967 return 0;
969 hwnd = wndPtr->hwndSelf;
971 /* Fill the window structure */
973 wndPtr->tid = GetCurrentThreadId();
974 wndPtr->owner = owner;
975 wndPtr->parent = parent;
976 wndPtr->class = classPtr;
977 wndPtr->winproc = winproc;
978 wndPtr->hInstance = cs->hInstance;
979 wndPtr->text = NULL;
980 wndPtr->hmemTaskQ = InitThreadInput16( 0, 0 );
981 wndPtr->hrgnUpdate = 0;
982 wndPtr->hrgnWnd = 0;
983 wndPtr->hwndLastActive = hwnd;
984 wndPtr->dwStyle = cs->style & ~WS_VISIBLE;
985 wndPtr->dwExStyle = cs->dwExStyle;
986 wndPtr->clsStyle = clsStyle;
987 wndPtr->wIDmenu = 0;
988 wndPtr->helpContext = 0;
989 wndPtr->flags = (type == WIN_PROC_16) ? 0 : WIN_ISWIN32;
990 wndPtr->pVScroll = NULL;
991 wndPtr->pHScroll = NULL;
992 wndPtr->userdata = 0;
993 wndPtr->hSysMenu = (wndPtr->dwStyle & WS_SYSMENU)
994 ? MENU_GetSysMenu( hwnd, 0 ) : 0;
995 wndPtr->cbWndExtra = wndExtra;
997 if (wndExtra) memset( wndPtr->wExtra, 0, wndExtra);
999 /* Call the WH_CBT hook */
1001 hwndLinkAfter = ((cs->style & (WS_CHILD|WS_MAXIMIZE)) == WS_CHILD)
1002 ? HWND_BOTTOM : HWND_TOP;
1004 if (HOOK_IsHooked( WH_CBT ))
1006 CBT_CREATEWNDA cbtc;
1007 LRESULT ret;
1009 cbtc.lpcs = cs;
1010 cbtc.hwndInsertAfter = hwndLinkAfter;
1011 ret = (type == WIN_PROC_32W) ? HOOK_CallHooksW(WH_CBT, HCBT_CREATEWND,
1012 (WPARAM)hwnd, (LPARAM)&cbtc)
1013 : HOOK_CallHooksA(WH_CBT, HCBT_CREATEWND,
1014 (WPARAM)hwnd, (LPARAM)&cbtc);
1015 if (ret)
1017 TRACE("CBT-hook returned 0\n");
1018 free_window_handle( hwnd );
1019 CLASS_RemoveWindow( classPtr );
1020 WIN_ReleaseWndPtr(wndPtr);
1021 return 0;
1025 /* Correct the window style - stage 2 */
1027 if (!(cs->style & WS_CHILD))
1029 wndPtr->dwStyle |= WS_CLIPSIBLINGS;
1030 if (!(cs->style & WS_POPUP))
1032 wndPtr->dwStyle |= WS_CAPTION;
1033 wndPtr->flags |= WIN_NEED_SIZE;
1036 SERVER_START_REQ( set_window_info )
1038 req->handle = hwnd;
1039 req->flags = SET_WIN_STYLE | SET_WIN_EXSTYLE | SET_WIN_INSTANCE;
1040 req->style = wndPtr->dwStyle;
1041 req->ex_style = wndPtr->dwExStyle;
1042 req->instance = (void *)wndPtr->hInstance;
1043 SERVER_CALL();
1045 SERVER_END_REQ;
1047 /* Get class or window DC if needed */
1049 if (clsStyle & CS_OWNDC) wndPtr->dce = DCE_AllocDCE(hwnd,DCE_WINDOW_DC);
1050 else if (clsStyle & CS_CLASSDC) wndPtr->dce = dce;
1051 else wndPtr->dce = NULL;
1053 /* Set the window menu */
1055 if ((wndPtr->dwStyle & (WS_CAPTION | WS_CHILD)) == WS_CAPTION )
1057 if (cs->hMenu) SetMenu(hwnd, cs->hMenu);
1058 else
1060 LPCSTR menuName = (LPCSTR)GetClassLongA( hwnd, GCL_MENUNAME );
1061 if (menuName)
1063 if (HIWORD(cs->hInstance))
1064 cs->hMenu = LoadMenuA(cs->hInstance,menuName);
1065 else
1066 cs->hMenu = LoadMenu16(cs->hInstance,menuName);
1068 if (cs->hMenu) SetMenu( hwnd, cs->hMenu );
1072 else SetWindowLongW( hwnd, GWL_ID, (UINT)cs->hMenu );
1073 WIN_ReleaseWndPtr( wndPtr );
1075 if (!USER_Driver.pCreateWindow( hwnd, cs, unicode))
1077 WIN_DestroyWindow( hwnd );
1078 return 0;
1081 /* Notify the parent window only */
1083 send_parent_notify( hwnd, WM_CREATE );
1084 if (!IsWindow( hwnd )) return 0;
1086 if (cs->style & WS_VISIBLE)
1088 /* in case WS_VISIBLE got set in the meantime */
1089 if (!(wndPtr = WIN_GetPtr( hwnd ))) return 0;
1090 WIN_SetStyle( hwnd, wndPtr->dwStyle & ~WS_VISIBLE );
1091 WIN_ReleasePtr( wndPtr );
1092 ShowWindow( hwnd, sw );
1095 /* Call WH_SHELL hook */
1097 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1098 HOOK_CallHooksA( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0 );
1100 TRACE("created window %04x\n", hwnd);
1101 return hwnd;
1105 /***********************************************************************
1106 * CreateWindow (USER.41)
1108 HWND16 WINAPI CreateWindow16( LPCSTR className, LPCSTR windowName,
1109 DWORD style, INT16 x, INT16 y, INT16 width,
1110 INT16 height, HWND16 parent, HMENU16 menu,
1111 HINSTANCE16 instance, LPVOID data )
1113 return CreateWindowEx16( 0, className, windowName, style,
1114 x, y, width, height, parent, menu, instance, data );
1118 /***********************************************************************
1119 * CreateWindowEx (USER.452)
1121 HWND16 WINAPI CreateWindowEx16( DWORD exStyle, LPCSTR className,
1122 LPCSTR windowName, DWORD style, INT16 x,
1123 INT16 y, INT16 width, INT16 height,
1124 HWND16 parent, HMENU16 menu,
1125 HINSTANCE16 instance, LPVOID data )
1127 ATOM classAtom;
1128 CREATESTRUCTA cs;
1129 char buffer[256];
1131 /* Find the class atom */
1133 if (HIWORD(className))
1135 if (!(classAtom = GlobalFindAtomA( className )))
1137 ERR( "bad class name %s\n", debugres_a(className) );
1138 return 0;
1141 else
1143 classAtom = LOWORD(className);
1144 if (!GlobalGetAtomNameA( classAtom, buffer, sizeof(buffer) ))
1146 ERR( "bad atom %x\n", classAtom);
1147 return 0;
1149 className = buffer;
1152 /* Fix the coordinates */
1154 cs.x = (x == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)x;
1155 cs.y = (y == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)y;
1156 cs.cx = (width == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)width;
1157 cs.cy = (height == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)height;
1159 /* Create the window */
1161 cs.lpCreateParams = data;
1162 cs.hInstance = (HINSTANCE)instance;
1163 cs.hMenu = (HMENU)menu;
1164 cs.hwndParent = WIN_Handle32( parent );
1165 cs.style = style;
1166 cs.lpszName = windowName;
1167 cs.lpszClass = className;
1168 cs.dwExStyle = exStyle;
1170 return WIN_Handle16( WIN_CreateWindowEx( &cs, classAtom, WIN_PROC_16 ));
1174 /***********************************************************************
1175 * CreateWindowExA (USER32.@)
1177 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1178 LPCSTR windowName, DWORD style, INT x,
1179 INT y, INT width, INT height,
1180 HWND parent, HMENU menu,
1181 HINSTANCE instance, LPVOID data )
1183 ATOM classAtom;
1184 CREATESTRUCTA cs;
1185 char buffer[256];
1187 if(!instance)
1188 instance=GetModuleHandleA(NULL);
1190 if(exStyle & WS_EX_MDICHILD)
1191 return CreateMDIWindowA(className, windowName, style, x, y, width, height, parent, instance, (LPARAM)data);
1193 /* Find the class atom */
1195 if (HIWORD(className))
1197 if (!(classAtom = GlobalFindAtomA( className )))
1199 ERR( "bad class name %s\n", debugres_a(className) );
1200 return 0;
1203 else
1205 classAtom = LOWORD(className);
1206 if (!GlobalGetAtomNameA( classAtom, buffer, sizeof(buffer) ))
1208 ERR( "bad atom %x\n", classAtom);
1209 return 0;
1211 className = buffer;
1214 /* Create the window */
1216 cs.lpCreateParams = data;
1217 cs.hInstance = instance;
1218 cs.hMenu = menu;
1219 cs.hwndParent = parent;
1220 cs.x = x;
1221 cs.y = y;
1222 cs.cx = width;
1223 cs.cy = height;
1224 cs.style = style;
1225 cs.lpszName = windowName;
1226 cs.lpszClass = className;
1227 cs.dwExStyle = exStyle;
1229 return WIN_CreateWindowEx( &cs, classAtom, WIN_PROC_32A );
1233 /***********************************************************************
1234 * CreateWindowExW (USER32.@)
1236 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1237 LPCWSTR windowName, DWORD style, INT x,
1238 INT y, INT width, INT height,
1239 HWND parent, HMENU menu,
1240 HINSTANCE instance, LPVOID data )
1242 ATOM classAtom;
1243 CREATESTRUCTW cs;
1244 WCHAR buffer[256];
1246 if(!instance)
1247 instance=GetModuleHandleA(NULL);
1249 if(exStyle & WS_EX_MDICHILD)
1250 return CreateMDIWindowW(className, windowName, style, x, y, width, height, parent, instance, (LPARAM)data);
1252 /* Find the class atom */
1254 if (HIWORD(className))
1256 if (!(classAtom = GlobalFindAtomW( className )))
1258 ERR( "bad class name %s\n", debugres_w(className) );
1259 return 0;
1262 else
1264 classAtom = LOWORD(className);
1265 if (!GlobalGetAtomNameW( classAtom, buffer, sizeof(buffer)/sizeof(WCHAR) ))
1267 ERR( "bad atom %x\n", classAtom);
1268 return 0;
1270 className = buffer;
1273 /* Create the window */
1275 cs.lpCreateParams = data;
1276 cs.hInstance = instance;
1277 cs.hMenu = menu;
1278 cs.hwndParent = parent;
1279 cs.x = x;
1280 cs.y = y;
1281 cs.cx = width;
1282 cs.cy = height;
1283 cs.style = style;
1284 cs.lpszName = windowName;
1285 cs.lpszClass = className;
1286 cs.dwExStyle = exStyle;
1288 /* Note: we rely on the fact that CREATESTRUCTA and */
1289 /* CREATESTRUCTW have the same layout. */
1290 return WIN_CreateWindowEx( (CREATESTRUCTA *)&cs, classAtom, WIN_PROC_32W );
1294 /***********************************************************************
1295 * WIN_SendDestroyMsg
1297 static void WIN_SendDestroyMsg( HWND hwnd )
1299 if( CARET_GetHwnd() == hwnd) DestroyCaret();
1300 if (USER_Driver.pResetSelectionOwner)
1301 USER_Driver.pResetSelectionOwner( hwnd, TRUE );
1304 * Send the WM_DESTROY to the window.
1306 SendMessageA( hwnd, WM_DESTROY, 0, 0);
1309 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1310 * make sure that the window still exists when we come back.
1312 if (IsWindow(hwnd))
1314 HWND* pWndArray;
1315 int i;
1317 if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1319 /* start from the end (FIXME: is this needed?) */
1320 for (i = 0; pWndArray[i]; i++) ;
1322 while (--i >= 0)
1324 if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1326 HeapFree( GetProcessHeap(), 0, pWndArray );
1328 else
1329 WARN("\tdestroyed itself while in WM_DESTROY!\n");
1333 /***********************************************************************
1334 * DestroyWindow (USER32.@)
1336 BOOL WINAPI DestroyWindow( HWND hwnd )
1338 BOOL is_child;
1339 HWND h;
1341 if (!(hwnd = WIN_IsCurrentThread( hwnd )) || (hwnd == GetDesktopWindow()))
1343 SetLastError( ERROR_ACCESS_DENIED );
1344 return FALSE;
1347 TRACE("(%04x)\n", hwnd);
1349 /* Look whether the focus is within the tree of windows we will
1350 * be destroying.
1352 h = GetFocus();
1353 if (h == hwnd || IsChild( hwnd, h ))
1355 HWND parent = GetAncestor( hwnd, GA_PARENT );
1356 if (parent == GetDesktopWindow()) parent = 0;
1357 SetFocus( parent );
1360 /* Call hooks */
1362 if( HOOK_CallHooksA( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0L) ) return FALSE;
1364 is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;
1366 if (is_child)
1368 if (!USER_IsExitingThread( GetCurrentThreadId() ))
1369 send_parent_notify( hwnd, WM_DESTROY );
1371 else if (!GetWindow( hwnd, GW_OWNER ))
1373 HOOK_CallHooksA( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L );
1374 /* FIXME: clean up palette - see "Internals" p.352 */
1377 if (!IsWindow(hwnd)) return TRUE;
1379 if (USER_Driver.pResetSelectionOwner)
1380 USER_Driver.pResetSelectionOwner( hwnd, FALSE ); /* before the window is unmapped */
1382 /* Hide the window */
1384 ShowWindow( hwnd, SW_HIDE );
1385 if (!IsWindow(hwnd)) return TRUE;
1387 /* Recursively destroy owned windows */
1389 if (!is_child)
1391 HWND owner;
1393 for (;;)
1395 int i, got_one = 0;
1396 HWND *list = WIN_ListChildren( GetDesktopWindow() );
1397 if (list)
1399 for (i = 0; list[i]; i++)
1401 if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1402 if (WIN_IsCurrentThread( list[i] ))
1404 DestroyWindow( list[i] );
1405 got_one = 1;
1406 continue;
1408 WIN_SetOwner( list[i], 0 );
1410 HeapFree( GetProcessHeap(), 0, list );
1412 if (!got_one) break;
1415 WINPOS_ActivateOtherWindow( hwnd );
1417 if ((owner = GetWindow( hwnd, GW_OWNER )))
1419 WND *ptr = WIN_FindWndPtr( owner );
1420 if (ptr)
1422 if (ptr->hwndLastActive == hwnd) ptr->hwndLastActive = owner;
1423 WIN_ReleaseWndPtr( ptr );
1428 /* Send destroy messages */
1430 WIN_SendDestroyMsg( hwnd );
1431 if (!IsWindow( hwnd )) return TRUE;
1433 /* Unlink now so we won't bother with the children later on */
1435 WIN_UnlinkWindow( hwnd );
1437 /* Destroy the window storage */
1439 WIN_DestroyWindow( hwnd );
1440 return TRUE;
1444 /***********************************************************************
1445 * CloseWindow (USER32.@)
1447 BOOL WINAPI CloseWindow( HWND hwnd )
1449 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1450 ShowWindow( hwnd, SW_MINIMIZE );
1451 return TRUE;
1455 /***********************************************************************
1456 * OpenIcon (USER32.@)
1458 BOOL WINAPI OpenIcon( HWND hwnd )
1460 if (!IsIconic( hwnd )) return FALSE;
1461 ShowWindow( hwnd, SW_SHOWNORMAL );
1462 return TRUE;
1466 /***********************************************************************
1467 * WIN_FindWindow
1469 * Implementation of FindWindow() and FindWindowEx().
1471 static HWND WIN_FindWindow( HWND parent, HWND child, ATOM className, LPCWSTR title )
1473 HWND *list = NULL;
1474 HWND retvalue = 0;
1475 int i = 0, len = 0;
1476 WCHAR *buffer = NULL;
1478 if (!parent) parent = GetDesktopWindow();
1479 if (title)
1481 len = strlenW(title) + 1; /* one extra char to check for chars beyond the end */
1482 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1485 if (!(list = list_window_children( parent, className, 0 ))) goto done;
1487 if (child)
1489 child = WIN_GetFullHandle( child );
1490 while (list[i] && list[i] != child) i++;
1491 if (!list[i]) goto done;
1492 i++; /* start from next window */
1495 if (title)
1497 while (list[i])
1499 if (GetWindowTextW( list[i], buffer, len ) && !strcmpiW( buffer, title )) break;
1500 i++;
1503 retvalue = list[i];
1505 done:
1506 if (list) HeapFree( GetProcessHeap(), 0, list );
1507 if (buffer) HeapFree( GetProcessHeap(), 0, buffer );
1508 return retvalue;
1513 /***********************************************************************
1514 * FindWindowA (USER32.@)
1516 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1518 HWND ret = FindWindowExA( 0, 0, className, title );
1519 if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1520 return ret;
1524 /***********************************************************************
1525 * FindWindowExA (USER32.@)
1527 HWND WINAPI FindWindowExA( HWND parent, HWND child,
1528 LPCSTR className, LPCSTR title )
1530 ATOM atom = 0;
1531 LPWSTR buffer;
1532 HWND hwnd;
1534 if (className)
1536 /* If the atom doesn't exist, then no class */
1537 /* with this name exists either. */
1538 if (!(atom = GlobalFindAtomA( className )))
1540 SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1541 return 0;
1545 buffer = HEAP_strdupAtoW( GetProcessHeap(), 0, title );
1546 hwnd = WIN_FindWindow( parent, child, atom, buffer );
1547 HeapFree( GetProcessHeap(), 0, buffer );
1548 return hwnd;
1552 /***********************************************************************
1553 * FindWindowExW (USER32.@)
1555 HWND WINAPI FindWindowExW( HWND parent, HWND child,
1556 LPCWSTR className, LPCWSTR title )
1558 ATOM atom = 0;
1560 if (className)
1562 /* If the atom doesn't exist, then no class */
1563 /* with this name exists either. */
1564 if (!(atom = GlobalFindAtomW( className )))
1566 SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1567 return 0;
1570 return WIN_FindWindow( parent, child, atom, title );
1574 /***********************************************************************
1575 * FindWindowW (USER32.@)
1577 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
1579 return FindWindowExW( 0, 0, className, title );
1583 /**********************************************************************
1584 * GetDesktopWindow (USER32.@)
1586 HWND WINAPI GetDesktopWindow(void)
1588 if (pWndDesktop) return pWndDesktop->hwndSelf;
1589 ERR( "You need the -desktop option when running with native USER\n" );
1590 ExitProcess(1);
1591 return 0;
1595 /*******************************************************************
1596 * EnableWindow (USER32.@)
1598 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
1600 WND *wndPtr;
1601 BOOL retvalue;
1602 LONG style;
1603 HWND full_handle;
1605 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
1606 return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
1608 hwnd = full_handle;
1610 TRACE("( %x, %d )\n", hwnd, enable);
1612 if (!(wndPtr = WIN_GetPtr( hwnd ))) return FALSE;
1613 style = wndPtr->dwStyle;
1614 retvalue = ((style & WS_DISABLED) != 0);
1615 WIN_ReleasePtr( wndPtr );
1617 if (enable && retvalue)
1619 WIN_SetStyle( hwnd, style & ~WS_DISABLED );
1620 SendMessageA( hwnd, WM_ENABLE, TRUE, 0 );
1622 else if (!enable && !retvalue)
1624 SendMessageA( hwnd, WM_CANCELMODE, 0, 0);
1626 WIN_SetStyle( hwnd, style | WS_DISABLED );
1628 if (hwnd == GetFocus())
1629 SetFocus( 0 ); /* A disabled window can't have the focus */
1631 if (hwnd == GetCapture())
1632 ReleaseCapture(); /* A disabled window can't capture the mouse */
1634 SendMessageA( hwnd, WM_ENABLE, FALSE, 0 );
1636 return retvalue;
1640 /***********************************************************************
1641 * IsWindowEnabled (USER32.@)
1643 BOOL WINAPI IsWindowEnabled(HWND hWnd)
1645 return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
1649 /***********************************************************************
1650 * IsWindowUnicode (USER32.@)
1652 BOOL WINAPI IsWindowUnicode( HWND hwnd )
1654 WND * wndPtr;
1655 BOOL retvalue;
1657 if (!(wndPtr = WIN_FindWndPtr(hwnd))) return FALSE;
1658 retvalue = (WINPROC_GetProcType( wndPtr->winproc ) == WIN_PROC_32W);
1659 WIN_ReleaseWndPtr(wndPtr);
1660 return retvalue;
1664 /**********************************************************************
1665 * GetWindowWord (USER32.@)
1667 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
1669 if (offset >= 0)
1671 WORD retvalue = 0;
1672 WND *wndPtr = WIN_GetPtr( hwnd );
1673 if (!wndPtr)
1675 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1676 return 0;
1678 if (wndPtr == WND_OTHER_PROCESS)
1680 if (IsWindow( hwnd ))
1681 FIXME( "(%d) not supported yet on other process window %x\n", offset, hwnd );
1682 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1683 return 0;
1685 if (offset > wndPtr->cbWndExtra - sizeof(WORD))
1687 WARN("Invalid offset %d\n", offset );
1688 SetLastError( ERROR_INVALID_INDEX );
1690 else retvalue = *(WORD *)(((char *)wndPtr->wExtra) + offset);
1691 WIN_ReleasePtr( wndPtr );
1692 return retvalue;
1695 switch(offset)
1697 case GWL_HWNDPARENT:
1698 return GetWindowLongW( hwnd, offset );
1699 case GWL_ID:
1700 case GWL_HINSTANCE:
1702 LONG ret = GetWindowLongW( hwnd, offset );
1703 if (HIWORD(ret))
1704 WARN("%d: discards high bits of 0x%08lx!\n", offset, ret );
1705 return LOWORD(ret);
1707 default:
1708 WARN("Invalid offset %d\n", offset );
1709 return 0;
1714 /**********************************************************************
1715 * SetWindowWord (USER32.@)
1717 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
1719 WORD *ptr, retval;
1720 WND * wndPtr;
1722 switch(offset)
1724 case GWL_ID:
1725 case GWL_HINSTANCE:
1726 case GWL_HWNDPARENT:
1727 return SetWindowLongW( hwnd, offset, (UINT)newval );
1728 default:
1729 if (offset < 0)
1731 WARN("Invalid offset %d\n", offset );
1732 SetLastError( ERROR_INVALID_INDEX );
1733 return 0;
1737 wndPtr = WIN_GetPtr( hwnd );
1738 if (wndPtr == WND_OTHER_PROCESS)
1740 if (IsWindow(hwnd))
1741 FIXME( "set %d <- %x not supported yet on other process window %x\n",
1742 offset, newval, hwnd );
1743 wndPtr = NULL;
1745 if (!wndPtr)
1747 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1748 return 0;
1751 if (offset > wndPtr->cbWndExtra - sizeof(WORD))
1753 WARN("Invalid offset %d\n", offset );
1754 WIN_ReleasePtr(wndPtr);
1755 SetLastError( ERROR_INVALID_INDEX );
1756 return 0;
1758 ptr = (WORD *)(((char *)wndPtr->wExtra) + offset);
1759 retval = *ptr;
1760 *ptr = newval;
1761 WIN_ReleasePtr(wndPtr);
1762 return retval;
1766 /**********************************************************************
1767 * WIN_GetWindowLong
1769 * Helper function for GetWindowLong().
1771 static LONG WIN_GetWindowLong( HWND hwnd, INT offset, WINDOWPROCTYPE type )
1773 LONG retvalue = 0;
1774 WND *wndPtr;
1776 if (offset == GWL_HWNDPARENT) return (LONG)GetParent( hwnd );
1778 if (!(wndPtr = WIN_GetPtr( hwnd )))
1780 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1781 return 0;
1784 if (wndPtr == WND_OTHER_PROCESS)
1786 if (offset >= 0)
1788 FIXME( "(%d) not supported on other process window %x\n", offset, hwnd );
1789 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1790 return 0;
1792 if (offset == GWL_WNDPROC)
1794 SetLastError( ERROR_ACCESS_DENIED );
1795 return 0;
1797 SERVER_START_REQ( set_window_info )
1799 req->handle = hwnd;
1800 req->flags = 0; /* don't set anything, just retrieve */
1801 if (!SERVER_CALL_ERR())
1803 switch(offset)
1805 case GWL_STYLE: retvalue = req->style; break;
1806 case GWL_EXSTYLE: retvalue = req->ex_style; break;
1807 case GWL_ID: retvalue = req->id; break;
1808 case GWL_HINSTANCE: retvalue = (ULONG_PTR)req->instance; break;
1809 case GWL_USERDATA: retvalue = (ULONG_PTR)req->user_data; break;
1810 default:
1811 SetLastError( ERROR_INVALID_INDEX );
1812 break;
1816 SERVER_END_REQ;
1817 return retvalue;
1820 /* now we have a valid wndPtr */
1822 if (offset >= 0)
1824 if (offset > wndPtr->cbWndExtra - sizeof(LONG))
1826 WARN("Invalid offset %d\n", offset );
1827 WIN_ReleasePtr( wndPtr );
1828 SetLastError( ERROR_INVALID_INDEX );
1829 return 0;
1831 /* Special case for dialog window procedure */
1832 if ((offset == DWL_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
1833 retvalue = (LONG)WINPROC_GetProc( (HWINDOWPROC)retvalue, type );
1834 else
1835 retvalue = *(LONG *)(((char *)wndPtr->wExtra) + offset);
1836 WIN_ReleasePtr( wndPtr );
1837 return retvalue;
1840 switch(offset)
1842 case GWL_USERDATA: retvalue = wndPtr->userdata; break;
1843 case GWL_STYLE: retvalue = wndPtr->dwStyle; break;
1844 case GWL_EXSTYLE: retvalue = wndPtr->dwExStyle; break;
1845 case GWL_ID: retvalue = (LONG)wndPtr->wIDmenu; break;
1846 case GWL_WNDPROC: retvalue = (LONG)WINPROC_GetProc( wndPtr->winproc, type ); break;
1847 case GWL_HINSTANCE: retvalue = wndPtr->hInstance; break;
1848 default:
1849 WARN("Unknown offset %d\n", offset );
1850 SetLastError( ERROR_INVALID_INDEX );
1851 break;
1853 WIN_ReleasePtr(wndPtr);
1854 return retvalue;
1858 /**********************************************************************
1859 * WIN_SetWindowLong
1861 * Helper function for SetWindowLong().
1863 * 0 is the failure code. However, in the case of failure SetLastError
1864 * must be set to distinguish between a 0 return value and a failure.
1866 static LONG WIN_SetWindowLong( HWND hwnd, INT offset, LONG newval,
1867 WINDOWPROCTYPE type )
1869 LONG retval = 0;
1870 WND *wndPtr;
1872 TRACE( "%x %d %lx %x\n", hwnd, offset, newval, type );
1874 if (!WIN_IsCurrentProcess( hwnd ))
1876 if (offset == GWL_WNDPROC)
1878 SetLastError( ERROR_ACCESS_DENIED );
1879 return 0;
1881 return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, offset, newval );
1884 wndPtr = WIN_GetPtr( hwnd );
1886 if (offset >= 0)
1888 LONG *ptr = (LONG *)(((char *)wndPtr->wExtra) + offset);
1889 if (offset > wndPtr->cbWndExtra - sizeof(LONG))
1891 WARN("Invalid offset %d\n", offset );
1892 WIN_ReleasePtr( wndPtr );
1893 SetLastError( ERROR_INVALID_INDEX );
1894 return 0;
1896 /* Special case for dialog window procedure */
1897 if ((offset == DWL_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
1899 retval = (LONG)WINPROC_GetProc( (HWINDOWPROC)*ptr, type );
1900 WINPROC_SetProc( (HWINDOWPROC *)ptr, (WNDPROC16)newval,
1901 type, WIN_PROC_WINDOW );
1902 WIN_ReleasePtr( wndPtr );
1903 return retval;
1905 retval = *ptr;
1906 *ptr = newval;
1907 WIN_ReleasePtr( wndPtr );
1909 else
1911 STYLESTRUCT style;
1912 BOOL ok;
1914 /* first some special cases */
1915 switch( offset )
1917 case GWL_STYLE:
1918 case GWL_EXSTYLE:
1919 style.styleOld = wndPtr->dwStyle;
1920 style.styleNew = newval;
1921 WIN_ReleasePtr( wndPtr );
1922 SendMessageW( hwnd, WM_STYLECHANGING, offset, (LPARAM)&style );
1923 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
1924 newval = style.styleNew;
1925 break;
1926 case GWL_HWNDPARENT:
1927 WIN_ReleasePtr( wndPtr );
1928 return (LONG)SetParent( hwnd, (HWND)newval );
1929 case GWL_WNDPROC:
1930 retval = (LONG)WINPROC_GetProc( wndPtr->winproc, type );
1931 WINPROC_SetProc( &wndPtr->winproc, (WNDPROC16)newval,
1932 type, WIN_PROC_WINDOW );
1933 WIN_ReleasePtr( wndPtr );
1934 return retval;
1935 case GWL_ID:
1936 case GWL_HINSTANCE:
1937 case GWL_USERDATA:
1938 break;
1939 default:
1940 WIN_ReleasePtr( wndPtr );
1941 WARN("Invalid offset %d\n", offset );
1942 SetLastError( ERROR_INVALID_INDEX );
1943 return 0;
1946 SERVER_START_REQ( set_window_info )
1948 req->handle = hwnd;
1949 switch(offset)
1951 case GWL_STYLE:
1952 req->flags = SET_WIN_STYLE;
1953 req->style = newval;
1954 break;
1955 case GWL_EXSTYLE:
1956 req->flags = SET_WIN_EXSTYLE;
1957 req->ex_style = newval;
1958 break;
1959 case GWL_ID:
1960 req->flags = SET_WIN_ID;
1961 req->id = newval;
1962 break;
1963 case GWL_HINSTANCE:
1964 req->flags = SET_WIN_INSTANCE;
1965 req->instance = (void *)newval;
1966 break;
1967 case GWL_USERDATA:
1968 req->flags = SET_WIN_USERDATA;
1969 req->user_data = (void *)newval;
1970 break;
1972 if ((ok = !SERVER_CALL_ERR()))
1974 switch(offset)
1976 case GWL_STYLE:
1977 wndPtr->dwStyle = newval;
1978 retval = req->old_style;
1979 break;
1980 case GWL_EXSTYLE:
1981 wndPtr->dwExStyle = newval;
1982 retval = req->old_ex_style;
1983 break;
1984 case GWL_ID:
1985 wndPtr->wIDmenu = newval;
1986 retval = req->old_id;
1987 break;
1988 case GWL_HINSTANCE:
1989 wndPtr->hInstance = newval;
1990 retval = (HINSTANCE)req->old_instance;
1991 break;
1992 case GWL_USERDATA:
1993 wndPtr->userdata = newval;
1994 retval = (ULONG_PTR)req->old_user_data;
1995 break;
1999 SERVER_END_REQ;
2000 WIN_ReleasePtr( wndPtr );
2002 if (!ok) return 0;
2004 if (offset == GWL_STYLE && USER_Driver.pSetWindowStyle)
2005 USER_Driver.pSetWindowStyle( hwnd, retval );
2007 if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2008 SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2011 return retval;
2015 /**********************************************************************
2016 * GetWindowLong (USER.135)
2018 LONG WINAPI GetWindowLong16( HWND16 hwnd, INT16 offset )
2020 return WIN_GetWindowLong( WIN_Handle32(hwnd), offset, WIN_PROC_16 );
2024 /**********************************************************************
2025 * GetWindowLongA (USER32.@)
2027 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2029 return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32A );
2033 /**********************************************************************
2034 * GetWindowLongW (USER32.@)
2036 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2038 return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32W );
2042 /**********************************************************************
2043 * SetWindowLong (USER.136)
2045 LONG WINAPI SetWindowLong16( HWND16 hwnd, INT16 offset, LONG newval )
2047 return WIN_SetWindowLong( WIN_Handle32(hwnd), offset, newval, WIN_PROC_16 );
2051 /**********************************************************************
2052 * SetWindowLongA (USER32.@)
2054 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2056 return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32A );
2060 /**********************************************************************
2061 * SetWindowLongW (USER32.@) Set window attribute
2063 * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2064 * value in a window's extra memory.
2066 * The _hwnd_ parameter specifies the window. is the handle to a
2067 * window that has extra memory. The _newval_ parameter contains the
2068 * new attribute or extra memory value. If positive, the _offset_
2069 * parameter is the byte-addressed location in the window's extra
2070 * memory to set. If negative, _offset_ specifies the window
2071 * attribute to set, and should be one of the following values:
2073 * GWL_EXSTYLE The window's extended window style
2075 * GWL_STYLE The window's window style.
2077 * GWL_WNDPROC Pointer to the window's window procedure.
2079 * GWL_HINSTANCE The window's pplication instance handle.
2081 * GWL_ID The window's identifier.
2083 * GWL_USERDATA The window's user-specified data.
2085 * If the window is a dialog box, the _offset_ parameter can be one of
2086 * the following values:
2088 * DWL_DLGPROC The address of the window's dialog box procedure.
2090 * DWL_MSGRESULT The return value of a message
2091 * that the dialog box procedure processed.
2093 * DWL_USER Application specific information.
2095 * RETURNS
2097 * If successful, returns the previous value located at _offset_. Otherwise,
2098 * returns 0.
2100 * NOTES
2102 * Extra memory for a window class is specified by a nonzero cbWndExtra
2103 * parameter of the WNDCLASS structure passed to RegisterClass() at the
2104 * time of class creation.
2106 * Using GWL_WNDPROC to set a new window procedure effectively creates
2107 * a window subclass. Use CallWindowProc() in the new windows procedure
2108 * to pass messages to the superclass's window procedure.
2110 * The user data is reserved for use by the application which created
2111 * the window.
2113 * Do not use GWL_STYLE to change the window's WS_DISABLE style;
2114 * instead, call the EnableWindow() function to change the window's
2115 * disabled state.
2117 * Do not use GWL_HWNDPARENT to reset the window's parent, use
2118 * SetParent() instead.
2120 * Win95:
2121 * When offset is GWL_STYLE and the calling app's ver is 4.0,
2122 * it sends WM_STYLECHANGING before changing the settings
2123 * and WM_STYLECHANGED afterwards.
2124 * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2126 LONG WINAPI SetWindowLongW(
2127 HWND hwnd, /* [in] window to alter */
2128 INT offset, /* [in] offset, in bytes, of location to alter */
2129 LONG newval /* [in] new value of location */
2131 return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32W );
2135 /*******************************************************************
2136 * GetWindowTextA (USER32.@)
2138 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2140 return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount,
2141 (LPARAM)lpString );
2144 /*******************************************************************
2145 * InternalGetWindowText (USER32.@)
2147 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2149 WND *win = WIN_FindWndPtr( hwnd );
2150 if (!win) return 0;
2151 if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2152 else lpString[0] = 0;
2153 WIN_ReleaseWndPtr( win );
2154 return strlenW(lpString);
2158 /*******************************************************************
2159 * GetWindowTextW (USER32.@)
2161 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2163 return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount,
2164 (LPARAM)lpString );
2168 /*******************************************************************
2169 * SetWindowText (USER32.@)
2170 * SetWindowTextA (USER32.@)
2172 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2174 return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2178 /*******************************************************************
2179 * SetWindowTextW (USER32.@)
2181 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2183 return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2187 /*******************************************************************
2188 * GetWindowTextLengthA (USER32.@)
2190 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2192 return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2195 /*******************************************************************
2196 * GetWindowTextLengthW (USER32.@)
2198 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2200 return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2204 /*******************************************************************
2205 * IsWindow (USER32.@)
2207 BOOL WINAPI IsWindow( HWND hwnd )
2209 WND *ptr;
2210 BOOL ret;
2212 if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2214 if (ptr != WND_OTHER_PROCESS)
2216 WIN_ReleasePtr( ptr );
2217 return TRUE;
2220 /* check other processes */
2221 SERVER_START_REQ( get_window_info )
2223 req->handle = hwnd;
2224 ret = !SERVER_CALL_ERR();
2226 SERVER_END_REQ;
2227 return ret;
2231 /***********************************************************************
2232 * GetWindowThreadProcessId (USER32.@)
2234 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2236 WND *ptr;
2237 DWORD tid = 0;
2239 if (!(ptr = WIN_GetPtr( hwnd )))
2241 SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2242 return 0;
2245 if (ptr != WND_OTHER_PROCESS)
2247 /* got a valid window */
2248 tid = ptr->tid;
2249 if (process) *process = GetCurrentProcessId();
2250 WIN_ReleasePtr( ptr );
2251 return tid;
2254 /* check other processes */
2255 SERVER_START_REQ( get_window_info )
2257 req->handle = hwnd;
2258 if (!SERVER_CALL_ERR())
2260 tid = (DWORD)req->tid;
2261 if (process) *process = (DWORD)req->pid;
2264 SERVER_END_REQ;
2265 return tid;
2269 /*****************************************************************
2270 * GetParent (USER32.@)
2272 HWND WINAPI GetParent( HWND hwnd )
2274 WND *wndPtr;
2275 HWND retvalue = 0;
2277 if (!(wndPtr = WIN_GetPtr( hwnd )))
2279 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2280 return 0;
2282 if (wndPtr == WND_OTHER_PROCESS)
2284 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2285 if (style & (WS_POPUP | WS_CHILD))
2287 SERVER_START_REQ( get_window_tree )
2289 req->handle = hwnd;
2290 if (!SERVER_CALL_ERR())
2292 if (style & WS_CHILD) retvalue = req->parent;
2293 else retvalue = req->owner;
2296 SERVER_END_REQ;
2299 else
2301 if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2302 else if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2303 WIN_ReleasePtr( wndPtr );
2305 return retvalue;
2309 /*****************************************************************
2310 * GetAncestor (USER32.@)
2312 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2314 WND *win;
2315 HWND ret = 0;
2316 size_t size;
2318 for (;;)
2320 if (!(win = WIN_GetPtr( hwnd )))
2322 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2323 return 0;
2325 if (win == WND_OTHER_PROCESS) break; /* need to do it the hard way */
2326 ret = win->parent;
2327 WIN_ReleasePtr( win );
2328 if (type == GA_PARENT) return ret;
2329 if (!ret || ret == GetDesktopWindow())
2331 ret = hwnd; /* if ret is the desktop, hwnd is the root ancestor */
2332 goto done;
2334 hwnd = ret; /* restart with parent as hwnd */
2337 size = (type == GA_PARENT) ? sizeof(user_handle_t) : REQUEST_MAX_VAR_SIZE;
2339 SERVER_START_VAR_REQ( get_window_parents, size )
2341 req->handle = hwnd;
2342 if (!SERVER_CALL())
2344 user_handle_t *data = server_data_ptr(req);
2345 int count = server_data_size(req) / sizeof(*data);
2346 if (count)
2348 switch(type)
2350 case GA_PARENT:
2351 ret = data[0];
2352 break;
2353 case GA_ROOT:
2354 case GA_ROOTOWNER:
2355 if (count > 1) ret = data[count - 2]; /* get the one before the desktop */
2356 else ret = WIN_GetFullHandle( hwnd );
2357 break;
2362 SERVER_END_VAR_REQ;
2364 done:
2365 if (ret && type == GA_ROOTOWNER)
2367 for (;;)
2369 HWND owner = GetWindow( ret, GW_OWNER );
2370 if (!owner) break;
2371 ret = owner;
2374 return ret;
2378 /*****************************************************************
2379 * SetParent (USER32.@)
2381 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2383 WND *wndPtr;
2384 HWND retvalue, full_handle;
2385 BOOL was_visible;
2387 if (!parent) parent = GetDesktopWindow();
2388 else parent = WIN_GetFullHandle( parent );
2390 if (!IsWindow( parent ))
2392 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2393 return 0;
2396 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2397 return SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2399 hwnd = full_handle;
2401 if (USER_Driver.pSetParent)
2402 return USER_Driver.pSetParent( hwnd, parent );
2404 /* Windows hides the window first, then shows it again
2405 * including the WM_SHOWWINDOW messages and all */
2406 was_visible = ShowWindow( hwnd, SW_HIDE );
2408 if (!IsWindow( parent )) return 0;
2409 if (!(wndPtr = WIN_GetPtr(hwnd)) || wndPtr == WND_OTHER_PROCESS) return 0;
2411 retvalue = wndPtr->parent; /* old parent */
2412 if (parent != retvalue)
2414 WIN_LinkWindow( hwnd, parent, HWND_TOP );
2416 if (parent != GetDesktopWindow()) /* a child window */
2418 if (!(wndPtr->dwStyle & WS_CHILD))
2420 HMENU menu = (HMENU)SetWindowLongW( hwnd, GWL_ID, 0 );
2421 if (menu) DestroyMenu( menu );
2425 WIN_ReleasePtr( wndPtr );
2427 /* SetParent additionally needs to make hwnd the topmost window
2428 in the x-order and send the expected WM_WINDOWPOSCHANGING and
2429 WM_WINDOWPOSCHANGED notification messages.
2431 SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0,
2432 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | (was_visible ? SWP_SHOWWINDOW : 0) );
2433 /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
2434 * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
2435 return retvalue;
2439 /*******************************************************************
2440 * IsChild (USER32.@)
2442 BOOL WINAPI IsChild( HWND parent, HWND child )
2444 HWND *list = WIN_ListParents( child );
2445 int i;
2446 BOOL ret;
2448 if (!list) return FALSE;
2449 parent = WIN_GetFullHandle( parent );
2450 for (i = 0; list[i]; i++) if (list[i] == parent) break;
2451 ret = (list[i] != 0);
2452 HeapFree( GetProcessHeap(), 0, list );
2453 return ret;
2457 /***********************************************************************
2458 * IsWindowVisible (USER32.@)
2460 BOOL WINAPI IsWindowVisible( HWND hwnd )
2462 HWND *list;
2463 BOOL retval;
2464 int i;
2466 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2467 if (!(list = WIN_ListParents( hwnd ))) return TRUE;
2468 for (i = 0; list[i]; i++)
2469 if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2470 retval = !list[i];
2471 HeapFree( GetProcessHeap(), 0, list );
2472 return retval;
2476 /***********************************************************************
2477 * WIN_IsWindowDrawable
2479 * hwnd is drawable when it is visible, all parents are not
2480 * minimized, and it is itself not minimized unless we are
2481 * trying to draw its default class icon.
2483 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2485 HWND *list;
2486 BOOL retval;
2487 int i;
2488 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2490 if (!(style & WS_VISIBLE)) return FALSE;
2491 if ((style & WS_MINIMIZE) && icon && GetClassLongA( hwnd, GCL_HICON )) return FALSE;
2493 if (!(list = WIN_ListParents( hwnd ))) return TRUE;
2494 for (i = 0; list[i]; i++)
2495 if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2496 break;
2497 retval = !list[i];
2498 HeapFree( GetProcessHeap(), 0, list );
2499 return retval;
2503 /*******************************************************************
2504 * GetTopWindow (USER32.@)
2506 HWND WINAPI GetTopWindow( HWND hwnd )
2508 if (!hwnd) hwnd = GetDesktopWindow();
2509 return GetWindow( hwnd, GW_CHILD );
2513 /*******************************************************************
2514 * GetWindow (USER32.@)
2516 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2518 HWND retval = 0;
2520 if (rel == GW_OWNER) /* this one may be available locally */
2522 WND *wndPtr = WIN_GetPtr( hwnd );
2523 if (!wndPtr)
2525 SetLastError( ERROR_INVALID_HANDLE );
2526 return 0;
2528 if (wndPtr != WND_OTHER_PROCESS)
2530 retval = wndPtr->owner;
2531 WIN_ReleasePtr( wndPtr );
2532 return retval;
2534 /* else fall through to server call */
2537 SERVER_START_REQ( get_window_tree )
2539 req->handle = hwnd;
2540 if (!SERVER_CALL_ERR())
2542 switch(rel)
2544 case GW_HWNDFIRST:
2545 retval = req->first_sibling;
2546 break;
2547 case GW_HWNDLAST:
2548 retval = req->last_sibling;
2549 break;
2550 case GW_HWNDNEXT:
2551 retval = req->next_sibling;
2552 break;
2553 case GW_HWNDPREV:
2554 retval = req->prev_sibling;
2555 break;
2556 case GW_OWNER:
2557 retval = req->owner;
2558 break;
2559 case GW_CHILD:
2560 retval = req->first_child;
2561 break;
2565 SERVER_END_REQ;
2566 return retval;
2570 /***********************************************************************
2571 * WIN_InternalShowOwnedPopups
2573 * Internal version of ShowOwnedPopups; Wine functions should use this
2574 * to avoid interfering with application calls to ShowOwnedPopups
2575 * and to make sure the application can't prevent showing/hiding.
2577 * Set unmanagedOnly to TRUE to show/hide unmanaged windows only.
2581 BOOL WIN_InternalShowOwnedPopups( HWND owner, BOOL fShow, BOOL unmanagedOnly )
2583 int count = 0;
2584 WND *pWnd;
2585 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2587 if (!win_array) return TRUE;
2590 * Show windows Lowest first, Highest last to preserve Z-Order
2592 while (win_array[count]) count++;
2593 while (--count >= 0)
2595 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2596 if (!(pWnd = WIN_FindWndPtr( win_array[count] ))) continue;
2598 if (pWnd->dwStyle & WS_POPUP)
2600 if (fShow)
2602 /* check in window was flagged for showing in previous WIN_InternalShowOwnedPopups call */
2603 if (pWnd->flags & WIN_NEEDS_INTERNALSOP)
2606 * Call ShowWindow directly because an application can intercept WM_SHOWWINDOW messages
2608 ShowWindow(pWnd->hwndSelf,SW_SHOW);
2609 pWnd->flags &= ~WIN_NEEDS_INTERNALSOP; /* remove the flag */
2612 else
2614 if ( IsWindowVisible(pWnd->hwndSelf) && /* hide only if window is visible */
2615 !( pWnd->flags & WIN_NEEDS_INTERNALSOP ) && /* don't hide if previous call already did it */
2616 !( unmanagedOnly && (pWnd->dwExStyle & WS_EX_MANAGED) ) ) /* don't hide managed windows if unmanagedOnly is TRUE */
2619 * Call ShowWindow directly because an application can intercept WM_SHOWWINDOW messages
2621 ShowWindow(pWnd->hwndSelf,SW_HIDE);
2622 /* flag the window for showing on next WIN_InternalShowOwnedPopups call */
2623 pWnd->flags |= WIN_NEEDS_INTERNALSOP;
2627 WIN_ReleaseWndPtr( pWnd );
2629 HeapFree( GetProcessHeap(), 0, win_array );
2631 return TRUE;
2634 /*******************************************************************
2635 * ShowOwnedPopups (USER32.@)
2637 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2639 int count = 0;
2640 WND *pWnd;
2641 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2643 if (!win_array) return TRUE;
2645 while (win_array[count]) count++;
2646 while (--count >= 0)
2648 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2649 if (!(pWnd = WIN_FindWndPtr( win_array[count] ))) continue;
2651 if (pWnd->dwStyle & WS_POPUP)
2653 if (fShow)
2655 if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2657 /* In Windows, ShowOwnedPopups(TRUE) generates
2658 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
2659 * regardless of the state of the owner
2661 SendMessageA(pWnd->hwndSelf, WM_SHOWWINDOW, SW_SHOW, SW_PARENTOPENING);
2662 pWnd->flags &= ~WIN_NEEDS_SHOW_OWNEDPOPUP;
2665 else
2667 if (IsWindowVisible(pWnd->hwndSelf))
2669 /* In Windows, ShowOwnedPopups(FALSE) generates
2670 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
2671 * regardless of the state of the owner
2673 SendMessageA(pWnd->hwndSelf, WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
2674 pWnd->flags |= WIN_NEEDS_SHOW_OWNEDPOPUP;
2678 WIN_ReleaseWndPtr( pWnd );
2680 HeapFree( GetProcessHeap(), 0, win_array );
2681 return TRUE;
2685 /*******************************************************************
2686 * GetLastActivePopup (USER32.@)
2688 HWND WINAPI GetLastActivePopup( HWND hwnd )
2690 HWND retval;
2691 WND *wndPtr =WIN_FindWndPtr(hwnd);
2692 if (!wndPtr) return hwnd;
2693 retval = wndPtr->hwndLastActive;
2694 if (!IsWindow( retval )) retval = wndPtr->hwndSelf;
2695 WIN_ReleaseWndPtr(wndPtr);
2696 return retval;
2700 /*******************************************************************
2701 * WIN_ListParents
2703 * Build an array of all parents of a given window, starting with
2704 * the immediate parent. The array must be freed with HeapFree.
2705 * Returns NULL if window is a top-level window.
2707 HWND *WIN_ListParents( HWND hwnd )
2709 WND *win;
2710 HWND current, *list;
2711 int pos = 0, size = 16, count;
2713 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
2715 current = hwnd;
2716 for (;;)
2718 if (!(win = WIN_GetPtr( current ))) goto empty;
2719 if (win == WND_OTHER_PROCESS) break; /* need to do it the hard way */
2720 list[pos] = win->parent;
2721 WIN_ReleasePtr( win );
2722 if (!(current = list[pos]))
2724 if (!pos) goto empty;
2725 return list;
2727 if (++pos == size - 1)
2729 /* need to grow the list */
2730 HWND *new_list = HeapReAlloc( GetProcessHeap(), 0, list, (size+16) * sizeof(HWND) );
2731 if (!new_list) goto empty;
2732 list = new_list;
2733 size += 16;
2737 /* at least one parent belongs to another process, have to query the server */
2738 SERVER_START_VAR_REQ( get_window_parents, REQUEST_MAX_VAR_SIZE )
2740 req->handle = hwnd;
2741 if (!SERVER_CALL())
2743 user_handle_t *data = server_data_ptr(req);
2744 count = server_data_size(req) / sizeof(*data);
2745 if (count)
2747 HWND *new_list = HeapReAlloc( GetProcessHeap(), 0,
2748 list, (count + 1) * sizeof(HWND) );
2749 if (new_list)
2751 list = new_list;
2752 for (pos = 0; pos < count; pos++) list[pos] = data[pos];
2753 list[pos] = 0;
2755 else count = 0;
2759 SERVER_END_VAR_REQ;
2760 if (count) return list;
2762 empty:
2763 HeapFree( GetProcessHeap(), 0, list );
2764 return NULL;
2768 /*******************************************************************
2769 * WIN_ListChildren
2771 * Build an array of the children of a given window. The array must be
2772 * freed with HeapFree. Returns NULL when no windows are found.
2774 HWND *WIN_ListChildren( HWND hwnd )
2776 return list_window_children( hwnd, 0, 0 );
2780 /*******************************************************************
2781 * EnumWindows (USER32.@)
2783 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
2785 HWND *list;
2786 BOOL ret = TRUE;
2787 int i, iWndsLocks;
2789 /* We have to build a list of all windows first, to avoid */
2790 /* unpleasant side-effects, for instance if the callback */
2791 /* function changes the Z-order of the windows. */
2793 if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return FALSE;
2795 /* Now call the callback function for every window */
2797 iWndsLocks = WIN_SuspendWndsLock();
2798 for (i = 0; list[i]; i++)
2800 /* Make sure that the window still exists */
2801 if (!IsWindow( list[i] )) continue;
2802 if (!(ret = lpEnumFunc( list[i], lParam ))) break;
2804 WIN_RestoreWndsLock(iWndsLocks);
2805 HeapFree( GetProcessHeap(), 0, list );
2806 return ret;
2810 /**********************************************************************
2811 * EnumTaskWindows16 (USER.225)
2813 BOOL16 WINAPI EnumTaskWindows16( HTASK16 hTask, WNDENUMPROC16 func,
2814 LPARAM lParam )
2816 TDB *tdb = TASK_GetPtr( hTask );
2817 if (!tdb) return FALSE;
2818 return EnumThreadWindows( (DWORD)tdb->teb->tid, (WNDENUMPROC)func, lParam );
2822 /**********************************************************************
2823 * EnumThreadWindows (USER32.@)
2825 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
2827 HWND *list;
2828 int i, iWndsLocks;
2830 if (!(list = list_window_children( GetDesktopWindow(), 0, GetCurrentThreadId() )))
2831 return FALSE;
2833 /* Now call the callback function for every window */
2835 iWndsLocks = WIN_SuspendWndsLock();
2836 for (i = 0; list[i]; i++)
2837 if (!func( list[i], lParam )) break;
2838 WIN_RestoreWndsLock(iWndsLocks);
2839 HeapFree( GetProcessHeap(), 0, list );
2840 return TRUE;
2844 /**********************************************************************
2845 * WIN_EnumChildWindows
2847 * Helper function for EnumChildWindows().
2849 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
2851 HWND *childList;
2852 BOOL ret = FALSE;
2854 for ( ; *list; list++)
2856 /* Make sure that the window still exists */
2857 if (!IsWindow( *list )) continue;
2858 /* skip owned windows */
2859 if (GetWindow( *list, GW_OWNER )) continue;
2860 /* Build children list first */
2861 childList = WIN_ListChildren( *list );
2863 ret = func( *list, lParam );
2865 if (childList)
2867 if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
2868 HeapFree( GetProcessHeap(), 0, childList );
2870 if (!ret) return FALSE;
2872 return TRUE;
2876 /**********************************************************************
2877 * EnumChildWindows (USER32.@)
2879 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
2881 HWND *list;
2882 int iWndsLocks;
2884 if (!(list = WIN_ListChildren( parent ))) return FALSE;
2885 iWndsLocks = WIN_SuspendWndsLock();
2886 WIN_EnumChildWindows( list, func, lParam );
2887 WIN_RestoreWndsLock(iWndsLocks);
2888 HeapFree( GetProcessHeap(), 0, list );
2889 return TRUE;
2893 /*******************************************************************
2894 * AnyPopup (USER.52)
2896 BOOL16 WINAPI AnyPopup16(void)
2898 return AnyPopup();
2902 /*******************************************************************
2903 * AnyPopup (USER32.@)
2905 BOOL WINAPI AnyPopup(void)
2907 int i;
2908 BOOL retvalue;
2909 HWND *list = WIN_ListChildren( GetDesktopWindow() );
2911 if (!list) return FALSE;
2912 for (i = 0; list[i]; i++)
2914 if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
2916 retvalue = (list[i] != 0);
2917 HeapFree( GetProcessHeap(), 0, list );
2918 return retvalue;
2922 /*******************************************************************
2923 * FlashWindow (USER32.@)
2925 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
2927 WND *wndPtr = WIN_FindWndPtr(hWnd);
2929 TRACE("%04x\n", hWnd);
2931 if (!wndPtr) return FALSE;
2932 hWnd = wndPtr->hwndSelf; /* make it a full handle */
2934 if (wndPtr->dwStyle & WS_MINIMIZE)
2936 if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
2938 HDC hDC = GetDC(hWnd);
2940 if (!SendMessageW( hWnd, WM_ERASEBKGND, (WPARAM16)hDC, 0 ))
2941 wndPtr->flags |= WIN_NEEDS_ERASEBKGND;
2943 ReleaseDC( hWnd, hDC );
2944 wndPtr->flags |= WIN_NCACTIVATED;
2946 else
2948 RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
2949 wndPtr->flags &= ~WIN_NCACTIVATED;
2951 WIN_ReleaseWndPtr(wndPtr);
2952 return TRUE;
2954 else
2956 WPARAM16 wparam;
2957 if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
2958 else wparam = (hWnd == GetActiveWindow());
2960 WIN_ReleaseWndPtr(wndPtr);
2961 SendMessageW( hWnd, WM_NCACTIVATE, wparam, (LPARAM)0 );
2962 return wparam;
2967 /*******************************************************************
2968 * GetWindowContextHelpId (USER32.@)
2970 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
2972 DWORD retval;
2973 WND *wnd = WIN_FindWndPtr( hwnd );
2974 if (!wnd) return 0;
2975 retval = wnd->helpContext;
2976 WIN_ReleaseWndPtr(wnd);
2977 return retval;
2981 /*******************************************************************
2982 * SetWindowContextHelpId (USER32.@)
2984 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
2986 WND *wnd = WIN_FindWndPtr( hwnd );
2987 if (!wnd) return FALSE;
2988 wnd->helpContext = id;
2989 WIN_ReleaseWndPtr(wnd);
2990 return TRUE;
2994 /*******************************************************************
2995 * DRAG_QueryUpdate
2997 * recursively find a child that contains spDragInfo->pt point
2998 * and send WM_QUERYDROPOBJECT
3000 BOOL16 DRAG_QueryUpdate( HWND hQueryWnd, SEGPTR spDragInfo, BOOL bNoSend )
3002 BOOL16 wParam, bResult = 0;
3003 POINT pt;
3004 LPDRAGINFO16 ptrDragInfo = MapSL(spDragInfo);
3005 RECT tempRect;
3007 if (!ptrDragInfo) return FALSE;
3009 CONV_POINT16TO32( &ptrDragInfo->pt, &pt );
3011 GetWindowRect(hQueryWnd,&tempRect);
3013 if( !PtInRect(&tempRect,pt) || !IsWindowEnabled(hQueryWnd)) return FALSE;
3015 if (!IsIconic( hQueryWnd ))
3017 GetClientRect( hQueryWnd, &tempRect );
3018 MapWindowPoints( hQueryWnd, 0, (LPPOINT)&tempRect, 2 );
3020 if (PtInRect( &tempRect, pt))
3022 int i;
3023 HWND *list = WIN_ListChildren( hQueryWnd );
3025 wParam = 0;
3027 if (list)
3029 for (i = 0; list[i]; i++)
3031 if (GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)
3033 GetWindowRect( list[i], &tempRect );
3034 if (PtInRect( &tempRect, pt )) break;
3037 if (list[i])
3039 if (IsWindowEnabled( list[i] ))
3040 bResult = DRAG_QueryUpdate( list[i], spDragInfo, bNoSend );
3042 HeapFree( GetProcessHeap(), 0, list );
3044 if(bResult) return bResult;
3046 else wParam = 1;
3048 else wParam = 1;
3050 ScreenToClient16(hQueryWnd,&ptrDragInfo->pt);
3052 ptrDragInfo->hScope = hQueryWnd;
3054 if (bNoSend) bResult = (GetWindowLongA( hQueryWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES) != 0;
3055 else bResult = SendMessage16( hQueryWnd, WM_QUERYDROPOBJECT, (WPARAM16)wParam, spDragInfo );
3057 if( !bResult ) CONV_POINT32TO16( &pt, &ptrDragInfo->pt );
3059 return bResult;
3063 /*******************************************************************
3064 * DragDetect (USER32.@)
3066 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3068 MSG msg;
3069 RECT rect;
3071 rect.left = pt.x - wDragWidth;
3072 rect.right = pt.x + wDragWidth;
3074 rect.top = pt.y - wDragHeight;
3075 rect.bottom = pt.y + wDragHeight;
3077 SetCapture(hWnd);
3079 while(1)
3081 while(PeekMessageA(&msg ,0 ,WM_MOUSEFIRST ,WM_MOUSELAST ,PM_REMOVE))
3083 if( msg.message == WM_LBUTTONUP )
3085 ReleaseCapture();
3086 return 0;
3088 if( msg.message == WM_MOUSEMOVE )
3090 POINT tmp;
3091 tmp.x = LOWORD(msg.lParam);
3092 tmp.y = HIWORD(msg.lParam);
3093 if( !PtInRect( &rect, tmp ))
3095 ReleaseCapture();
3096 return 1;
3100 WaitMessage();
3102 return 0;
3105 /******************************************************************************
3106 * DragObject (USER.464)
3108 DWORD WINAPI DragObject16( HWND16 hwndScope, HWND16 hWnd, UINT16 wObj,
3109 HANDLE16 hOfStruct, WORD szList, HCURSOR16 hCursor )
3111 MSG msg;
3112 LPDRAGINFO16 lpDragInfo;
3113 SEGPTR spDragInfo;
3114 HCURSOR16 hDragCursor=0, hOldCursor=0, hBummer=0;
3115 HGLOBAL16 hDragInfo = GlobalAlloc16( GMEM_SHARE | GMEM_ZEROINIT, 2*sizeof(DRAGINFO16));
3116 HCURSOR16 hCurrentCursor = 0;
3117 HWND16 hCurrentWnd = 0;
3119 lpDragInfo = (LPDRAGINFO16) GlobalLock16(hDragInfo);
3120 spDragInfo = K32WOWGlobalLock16(hDragInfo);
3122 if( !lpDragInfo || !spDragInfo ) return 0L;
3124 if (!(hBummer = LoadCursorA(0, MAKEINTRESOURCEA(OCR_NO))))
3126 GlobalFree16(hDragInfo);
3127 return 0L;
3130 if(hCursor)
3132 if( !(hDragCursor = CURSORICON_IconToCursor(hCursor, FALSE)) )
3134 GlobalFree16(hDragInfo);
3135 return 0L;
3138 if( hDragCursor == hCursor ) hDragCursor = 0;
3139 else hCursor = hDragCursor;
3141 hOldCursor = SetCursor(hDragCursor);
3144 lpDragInfo->hWnd = hWnd;
3145 lpDragInfo->hScope = 0;
3146 lpDragInfo->wFlags = wObj;
3147 lpDragInfo->hList = szList; /* near pointer! */
3148 lpDragInfo->hOfStruct = hOfStruct;
3149 lpDragInfo->l = 0L;
3151 SetCapture(hWnd);
3152 ShowCursor( TRUE );
3156 GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST );
3158 *(lpDragInfo+1) = *lpDragInfo;
3160 lpDragInfo->pt.x = msg.pt.x;
3161 lpDragInfo->pt.y = msg.pt.y;
3163 /* update DRAGINFO struct */
3164 TRACE_(msg)("lpDI->hScope = %04x\n",lpDragInfo->hScope);
3166 if( DRAG_QueryUpdate(hwndScope, spDragInfo, FALSE) > 0 )
3167 hCurrentCursor = hCursor;
3168 else
3170 hCurrentCursor = hBummer;
3171 lpDragInfo->hScope = 0;
3173 if( hCurrentCursor )
3174 SetCursor(hCurrentCursor);
3176 /* send WM_DRAGLOOP */
3177 SendMessage16( hWnd, WM_DRAGLOOP, (WPARAM16)(hCurrentCursor != hBummer),
3178 (LPARAM) spDragInfo );
3179 /* send WM_DRAGSELECT or WM_DRAGMOVE */
3180 if( hCurrentWnd != lpDragInfo->hScope )
3182 if( hCurrentWnd )
3183 SendMessage16( hCurrentWnd, WM_DRAGSELECT, 0,
3184 (LPARAM)MAKELONG(LOWORD(spDragInfo)+sizeof(DRAGINFO16),
3185 HIWORD(spDragInfo)) );
3186 hCurrentWnd = lpDragInfo->hScope;
3187 if( hCurrentWnd )
3188 SendMessage16( hCurrentWnd, WM_DRAGSELECT, 1, (LPARAM)spDragInfo);
3190 else
3191 if( hCurrentWnd )
3192 SendMessage16( hCurrentWnd, WM_DRAGMOVE, 0, (LPARAM)spDragInfo);
3194 } while( msg.message != WM_LBUTTONUP && msg.message != WM_NCLBUTTONUP );
3196 ReleaseCapture();
3197 ShowCursor( FALSE );
3199 if( hCursor )
3201 SetCursor( hOldCursor );
3202 if (hDragCursor) DestroyCursor( hDragCursor );
3205 if( hCurrentCursor != hBummer )
3206 msg.lParam = SendMessage16( lpDragInfo->hScope, WM_DROPOBJECT,
3207 (WPARAM16)hWnd, (LPARAM)spDragInfo );
3208 else
3209 msg.lParam = 0;
3210 GlobalFree16(hDragInfo);
3212 return (DWORD)(msg.lParam);
3216 /******************************************************************************
3217 * GetWindowModuleFileNameA (USER32.@)
3219 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR lpszFileName, UINT cchFileNameMax)
3221 FIXME("GetWindowModuleFileNameA(hwnd 0x%x, lpszFileName %p, cchFileNameMax %u) stub!\n",
3222 hwnd, lpszFileName, cchFileNameMax);
3223 return 0;
3226 /******************************************************************************
3227 * GetWindowModuleFileNameW (USER32.@)
3229 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPSTR lpszFileName, UINT cchFileNameMax)
3231 FIXME("GetWindowModuleFileNameW(hwnd 0x%x, lpszFileName %p, cchFileNameMax %u) stub!\n",
3232 hwnd, lpszFileName, cchFileNameMax);
3233 return 0;