Code:
/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / wpf / src / UIAutomation / Win32Providers / MS / Internal / AutomationProxies / Misc.cs / 1 / Misc.cs
//---------------------------------------------------------------------------- // //// Copyright (C) Microsoft Corporation. All rights reserved. // // // // Description: Miscellaneous helper routines // // History: // 12/06/2004 : Created [....] // //--------------------------------------------------------------------------- // PRESHARP: In order to avoid generating warnings about unkown message numbers and unknown pragmas. #pragma warning disable 1634, 1691 using Microsoft.Win32.SafeHandles; using MS.Win32; using System; using System.Collections; using System.ComponentModel; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Security.Permissions; using System.Text; using System.Windows.Automation; using System.Windows.Automation.Provider; using System.Windows; using System.Windows.Input; using System.Diagnostics; namespace MS.Internal.AutomationProxies { static class Misc { //----------------------------------------------------- // // Internal Methods // //----------------------------------------------------- #region Internal Methods // // HrGetWindowShortcut() // internal static string AccessKey(string s) { // Get the index of the shortcut int iPosShortCut = s.IndexOf('&'); // Did we found an & or is it at the end of the string if (iPosShortCut < 0 || iPosShortCut + 1 >= s.Length) { return null; } // Build the result string return ST.Get(STID.KeyAlt) + "+" + s[iPosShortCut + 1]; } // Extend an existing RunTimeID by one element internal static int[] AppendToRuntimeId(int[] baseID, int id) { // For the base case, where parent is a hwnd, baseID will be null, // so use AppendRuntimeId instead. UIA will then glue that to the ID // of the parent HWND. if(baseID == null) baseID = new int[] { AutomationInteropProvider.AppendRuntimeId }; int len = baseID.Length; int[] newID = new int[len + 1]; baseID.CopyTo(newID, 0); newID[len] = id; return newID; } internal static double[] RectArrayToDoubleArray(Rect[] rectArray) { if (rectArray == null) return null; double[] doubles = new double[rectArray.Length * 4]; int scan = 0; for (int i = 0; i < rectArray.Length; i++) { doubles[scan++] = rectArray[i].X; doubles[scan++] = rectArray[i].Y; doubles[scan++] = rectArray[i].Width; doubles[scan++] = rectArray[i].Height; } return doubles; } // Ensure a window and all its parents are enabled. // If not, throw ElementNotEnabledException. internal static void CheckEnabled(IntPtr hwnd) { if (!IsEnabled(hwnd)) { throw new ElementNotEnabledException(); } } // Checks to see if the process owning the hwnd is currently in menu mode // and takes steps to exit menu mode if it is internal static void ClearMenuMode() { // Check if we're in menu mode with helper method. if (InMenuMode()) { // If we are, send an alt keypress to escape Input.SendKeyboardInput(Key.LeftAlt, true); Input.SendKeyboardInput(Key.LeftAlt, false); // Wait for a few milliseconds for this operation to be completed long dwTicks = (long)Environment.TickCount; // Wait until the action has been completed while (InMenuMode() && ((long)Environment.TickCount - dwTicks) < MenuTimeOut) { // Sleep the shortest amount of time possible while still guaranteeing that some sleep occurs System.Threading.Thread.Sleep(1); } } } internal static bool CloseHandle(IntPtr processHandle) { bool result = UnsafeNativeMethods.CloseHandle(processHandle); int lastWin32Error = Marshal.GetLastWin32Error(); if (!result) { ThrowWin32ExceptionsIfError(lastWin32Error); } return result; } // Compares 2 raw elements and returns true if equal, false otherwise internal static bool Compare(ProxySimple el1, ProxySimple el2) { int[] a1 = el1.GetRuntimeId(); int[] a2 = el2.GetRuntimeId(); int l = a1.Length; if (l != a2.Length) return false; for (int i = 0; i < l; i++) { if (a1[i] != a2[i]) { return false; } } return true; } internal static IntPtr DispatchMessage(ref NativeMethods.MSG msg) { // From the Windows SDK documentation: // The return value specifies the value returned by the window procedure. // Although its meaning depends on the message being dispatched, the return // value generally is ignored. #pragma warning suppress 6031, 6523 return UnsafeNativeMethods.DispatchMessage(ref msg); } internal unsafe static bool EnumChildWindows(IntPtr hwnd, NativeMethods.EnumChildrenCallbackVoid lpEnumFunc, void* lParam) { bool result = UnsafeNativeMethods.EnumChildWindows(hwnd, lpEnumFunc, lParam); int lastWin32Error = Marshal.GetLastWin32Error(); if (!result) { ThrowWin32ExceptionsIfError(lastWin32Error); } return result; } internal static IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string className, string wndName) { // The failure case of this API may also be a valid return. GetLastError() is need to determine a true failure state. // Clear the last error code to make sure we have a good starting condition to determine error state. UnsafeNativeMethods.SetLastError(0); IntPtr result = UnsafeNativeMethods.FindWindowEx(hwndParent, hwndChildAfter, className, wndName); int lastWin32Error = Marshal.GetLastWin32Error(); if (result == IntPtr.Zero) { ThrowWin32ExceptionsIfError(lastWin32Error); } return result; } internal static string GetClassName(IntPtr hwnd) { StringBuilder sb = new StringBuilder(NativeMethods.MAX_PATH + 1); int result = UnsafeNativeMethods.GetClassName(hwnd, sb, NativeMethods.MAX_PATH); int lastWin32Error = Marshal.GetLastWin32Error(); if (result == 0) { ThrowWin32ExceptionsIfError(lastWin32Error); return ""; } return sb.ToString(); } // Get the name of a control and conditionally strip mnemonic. // label is the hwnd of the control that is funtioning as the label. Use GetLabelhwnd to find this. // If stripMnemonic is true, amperstrands characters will be stripped out. internal static string GetControlName(IntPtr label, bool stripMnemonic) { if (label == IntPtr.Zero) { return null; } StringBuilder sb = new StringBuilder(MaxLengthNameProperty); int result = UnsafeNativeMethods.GetWindowText(label, sb, MaxLengthNameProperty); int lastWin32Error = Marshal.GetLastWin32Error(); if (result == 0) { ThrowWin32ExceptionsIfError(lastWin32Error); return null; } return stripMnemonic ? StripMnemonic(sb.ToString()) : sb.ToString(); } internal static bool GetClientRectInScreenCoordinates(IntPtr hwnd, ref NativeMethods.Win32Rect rc) { rc = NativeMethods.Win32Rect.Empty; if (!GetClientRect(hwnd, ref rc)) { return false; } NativeMethods.Win32Point leftTop = new NativeMethods.Win32Point(rc.left, rc.top); if (!MapWindowPoints(hwnd, IntPtr.Zero, ref leftTop, 1)) { return false; } NativeMethods.Win32Point rightBottom = new NativeMethods.Win32Point(rc.right, rc.bottom); if (!MapWindowPoints(hwnd, IntPtr.Zero, ref rightBottom, 1)) { return false; } rc = new NativeMethods.Win32Rect(leftTop.x, leftTop.y, rightBottom.x, rightBottom.y); return true; } internal static bool GetClientRect(IntPtr hwnd, ref NativeMethods.Win32Rect rc) { bool result = UnsafeNativeMethods.GetClientRect(hwnd, ref rc); int lastWin32Error = Marshal.GetLastWin32Error(); if (!result) { ThrowWin32ExceptionsIfError(lastWin32Error); } // When the control is right to left GetClentRect() will return a rectangle with left > right. // Normalize thesee rectangle back to left to right. rc.Normalize(IsLayoutRTL(hwnd)); return result; } internal static bool GetComboBoxInfo(IntPtr hwnd, ref NativeMethods.COMBOBOXINFO cbi) { bool result = UnsafeNativeMethods.GetComboBoxInfo(hwnd, ref cbi); int lastWin32Error = Marshal.GetLastWin32Error(); if (!result) { ThrowWin32ExceptionsIfError(lastWin32Error); } return result; } internal static bool GetCursorPos(ref NativeMethods.Win32Point pt) { // Vista and beyond use GetPhysicalCursorPos which handles DPI issues bool result = (System.Environment.OSVersion.Version.Major >= 6) ? UnsafeNativeMethods.GetPhysicalCursorPos(ref pt) : UnsafeNativeMethods.GetCursorPos(ref pt); int lastWin32Error = Marshal.GetLastWin32Error(); if (!result) { ThrowWin32ExceptionsIfError(lastWin32Error); } return result; } internal static IntPtr GetDC(IntPtr hwnd) { IntPtr hdc = UnsafeNativeMethods.GetDC(hwnd); int lastWin32Error = Marshal.GetLastWin32Error(); if (hdc == IntPtr.Zero) { ThrowWin32ExceptionsIfError(lastWin32Error); } return hdc; } internal static IntPtr GetFocusedWindow() { NativeMethods.GUITHREADINFO gui; return ProxyGetGUIThreadInfo(0, out gui) ? gui.hwndFocus : IntPtr.Zero; } internal static string GetItemToolTipText(IntPtr hwnd, IntPtr hwndToolTip, int item) { if (hwndToolTip != IntPtr.Zero) { // We've found the tooltip window, so we won't need to scan for it. // Got a tooltip window - use it. NativeMethods.TOOLINFO tool = new NativeMethods.TOOLINFO(); tool.Init(Marshal.SizeOf(typeof(NativeMethods.TOOLINFO))); tool.hwnd = hwnd; tool.uId = item; return XSendMessage.GetItemText(hwndToolTip, tool); } else { // Control doesn't know its tooltip window - instead scan for one... // Enum the top-level windows owned by this thread... uint processId; uint threadId = GetWindowThreadProcessId(hwnd, out processId); UnsafeNativeMethods.ENUMTOOLTIPWINDOWINFO info = new UnsafeNativeMethods.ENUMTOOLTIPWINDOWINFO(); info.hwnd = hwnd; info.id = item; info.name = ""; UnsafeNativeMethods.EnumThreadWndProc enumToolTipWindows = new UnsafeNativeMethods.EnumThreadWndProc(EnumToolTipWindows); GCHandle gch = GCHandle.Alloc(enumToolTipWindows); UnsafeNativeMethods.EnumThreadWindows(threadId, enumToolTipWindows, ref info); gch.Free(); return info.name; } } // -------------------------------------------------------------------------- // // GetLabelhwnd() // // This walks backwards among peer windows to find a static field. It stops // if it gets to the front or hits a group/tabstop, just like the dialog // manager does. // // Ported from OleAcc\Client.CPP // ------------------------------------------------------------------------- internal static IntPtr GetLabelhwnd(IntPtr hwnd) { // Sanity check if (!UnsafeNativeMethods.IsWindow(hwnd)) { return IntPtr.Zero; } // Only get labels for child windows - not top-level windows or desktop IntPtr hwndParent = Misc.GetParent(hwnd); if (hwndParent == IntPtr.Zero || hwndParent == UnsafeNativeMethods.GetDesktopWindow()) { return IntPtr.Zero; } IntPtr peer = hwnd; // If GetWindow fails we're going to exit, no need to call Marshal.GetLastWin32Error #pragma warning suppress 56523 while ((peer = UnsafeNativeMethods.GetWindow(peer, NativeMethods.GW_HWNDPREV)) != IntPtr.Zero) { // // Is this a static dude? // int code = Misc.ProxySendMessageInt(peer, NativeMethods.WM_GETDLGCODE, IntPtr.Zero, IntPtr.Zero); if ((code & NativeMethods.DLGC_STATIC) == NativeMethods.DLGC_STATIC) { // // Great, we've found our label. // return peer; } // // Skip invisible controls. // Note that we do this after checking if its a static, so that we give invisible statics a chance. // Using invisible statics is an easy workaround to add names to controls without changing the visual UI. // // If GetWindowLong fails we're going to exit, no need to call Marshal.GetLastWin32Error #pragma warning suppress 56523 int style = UnsafeNativeMethods.GetWindowLong(peer, NativeMethods.GWL_STYLE); if ((style & NativeMethods.WS_VISIBLE) != 0) continue; // // Is this a tabstop or group? If so, bail out now. // if ((style & (NativeMethods.WS_GROUP | NativeMethods.WS_TABSTOP)) != 0) break; } // Failed to find a suitable peer return IntPtr.Zero; } internal static bool GetMenuBarInfo(IntPtr hwnd, int idObject, uint item, ref NativeMethods.MENUBARINFO mbi) { // The failure case of this API may also be a valid return. GetLastError() is need to determine a true failure state. // Clear the last error code to make sure we have a good starting condition to determine error state. UnsafeNativeMethods.SetLastError(0); bool result = UnsafeNativeMethods.GetMenuBarInfo(hwnd, idObject, item, ref mbi); int lastWin32Error = Marshal.GetLastWin32Error(); if (!result) { ThrowWin32ExceptionsIfError(lastWin32Error); } return result; } internal static int GetMenuItemCount(IntPtr hmenu) { int count = UnsafeNativeMethods.GetMenuItemCount(hmenu); int lastWin32Error = Marshal.GetLastWin32Error(); if (count == -1) { ThrowWin32ExceptionsIfError(lastWin32Error); } return count; } internal static bool GetMenuItemInfo(IntPtr hmenu, int item, bool byPosition, ref NativeMethods.MENUITEMINFO menuItemInfo) { bool result = UnsafeNativeMethods.GetMenuItemInfo(hmenu, item, byPosition, ref menuItemInfo); int lastWin32Error = Marshal.GetLastWin32Error(); if (!result) { ThrowWin32ExceptionsIfError(lastWin32Error); } return result; } internal static bool GetMenuItemRect(IntPtr hwnd, IntPtr hmenu, int item, out NativeMethods.Win32Rect rc) { bool result = UnsafeNativeMethods.GetMenuItemRect(hwnd, hmenu, item, out rc); int lastWin32Error = Marshal.GetLastWin32Error(); if (!result) { ThrowWin32ExceptionsIfError(lastWin32Error); } return result; } internal static bool GetMessage(ref NativeMethods.MSG msg, IntPtr hwnd, int msgFilterMin, int msgFilterMax) { int result = UnsafeNativeMethods.GetMessage(ref msg, hwnd, msgFilterMin, msgFilterMax); int lastWin32Error = Marshal.GetLastWin32Error(); bool success = (result != 0 && result != -1); if (!success) { ThrowWin32ExceptionsIfError(lastWin32Error); } return success; } internal static int GetObjectW(IntPtr hObject, int size, ref NativeMethods.LOGFONT lf) { int result = UnsafeNativeMethods.GetObjectW(hObject, size, ref lf); int lastWin32Error = Marshal.GetLastWin32Error(); if (result == 0) { ThrowWin32ExceptionsIfError(lastWin32Error); } return result; } internal static IntPtr GetParent(IntPtr hwnd) { // The failure case of this API may also be a valid return. GetLastError() is need to determine a true failure state. // Clear the last error code to make sure we have a good starting condition to determine error state. UnsafeNativeMethods.SetLastError(0); IntPtr hwndParent = UnsafeNativeMethods.GetAncestor(hwnd, NativeMethods.GA_PARENT); int lastWin32Error = Marshal.GetLastWin32Error(); if (hwndParent == IntPtr.Zero) { ThrowWin32ExceptionsIfError(lastWin32Error); } return hwndParent; } internal static bool GetScrollBarInfo(IntPtr hwnd, int fnBar, ref NativeMethods.ScrollBarInfo sbi) { bool result = UnsafeNativeMethods.GetScrollBarInfo(hwnd, fnBar, ref sbi); int lastWin32Error = Marshal.GetLastWin32Error(); if (!result) { ThrowWin32ExceptionsIfError(lastWin32Error); } return result; } internal static bool GetScrollInfo(IntPtr hwnd, int fnBar, ref NativeMethods.ScrollInfo si) { bool result = UnsafeNativeMethods.GetScrollInfo(hwnd, fnBar, ref si); int lastWin32Error = Marshal.GetLastWin32Error(); if (!result) { // 1447 ERROR_NO_SCROLLBARS The window does not have scroll bars. // If GetScrollInfo() fails with ERROR_NO_SCROLLBARS then there is no scroll information // to get. Just return false saying that GetScrollInfo() could not get the information if (lastWin32Error == 1447) { return false; } ThrowWin32ExceptionsIfError(lastWin32Error); } return result; } internal static int GetTextExtentPoint32(IntPtr hdc, string text, int length, out NativeMethods.SIZE size) { // The failure case of this API may also be a valid return. GetLastError() is need to determine a true failure state. // Clear the last error code to make sure we have a good starting condition to determine error state. UnsafeNativeMethods.SetLastError(0); int result = UnsafeNativeMethods.GetTextExtentPoint32(hdc, text, length, out size); int lastWin32Error = Marshal.GetLastWin32Error(); if (result == 0) { ThrowWin32ExceptionsIfError(lastWin32Error); } return result; } // Calls a message that retrieves a string, but doesn't take a length argument, in a relatively safe manner. // Attempts to rapidly resize in hopes of crashing UI Automation should just crash whatever is rapidly resizing. // Param "hwnd" the Window Handle // Param "uMsg" the Windows Message // Param "wParam" the Windows wParam // Param "maxLength" the size of the string internal static unsafe string GetUnsafeText(IntPtr hwnd, int uMsg, IntPtr wParam, int maxLength) { uint pageSize = GetPageSize(); IntPtr memAddr = IntPtr.Zero; // Ptr to remote mem // calculate the size needed for the string uint cbSize = (uint)((maxLength + 1) * sizeof(char)); // resize it to include enough pages for the string, and an extra guarding page, and one extra page to account for shifts. cbSize = ((cbSize / pageSize) + 3) * pageSize; try { // Allocate the space memAddr = VirtualAlloc(IntPtr.Zero, new UIntPtr(cbSize), UnsafeNativeMethods.MEM_COMMIT, UnsafeNativeMethods.PAGE_READWRITE); // Allocate the Final page as No Access, so any attempt to write to it will GPF VirtualAlloc(new IntPtr((byte *)memAddr.ToPointer() + cbSize - pageSize), new UIntPtr(pageSize), UnsafeNativeMethods.MEM_COMMIT, UnsafeNativeMethods.PAGE_NOACCESS); // Send the message... if (ProxySendMessage(hwnd, uMsg, wParam, memAddr) == IntPtr.Zero) { return ""; } String str = new string((char*)memAddr.ToPointer(), 0, maxLength); // Note: lots of "old world" strings are null terminated // Leaving the null termination in the System.String may lead // to some issues when used with the StringBuilder int nullTermination = str.IndexOf('\0'); if (-1 != nullTermination) { // We need to strip null terminated char and everything behind it from the str str = str.Remove(nullTermination, maxLength - nullTermination); } return str; } finally { // Free the memory if (memAddr != IntPtr.Zero) { VirtualFree(memAddr, UIntPtr.Zero, UnsafeNativeMethods.MEM_RELEASE); } } } internal static IntPtr GetWindow(IntPtr hwnd, int cmd) { // The failure case of this API may also be a valid return. GetLastError() is need to determine a true failure state. // Clear the last error code to make sure we have a good starting condition to determine error state. UnsafeNativeMethods.SetLastError(0); IntPtr resultHwnd = UnsafeNativeMethods.GetWindow(hwnd, cmd); int lastWin32Error = Marshal.GetLastWin32Error(); if (resultHwnd == IntPtr.Zero) { ThrowWin32ExceptionsIfError(lastWin32Error); } return resultHwnd; } // Gets the extended style of the window internal static int GetWindowExStyle(IntPtr hwnd) { // The failure case of this API may also be a valid return. GetLastError() is need to determine a true failure state. // Clear the last error code to make sure we have a good starting condition to determine error state. UnsafeNativeMethods.SetLastError(0); int exstyle = UnsafeNativeMethods.GetWindowLong(hwnd, NativeMethods.GWL_EXSTYLE); int lastWin32Error = Marshal.GetLastWin32Error(); if (exstyle == 0) { ThrowWin32ExceptionsIfError(lastWin32Error); } return exstyle; } // Gets the id of the window internal static int GetWindowId(IntPtr hwnd) { // The failure case of this API may also be a valid return. GetLastError() is need to determine a true failure state. // Clear the last error code to make sure we have a good starting condition to determine error state. UnsafeNativeMethods.SetLastError(0); int id = UnsafeNativeMethods.GetWindowLong(hwnd, NativeMethods.GWL_ID); int lastWin32Error = Marshal.GetLastWin32Error(); if (id == 0) { ThrowWin32ExceptionsIfError(lastWin32Error); } return id; } // Gets the parent of the window internal static IntPtr GetWindowParent(IntPtr hwnd) { // NOTE: This may have issues in 64-bit. // The failure case of this API may also be a valid return. GetLastError() is need to determine a true failure state. // Clear the last error code to make sure we have a good starting condition to determine error state. UnsafeNativeMethods.SetLastError(0); int result = UnsafeNativeMethods.GetWindowLong(hwnd, NativeMethods.GWL_HWNDPARENT); int lastWin32Error = Marshal.GetLastWin32Error(); if (result == 0) { ThrowWin32ExceptionsIfError(lastWin32Error); } return (IntPtr)result; } internal static bool GetWindowRect(IntPtr hwnd, ref NativeMethods.Win32Rect rc) { bool result = UnsafeNativeMethods.GetWindowRect(hwnd, ref rc); int lastWin32Error = Marshal.GetLastWin32Error(); if (!result) { ThrowWin32ExceptionsIfError(lastWin32Error); } return result; } // Gets the style of the window internal static int GetWindowStyle(IntPtr hwnd) { // The failure case of this API may also be a valid return. GetLastError() is need to determine a true failure state. // Clear the last error code to make sure we have a good starting condition to determine error state. UnsafeNativeMethods.SetLastError(0); int style = UnsafeNativeMethods.GetWindowLong(hwnd, NativeMethods.GWL_STYLE); int lastWin32Error = Marshal.GetLastWin32Error(); if (style == 0) { ThrowWin32ExceptionsIfError(lastWin32Error); } return style; } internal static uint GetWindowThreadProcessId(IntPtr hwnd, out uint processId) { // GetWindowThreadProcessId does use SetLastError(). So a call to GetLastError() would be meanless. // Disabling the PreSharp warning. #pragma warning suppress 6523 uint threadId = UnsafeNativeMethods.GetWindowThreadProcessId(hwnd, out processId); if (threadId == 0) { throw new ElementNotAvailableException(); } return threadId; } internal static short GlobalAddAtom(string atomName) { short atom = UnsafeNativeMethods.GlobalAddAtom(atomName); int lastWin32Error = Marshal.GetLastWin32Error(); if (atom == 0) { ThrowWin32ExceptionsIfError(lastWin32Error); } return atom; } internal static short GlobalDeleteAtom(short atom) { // This API does not have an error condition. GetLastError is used to determine if an error occured. // So, clear the last error code to make sure we have a good starting condition to determine error state. UnsafeNativeMethods.SetLastError(0); short result = UnsafeNativeMethods.GlobalDeleteAtom(atom); ThrowWin32ExceptionsIfError(Marshal.GetLastWin32Error()); return result; } // detect if we're in the menu mode internal static bool InMenuMode() { NativeMethods.GUITHREADINFO gui; return (ProxyGetGUIThreadInfo(0, out gui) && (IsBitSet(gui.dwFlags, NativeMethods.GUI_INMENUMODE))); } internal static bool IsBitSet(int flags, int bit) { return (flags & bit) == bit; } // Check if window is really enabled, taking parent state into account. internal static bool IsEnabled(IntPtr hwnd) { // Navigate up parent chain. If any ancestor window is // not enabled, then that has the effect of disabling this window. // All ancestor windows must be enabled for this window to be enabled. for (; ; ) { if (!SafeNativeMethods.IsWindowEnabled(hwnd)) { return false; } hwnd = UnsafeNativeMethods.GetAncestor(hwnd, NativeMethods.GA_PARENT); if (hwnd == IntPtr.Zero) { return true; } } } internal static bool IsControlRTL(IntPtr hwnd) { int exStyle = GetWindowExStyle(hwnd); return IsBitSet(exStyle, NativeMethods.WS_EX_LAYOUTRTL) || IsBitSet(exStyle, NativeMethods.WS_EX_RTLREADING); } internal static bool IsLayoutRTL(IntPtr hwnd) { return IsBitSet(GetWindowExStyle(hwnd), NativeMethods.WS_EX_LAYOUTRTL); } internal static bool IsReadingRTL(IntPtr hwnd) { return IsBitSet(GetWindowExStyle(hwnd), NativeMethods.WS_EX_RTLREADING); } internal static bool IntersectRect(ref NativeMethods.Win32Rect rcDest, ref NativeMethods.Win32Rect rc1, ref NativeMethods.Win32Rect rc2) { bool result = SafeNativeMethods.IntersectRect(ref rcDest, ref rc1, ref rc2); int lastWin32Error = Marshal.GetLastWin32Error(); if (!result) { ThrowWin32ExceptionsIfError(lastWin32Error); } return result; } // Call IsCriticalException w/in a catch-all-exception handler to allow critical exceptions // to be thrown (this is copied from exception handling code in WinForms but feel free to // add new critical exceptions). Usage: // try // { // Somecode(); // } // catch (Exception e) // { // if (Misc.IsCriticalException(e)) // throw; // // ignore non-critical errors from external code // } internal static bool IsCriticalException(Exception e) { return e is NullReferenceException || e is StackOverflowException || e is OutOfMemoryException || e is System.Threading.ThreadAbortException; } // this is to determine is an item is visible. The assumption is that the items here are not hwnds // and that they are clipped by there parent. For example this is called by the WindowsListBox. // In that case the hwnd is the list box and the itemRect would be a list item this code checks to see // if the item is scrolled out of view. static internal bool IsItemVisible(IntPtr hwnd, ref NativeMethods.Win32Rect itemRect) { NativeMethods.Win32Rect clientRect = new NativeMethods.Win32Rect(0, 0, 0, 0); if (!GetClientRectInScreenCoordinates(hwnd, ref clientRect)) return false; NativeMethods.Win32Rect intersection = new NativeMethods.Win32Rect(0, 0, 0, 0); // Returns true if the passed in itemRect overlaps with the client area of the hwnd this API // does not modify clientRect or itemRect return IntersectRect(ref intersection, ref clientRect, ref itemRect); } static internal bool IsItemVisible(ref NativeMethods.Win32Rect parentRect, ref NativeMethods.Win32Rect itemRect) { NativeMethods.Win32Rect intersection = new NativeMethods.Win32Rect(0, 0, 0, 0); // Returns true if the passed in itemRect overlaps with the client area of the hwnd this API // does not modify clientRect or itemRect return IntersectRect(ref intersection, ref parentRect, ref itemRect); } static internal bool IsItemVisible(ref NativeMethods.Win32Rect parentRect, ref Rect itemRect) { NativeMethods.Win32Rect itemRc = new NativeMethods.Win32Rect(itemRect); NativeMethods.Win32Rect intersection = new NativeMethods.Win32Rect(0, 0, 0, 0); // Returns true if the passed in itemRect overlaps with the client area of the hwnd this API // does not modify clientRect or itemRect return IntersectRect(ref intersection, ref parentRect, ref itemRc); } static internal bool IsItemVisible(ref Rect parentRect, ref NativeMethods.Win32Rect itemRect) { NativeMethods.Win32Rect parentRc = new NativeMethods.Win32Rect(parentRect); NativeMethods.Win32Rect intersection = new NativeMethods.Win32Rect(0, 0, 0, 0); // Returns true if the passed in itemRect overlaps with the client area of the hwnd this API // does not modify clientRect or itemRect return IntersectRect(ref intersection, ref parentRc, ref itemRect); } static internal bool IsItemVisible(ref Rect parentRect, ref Rect itemRect) { NativeMethods.Win32Rect itemRc = new NativeMethods.Win32Rect(itemRect); NativeMethods.Win32Rect parentRc = new NativeMethods.Win32Rect(parentRect); NativeMethods.Win32Rect intersection = new NativeMethods.Win32Rect(0, 0, 0, 0); // Returns true if the passed in itemRect overlaps with the client area of the hwnd this API // does not modify clientRect or itemRect return IntersectRect(ref intersection, ref parentRc, ref itemRc); } internal static bool IsProgmanWindow(IntPtr hwnd) { while (hwnd != IntPtr.Zero) { if (GetClassName(hwnd).CompareTo("Progman") == 0) { return true; } hwnd = UnsafeNativeMethods.GetAncestor(hwnd, NativeMethods.GA_PARENT); } return false; } internal static bool IsWow64Process(MS.Internal.AutomationProxies.SafeProcessHandle hProcess, out bool Wow64Process) { bool result = UnsafeNativeMethods.IsWow64Process(hProcess, out Wow64Process); int lastWin32Error = Marshal.GetLastWin32Error(); if (!result) { ThrowWin32ExceptionsIfError(lastWin32Error); } return result; } // wrapper for MapWindowPoints internal static bool MapWindowPoints(IntPtr hWndFrom, IntPtr hWndTo, ref NativeMethods.Win32Rect rect, int cPoints) { // The failure case of this API may also be a valid return. GetLastError() is need to determine a true failure state. // Clear the last error code to make sure we have a good starting condition to determine error state. UnsafeNativeMethods.SetLastError(0); int mappingOffset = UnsafeNativeMethods.MapWindowPoints(hWndFrom, hWndTo, ref rect, cPoints); int lastWin32Error = Marshal.GetLastWin32Error(); if (mappingOffset == 0) { // When mapping points to/from Progman and its children MapWindowPoints may fail with error code 1400 // Invalid Window Handle. Since Progman is the desktop no mapping is need. if ((IsProgmanWindow(hWndFrom) && hWndTo == IntPtr.Zero) || (hWndFrom == IntPtr.Zero && IsProgmanWindow(hWndTo))) { lastWin32Error = 0; } ThrowWin32ExceptionsIfError(lastWin32Error); // If the coordinates is at the origin a zero return is valid. // Use GetLastError() to check that. Error code 0 is "Operation completed successfull". return lastWin32Error == 0; } return true; } // wrapper for MapWindowPoints internal static bool MapWindowPoints(IntPtr hWndFrom, IntPtr hWndTo, ref NativeMethods.Win32Point pt, int cPoints) { // The failure case of this API may also be a valid return. GetLastError() is need to determine a true failure state. // Clear the last error code to make sure we have a good starting condition to determine error state. UnsafeNativeMethods.SetLastError(0); int mappingOffset = UnsafeNativeMethods.MapWindowPoints(hWndFrom, hWndTo, ref pt, cPoints); int lastWin32Error = Marshal.GetLastWin32Error(); if (mappingOffset == 0) { // When mapping points to/from Progman and its children MapWindowPoints may fail with error code 1400 // Invalid Window Handle. Since Progman is the desktop no mapping is need. if ((IsProgmanWindow(hWndFrom) && hWndTo == IntPtr.Zero) || (hWndFrom == IntPtr.Zero && IsProgmanWindow(hWndTo))) { lastWin32Error = 0; } ThrowWin32ExceptionsIfError(lastWin32Error); // If the coordinates is at the origin a zero return is valid. // Use GetLastError() to check that. Error code 0 is "Operation completed successfull". return lastWin32Error == 0; } return true; } // Move the mouse to the x, y location and perfoms a mouse clik // The mouse is then brough back to the original location. internal static void MouseClick(int x, int y) { MouseClick(x, y, false); } // Move the mouse to the x, y location and perfoms either // a single of double clik depending on the fDoubleClick parameter // The mouse is then brough back to the original location. internal static void MouseClick(int x, int y, bool fDoubleClick) { NativeMethods.Win32Point ptPrevious = new NativeMethods.Win32Point(); bool fSetOldCursorPos = GetCursorPos(ref ptPrevious); bool mouseSwapped = UnsafeNativeMethods.GetSystemMetrics(NativeMethods.SM_SWAPBUTTON) != 0; Input.SendMouseInput(x, y, 0, SendMouseInputFlags.Move | SendMouseInputFlags.Absolute); Input.SendMouseInput(0, 0, 0, mouseSwapped ? SendMouseInputFlags.RightDown : SendMouseInputFlags.LeftDown); Input.SendMouseInput(0, 0, 0, mouseSwapped ? SendMouseInputFlags.RightUp : SendMouseInputFlags.LeftUp); if (fDoubleClick) { Input.SendMouseInput(0, 0, 0, mouseSwapped ? SendMouseInputFlags.RightDown : SendMouseInputFlags.LeftDown); Input.SendMouseInput(0, 0, 0, mouseSwapped ? SendMouseInputFlags.RightUp : SendMouseInputFlags.LeftUp); } // toolbar items don't have time to proccess the mouse click if we move it back too soon // so wait a small amount of time to give them a chance. A value of 10 made this work // on a 2gig dual proc machine so 50 should cover a slower machine. System.Threading.Thread.Sleep(50); // Set back the mouse position where it was if (fSetOldCursorPos) { Input.SendMouseInput(ptPrevious.x, ptPrevious.y, 0, SendMouseInputFlags.Move | SendMouseInputFlags.Absolute); } } [SecurityPermission(SecurityAction.Demand, UnmanagedCode = true)] internal static int MsgWaitForMultipleObjects(SafeWaitHandle handle, bool waitAll, int milliseconds, int wakeMask) { int terminationEvent, lastWin32Error; if (handle == null) { terminationEvent = UnsafeNativeMethods.MsgWaitForMultipleObjects(0, null, waitAll, milliseconds, wakeMask); lastWin32Error = Marshal.GetLastWin32Error(); } else { RuntimeHelpers.PrepareConstrainedRegions(); bool fRelease = false; try { handle.DangerousAddRef(ref fRelease); IntPtr[] handles = { handle.DangerousGetHandle() }; terminationEvent = UnsafeNativeMethods.MsgWaitForMultipleObjects(1, handles, waitAll, milliseconds, wakeMask); lastWin32Error = Marshal.GetLastWin32Error(); } finally { if (fRelease) { handle.DangerousRelease(); } } } if (terminationEvent == NativeMethods.WAIT_FAILED) { ThrowWin32ExceptionsIfError(lastWin32Error); } return terminationEvent; } internal static IntPtr OpenProcess(int flags, bool inherit, uint processId, IntPtr hwnd) { IntPtr processHandle = UnsafeNativeMethods.OpenProcess(flags, inherit, processId); int lastWin32Error = Marshal.GetLastWin32Error(); // If we fail due to permission issues, if we're on vista, try the hooking technique // to access the process instead. if (processHandle == IntPtr.Zero && lastWin32Error == 5/*ERROR_ACCESS_DENIED*/ && System.Environment.OSVersion.Version.Major >= 6) { try { processHandle = UnsafeNativeMethods.GetProcessHandleFromHwnd(hwnd); lastWin32Error = Marshal.GetLastWin32Error(); } catch(EntryPointNotFoundException) { // Ignore; until OLEACC propogates into Vista builds, the entry point may not be present. } } if (processHandle == IntPtr.Zero) { ThrowWin32ExceptionsIfError(lastWin32Error); } return processHandle; } // wrapper for PostMessage internal static void PostMessage(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam) { bool result = UnsafeNativeMethods.PostMessage(hwnd, msg, wParam, lParam); int lastWin32Error = Marshal.GetLastWin32Error(); if (!result) { ThrowWin32ExceptionsIfError(lastWin32Error); } } // Returns the Win32 Class Name for an hwnd internal static string ProxyGetClassName(IntPtr hwnd) { const int OBJID_QUERYCLASSNAMEIDX = unchecked(unchecked((int)0xFFFFFFF4)); const int QUERYCLASSNAME_BASE = 65536; // Call ProxySendMessage ignoring the timeout // int index = ProxySendMessageInt(hwnd, NativeMethods.WM_GETOBJECT, IntPtr.Zero, (IntPtr)OBJID_QUERYCLASSNAMEIDX, true); if (index >= QUERYCLASSNAME_BASE && index - QUERYCLASSNAME_BASE < _asClassNames.Length) { return _asClassNames[index - QUERYCLASSNAME_BASE]; } else { return RealGetWindowClass(hwnd); } } // wrapper for GetGuiThreadInfo internal static bool ProxyGetGUIThreadInfo(uint idThread, out NativeMethods.GUITHREADINFO gui) { gui = new NativeMethods.GUITHREADINFO(); gui.cbSize = Marshal.SizeOf(gui.GetType()); bool result = UnsafeNativeMethods.GetGUIThreadInfo(idThread, ref gui); int lastWin32Error = Marshal.GetLastWin32Error(); if (!result) { // If the focused thread is on another [secure] desktop, GetGUIThreadInfo // will fail with ERROR_ACCESS_DENIED - don't throw an exception for that case, // instead treat as a failure. Callers will treat this as though no window has // focus. if (lastWin32Error == 5 /*ERROR_ACCESS_DENIED*/) return false; ThrowWin32ExceptionsIfError(lastWin32Error); } #if _NEED_DEBUG_OUTPUT bool fCaretBlink = (gui.dwFlags & NativeMethods.GUI_CARETBLINKING) != 0; bool fMoveSize = (gui.dwFlags & NativeMethods.GUI_INMOVESIZE) != 0; bool fMenuMode = (gui.dwFlags & NativeMethods.GUI_INMENUMODE) != 0; bool fSystemMenuMode = (gui.dwFlags & NativeMethods.GUI_SYSTEMMENUMODE) != 0; bool fPopupMenuMode = (gui.dwFlags & NativeMethods.GUI_POPUPMENUMODE) != 0; StringBuilder sbFlag = new StringBuilder(NativeMethods.MAX_PATH); if (fCaretBlink) { sbFlag.Append("GUI_CARETBLINKING"); } if (fMoveSize) { sbFlag.Append(sbFlag.Length > 0 ? " | GUI_INMOVESIZE" : "GUI_INMOVESIZE"); } if (fMenuMode) { sbFlag.Append(sbFlag.Length > 0 ? " | GUI_INMENUMODE" : "GUI_INMENUMODE"); } if (fSystemMenuMode) { sbFlag.Append(sbFlag.Length > 0 ? " | GUI_SYSTEMMENUMODE" : "GUI_SYSTEMMENUMODE"); } if (fPopupMenuMode) { sbFlag.Append(sbFlag.Length > 0 ? " | GUI_POPUPMENUMODE" : "GUI_POPUPMENUMODE"); } StringBuilder sb = new StringBuilder(NativeMethods.MAX_PATH); sb.Append("GUITHREADINFO \n\r{"); sb.AppendFormat("\n\r\tcbSize = {0}", gui.cbSize); sb.AppendFormat("\n\r\tdwFlags = {0}", gui.dwFlags); if (sbFlag.Length > 0) { sb.Append(" ("); sb.Append(sbFlag); sb.Append(")"); } sb.AppendFormat("\n\r\thwndActive = 0x{0:x8}", gui.hwndActive.ToInt32()); sb.AppendFormat("\n\r\thwndFocus = 0x{0:x8}", gui.hwndFocus.ToInt32()); sb.AppendFormat("\n\r\thwndCapture = 0x{0:x8}", gui.hwndCapture.ToInt32()); sb.AppendFormat("\n\r\thwndMenuOwner = 0x{0:x8}", gui.hwndMenuOwner.ToInt32()); sb.AppendFormat("\n\r\thwndMoveSize = 0x{0:x8}", gui.hwndMoveSize.ToInt32()); sb.AppendFormat("\n\r\thwndCaret = 0x{0:x8}", gui.hwndCaret.ToInt32()); sb.AppendFormat("\n\r\trc = ({0}, {1}, {2}, {3})", gui.rc.left, gui.rc.top, gui.rc.right, gui.rc.bottom); sb.Append("\n\r}"); System.Diagnostics.Debug.WriteLine(sb.ToString()); #endif return result; } // The name text based on the WM_GETTEXT message. The text is truncated to a predefined character // length. internal static string ProxyGetText(IntPtr hwnd) { return ProxyGetText(hwnd, MaxLengthNameProperty); } internal static string ProxyGetText(IntPtr hwnd, int length) { // if the length is zero don't bother asking for the text. if (length == 0) { return ""; } // Length passes to SendMessage includes terminating NUL StringBuilder str = new StringBuilder(length + 1); // Send the message... ProxySendMessage(hwnd, NativeMethods.WM_GETTEXT, (IntPtr)str.Capacity, str); // We don't try to decifer between a zero length string and an error return str.ToString(); } // wrapper for GetTitleBarInfo internal static bool ProxyGetTitleBarInfo(IntPtr hwnd, out UnsafeNativeMethods.TITLEBARINFO ti) { ti = new UnsafeNativeMethods.TITLEBARINFO(); ti.cbSize = Marshal.SizeOf(ti.GetType()); bool result = UnsafeNativeMethods.GetTitleBarInfo(hwnd, ref ti); int lastWin32Error = Marshal.GetLastWin32Error(); if (!result) { ThrowWin32ExceptionsIfError(lastWin32Error); return false; } return true; } internal static bool ProxyGetTitleBarInfoEx(IntPtr hwnd, out UnsafeNativeMethods.TITLEBARINFOEX ti) { ti = new UnsafeNativeMethods.TITLEBARINFOEX(); ti.cbSize = Marshal.SizeOf(ti.GetType()); IntPtr result; IntPtr resultSendMessage = UnsafeNativeMethods.SendMessageTimeout(hwnd, NativeMethods.WM_GETTITLEBARINFOEX, IntPtr.Zero, ref ti, _sendMessageFlags, _sendMessageTimeoutValue, out result); int lastWin32Error = Marshal.GetLastWin32Error(); if (resultSendMessage == IntPtr.Zero) { //Window owner failed to process the message WM_GETTITLEBARINFOEX EvaluateSendMessageTimeoutError(lastWin32Error); } return true; } // Return the bounding rects for titlebar items or null if they are invisible or offscreen internal static Rect [] GetTitlebarRects(IntPtr hwnd) { // Vista and beyond if (System.Environment.OSVersion.Version.Major >= 6) { return GetTitlebarRectsEx(hwnd); } // Up through XP return GetTitlebarRectsXP(hwnd); } internal static Rect GetTitleBarRect(IntPtr hwnd) { UnsafeNativeMethods.TITLEBARINFO ti; if (!Misc.ProxyGetTitleBarInfo(hwnd, out ti) || ti.rcTitleBar.IsEmpty) { return Rect.Empty; } NativeMethods.MENUBARINFO mbi; bool retValue = WindowsMenu.GetMenuBarInfo(hwnd, NativeMethods.OBJID_SYSMENU, 0, out mbi); // Possible that there is no menu int left = (!retValue || mbi.rcBar.IsEmpty) ? ti.rcTitleBar.left : mbi.rcBar.left; return new Rect(left, ti.rcTitleBar.top, ti.rcTitleBar.right - left, ti.rcTitleBar.bottom - ti.rcTitleBar.top); } internal static IntPtr ProxySendMessage(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam) { IntPtr result; IntPtr resultSendMessage = UnsafeNativeMethods.SendMessageTimeout(hwnd, msg, wParam, lParam, _sendMessageFlags, _sendMessageTimeoutValue, out result); int lastWin32Error = Marshal.GetLastWin32Error(); if (resultSendMessage == IntPtr.Zero) { EvaluateSendMessageTimeoutError(lastWin32Error); } return result; } // On a 64-bit platform, the value of the IntPtr is too large to represent as a 32-bit signed integer. // An int is a System.Int32. When an explicit cast of IntPtr to int is done on a 64-bit platform an // OverflowException will occur when the IntPtr value exceeds the range of int. In cases where using // SendMessage to get back int (e.g. an item index or an enum value), this version safely truncates // from IntPtr to int. internal static int ProxySendMessageInt(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam) { IntPtr result = ProxySendMessage(hwnd, msg, wParam, lParam); return unchecked((int)(long)result); } // Same as above but does not throw on timeout // @ internal static IntPtr ProxySendMessage(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, bool ignoreTimeout) { IntPtr result; IntPtr resultSendMessage = UnsafeNativeMethods.SendMessageTimeout(hwnd, msg, wParam, lParam, _sendMessageFlags, _sendMessageTimeoutValue, out result); int lastWin32Error = Marshal.GetLastWin32Error(); if (resultSendMessage == IntPtr.Zero) { EvaluateSendMessageTimeoutError(lastWin32Error, ignoreTimeout); } return result; } // On a 64-bit platform, the value of the IntPtr is too large to represent as a 32-bit signed integer. // An int is a System.Int32. When an explicit cast of IntPtr to int is done on a 64-bit platform an // OverflowException will occur when the IntPtr value exceeds the range of int. In cases where using // SendMessage to get back int (e.g. an item index or an enum value), this version safely truncates // from IntPtr to int. internal static int ProxySendMessageInt(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, bool ignoreTimeout) { IntPtr result = ProxySendMessage(hwnd, msg, wParam, lParam, ignoreTimeout); return unchecked((int)(long)result); } internal static IntPtr ProxySendMessage(IntPtr hwnd, int msg, IntPtr wParam, StringBuilder sb) { IntPtr result; IntPtr resultSendMessage = UnsafeNativeMethods.SendMessageTimeout(hwnd, msg, wParam, sb, _sendMessageFlags, _sendMessageTimeoutValue, out result); int lastWin32Error = Marshal.GetLastWin32Error(); if (resultSendMessage == IntPtr.Zero) { EvaluateSendMessageTimeoutError(lastWin32Error); } return result; } // On a 64-bit platform, the value of the IntPtr is too large to represent as a 32-bit signed integer. // An int is a System.Int32. When an explicit cast of IntPtr to int is done on a 64-bit platform an // OverflowException will occur when the IntPtr value exceeds the range of int. In cases where using // SendMessage to get back int (e.g. an item index or an enum value), this version safely truncates // from IntPtr to int. internal static int ProxySendMessageInt(IntPtr hwnd, int msg, IntPtr wParam, StringBuilder sb) { IntPtr result = ProxySendMessage(hwnd, msg, wParam, sb); return unchecked((int)(long)result); } internal static IntPtr ProxySendMessage(IntPtr hwnd, int msg, IntPtr wParam, ref NativeMethods.Win32Rect lParam) { IntPtr result; IntPtr resultSendMessage = UnsafeNativeMethods.SendMessageTimeout(hwnd, msg, wParam, ref lParam, _sendMessageFlags, _sendMessageTimeoutValue, out result); int lastWin32Error = Marshal.GetLastWin32Error(); if (resultSendMessage == IntPtr.Zero) { EvaluateSendMessageTimeoutError(lastWin32Error); } return result; } internal static IntPtr ProxySendMessage(IntPtr hwnd, int msg, out int wParam, out int lParam) { IntPtr result; IntPtr resultSendMessage = UnsafeNativeMethods.SendMessageTimeout(hwnd, msg, out wParam, out lParam, _sendMessageFlags, _sendMessageTimeoutValue, out result); int lastWin32Error = Marshal.GetLastWin32Error(); if (resultSendMessage == IntPtr.Zero) { EvaluateSendMessageTimeoutError(lastWin32Error); } return result; } // Check if a point is within the bounding Rect of a window internal static bool PtInRect(ref NativeMethods.Win32Rect rc, int x, int y) { return x >= rc.left && x < rc.right && y >= rc.top && y < rc.bottom; } internal static bool PtInRect(ref Rect rc, int x, int y) { return x >= rc.Left && x < rc.Right && y >= rc.Top && y < rc.Bottom; } // Check if a point is within the client Rect of a window internal static bool PtInWindowRect(IntPtr hwnd, int x, int y) { NativeMethods.Win32Rect rc = new NativeMethods.Win32Rect(); if (!GetWindowRect(hwnd, ref rc)) { return false; } return x >= rc.left && x < rc.right && y >= rc.top && y < rc.bottom; } internal static bool ReadProcessMemory(MS.Internal.AutomationProxies.SafeProcessHandle hProcess, IntPtr source, IntPtr dest, IntPtr size, out int bytesRead) { bool result = UnsafeNativeMethods.ReadProcessMemory(hProcess, source, dest, size, out bytesRead); int lastWin32Error = Marshal.GetLastWin32Error(); if (!result) { ThrowWin32ExceptionsIfError(lastWin32Error); } return result; } internal static bool ReadProcessMemory(MS.Internal.AutomationProxies.SafeProcessHandle hProcess, IntPtr source, MS.Internal.AutomationProxies.SafeCoTaskMem destAddress, IntPtr size, out int bytesRead) { bool result = UnsafeNativeMethods.ReadProcessMemory(hProcess, source, destAddress, size, out bytesRead); int lastWin32Error = Marshal.GetLastWin32Error(); if (!result) { ThrowWin32ExceptionsIfError(lastWin32Error); } return result; } // Get the class name internal static string RealGetWindowClass(IntPtr hwnd) { System.Text.StringBuilder className = new System.Text.StringBuilder(NativeMethods.MAX_PATH + 1); uint result = UnsafeNativeMethods.RealGetWindowClass(hwnd, className, NativeMethods.MAX_PATH); int lastWin32Error = Marshal.GetLastWin32Error(); if (result == 0) { ThrowWin32ExceptionsIfError(lastWin32Error); return ""; } return className.ToString(); } internal static bool RegisterHotKey(IntPtr hwnd, short atom, int modifiers, int vk) { bool result = UnsafeNativeMethods.RegisterHotKey(hwnd, atom, modifiers, vk); int lastWin32Error = Marshal.GetLastWin32Error(); if (!result) { ThrowWin32ExceptionsIfError(lastWin32Error); } return result; } internal static int ReleaseDC(IntPtr hwnd, IntPtr hdc) { // If ReleaseDC fails we will not do anything with that information so just ignore the // PRESHARP warnings. #pragma warning suppress 6031, 6523 return UnsafeNativeMethods.ReleaseDC(hwnd, hdc); } internal static int RegisterWindowMessage(string msg) { int result = SafeNativeMethods.RegisterWindowMessage(msg); int lastWin32Error = Marshal.GetLastWin32Error(); if (result == 0) { ThrowWin32ExceptionsIfError(lastWin32Error); } return result; } internal static IntPtr SelectObject(IntPtr hdc, IntPtr hObject) { // There is no indication in the Windows SDK documentation that SelectObject() // will set an error to be retrieved with GetLastError, so set the pragma to ignore // the PRESHARP warning. Anyway if ReleaseDC() fails here, nothing more can be done // since the code is restoring the orginal object and discarding the temp object. #pragma warning suppress 6031, 6523 return UnsafeNativeMethods.SelectObject(hdc, hObject); } internal static int SendInput(int inputs, ref NativeMethods.INPUT ki, int size) { int eventCount = UnsafeNativeMethods.SendInput(inputs, ref ki, size); int lastWin32Error = Marshal.GetLastWin32Error(); if (eventCount <= 0) { ThrowWin32ExceptionsIfError(lastWin32Error); } return eventCount; } // The Win32 call to SetFocus does not do it for hwnd that are // not in the same process as the caller. // This is implemented here to work around this behavior. // Fake keystroke are sent to a specific hwnd to force // Windows to give the focus to that hwnd. static internal bool SetFocus(IntPtr hwnd) { // First Check for ComboLBox // Because it uses Keystrokes it dismisses the ComboLBox string className = RealGetWindowClass(hwnd); if (className == "ComboLBox") return true; // If window is currently Disabled or Invisible no need // to continue if (!SafeNativeMethods.IsWindowVisible(hwnd) || !SafeNativeMethods.IsWindowEnabled(hwnd)) { return false; } // If already focused, leave as-is. Calling SetForegroundWindow // on an already focused HWND will remove focus! if (GetFocusedWindow().Equals(hwnd)) { return true; } // Try calling SetForegroundWindow directly first; it should succeed if we // already have the focus or have UIAccess if (UnsafeNativeMethods.SetForegroundWindow(hwnd)) { return true; } // Use the hotkey technique: // Register a hotkey and send it to ourselves - this gives us the // input, and allows us to call SetForegroundWindow. short atom = GlobalAddAtom("FocusHotKey"); if (atom == 0) { return false; } short vk = 0xB9; bool gotHotkey = false; for (int tries = 0; tries < 10; tries++) { if (RegisterHotKey(IntPtr.Zero, atom, 0, vk)) { gotHotkey = true; break; } vk++; // try another key } if (gotHotkey) { // Get state of modifiers - and temporarilly release them... bool fShiftDown = (UnsafeNativeMethods.GetAsyncKeyState(UnsafeNativeMethods.VK_SHIFT) & unchecked((int)0x80000000)) != 0; bool fAltDown = (UnsafeNativeMethods.GetAsyncKeyState(UnsafeNativeMethods.VK_MENU) & unchecked((int)0x80000000)) != 0; bool fCtrlDown = (UnsafeNativeMethods.GetAsyncKeyState(UnsafeNativeMethods.VK_CONTROL) & unchecked((int)0x80000000)) != 0; if (fShiftDown) Input.SendKeyboardInputVK(UnsafeNativeMethods.VK_SHIFT, false); if (fAltDown) Input.SendKeyboardInputVK(UnsafeNativeMethods.VK_MENU, false); if (fCtrlDown) Input.SendKeyboardInputVK(UnsafeNativeMethods.VK_CONTROL, false); Input.SendKeyboardInputVK(vk, true); Input.SendKeyboardInputVK(vk, false); // Restore release modifier keys... if (fShiftDown) Input.SendKeyboardInputVK(UnsafeNativeMethods.VK_SHIFT, true); if (fAltDown) Input.SendKeyboardInputVK(UnsafeNativeMethods.VK_MENU, true); if (fCtrlDown) Input.SendKeyboardInputVK(UnsafeNativeMethods.VK_CONTROL, true); // Spin in this message loop until we get the hot key while (true) { // If the hotkey input gets lost (eg due to desktop switch), GetMessage may not return - // so use MsgWait first so we can timeout if there's no message present instead of blocking. int result = MsgWaitForMultipleObjects(null, false, 2000, NativeMethods.QS_ALLINPUT); if (result == NativeMethods.WAIT_FAILED || result == NativeMethods.WAIT_TIMEOUT) break; NativeMethods.MSG msg = new NativeMethods.MSG(); if (!GetMessage(ref msg, IntPtr.Zero, 0, 0)) break; // TranslateMessage() will not set an error to be retrieved with GetLastError, // so set the pragma to ignore the PERSHARP warning. // the PERSHARP warning. #pragma warning suppress 6031, 6523 UnsafeNativeMethods.TranslateMessage(ref msg); // From the Windows SDK documentation: // The return value specifies the value returned by the window procedure. // Although its meaning depends on the message being dispatched, the return // value generally is ignored. #pragma warning suppress 6031, 6523 UnsafeNativeMethods.DispatchMessage(ref msg); if (msg.message == NativeMethods.WM_HOTKEY && (short)msg.wParam == atom) { break; } } UnregisterHotKey(IntPtr.Zero, atom); } GlobalDeleteAtom(atom); return UnsafeNativeMethods.SetForegroundWindow(hwnd); } internal static int SetScrollPos(IntPtr hwnd, int bar, int pos, bool redraw) { // NOTE: From Windows SDK Documentaion: // If the function succeeds, the return value is the previous position of the scroll // box. If the desktop is themed and the parent window is a message-only window, // the function returns an incorrect value. // The failure case of this API may also be a valid return. GetLastError() is need to determine a true failure state. // Clear the last error code to make sure we have a good starting condition to determine error state. UnsafeNativeMethods.SetLastError(0); int prevPos = UnsafeNativeMethods.SetScrollPos(hwnd, bar, pos, redraw); int lastWin32Error = Marshal.GetLastWin32Error(); if (prevPos == 0) { ThrowWin32ExceptionsIfError(lastWin32Error); } return prevPos; } internal static IntPtr SetWinEventHook(int eventMin, int eventMax, IntPtr hmodWinEventProc, NativeMethods.WinEventProcDef WinEventReentrancyFilter, uint idProcess, uint idThread, int dwFlags) { // There is no indication in the Windows SDK documentation that SetWinEventHook() // will set an error to be retrieved with GetLastError, so set the pragma to ignore // the PERSHARP warning. #pragma warning suppress 6523 return UnsafeNativeMethods.SetWinEventHook(eventMin, eventMax, hmodWinEventProc, WinEventReentrancyFilter, idProcess, idThread, dwFlags); } // this strips the mnemonic prefix for short cuts as well as leading spaces // If we find && leave one & there. internal static string StripMnemonic(string s) { // If there are no spaces or & then it's ok just return it if (string.IsNullOrEmpty(s) || s.IndexOfAny(new char[2] { ' ', '&' }) < 0) { return s; } char[] ach = s.ToCharArray(); bool amper = false; bool leadingSpace = false; int dest = 0; for (int source = 0; source < ach.Length; source++) { // get rid of leading spaces if (ach[source] == ' ' && leadingSpace == false) { continue; } else { leadingSpace = true; } // get rid of & if (ach[source] == '&' && amper == false) { amper = true; } else { ach[dest++] = ach[source]; } } return new string(ach, 0, dest); } internal static void ThrowWin32ExceptionsIfError(int errorCode) { switch (errorCode) { case 0: // 0 ERROR_SUCCESS The operation completed successfully. // The error code indicates that there is no error, so do not throw an exception. break; case 6: // 6 ERROR_INVALID_HANDLE The handle is invalid. case 1400: // 1400 ERROR_INVALID_WINDOW_HANDLE Invalid window handle. case 1401: // 1401 ERROR_INVALID_MENU_HANDLE Invalid menu handle. case 1402: // 1402 ERROR_INVALID_CURSOR_HANDLE Invalid cursor handle. case 1403: // 1403 ERROR_INVALID_ACCEL_HANDLE Invalid accelerator table handle. case 1404: // 1404 ERROR_INVALID_HOOK_HANDLE Invalid hook handle. case 1405: // 1405 ERROR_INVALID_DWP_HANDLE Invalid handle to a multiple-window position structure. case 1406: // 1406 ERROR_TLW_WITH_WSCHILD Cannot create a top-level child window. case 1407: // 1407 ERROR_CANNOT_FIND_WND_CLASS Cannot find window class. case 1408: // 1408 ERROR_WINDOW_OF_OTHER_THREAD Invalid window; it belongs to other thread. throw new ElementNotAvailableException(); // We're getting this in AMD64 when calling RealGetWindowClass; adding this code // to allow the DRTs to pass while we continue investigation. case 87: // 87 ERROR_INVALID_PARAMETER throw new ElementNotAvailableException(); case 8: // 8 ERROR_NOT_ENOUGH_MEMORY Not enough storage is available to process this command. case 14: // 14 ERROR_OUTOFMEMORY Not enough storage is available to complete this operation. throw new OutOfMemoryException(); case 998: // 998 ERROR_NOACCESS Invalid access to memory location. case 5: // 5 ERROR_ACCESS_DENIED throw new InvalidOperationException(); case 121: // 121 ERROR_SEM_TIMEOUT The semaphore timeout period has expired. case 258: // 258 WAIT_TIMEOUT The wait operation timed out. case 1053: // 1053 ERROR_SERVICE_REQUEST_TIMEOUT The service did not respond to the start or control request in a timely fashion. case 1460: // 1460 ERROR_TIMEOUT This operation returned because the timeout period expired. throw new TimeoutException(); default: // Not sure how to map the reset of the error codes so throw generic Win32Exception. throw new Win32Exception(errorCode); } } internal static bool UnhookWinEvent(IntPtr winEventHook) { // There is no indication in the Windows SDK documentation that UnhookWinEvent() // will set an error to be retrieved with GetLastError, so set the pragma to ignore // the PERSHARP warning. #pragma warning suppress 6523 return UnsafeNativeMethods.UnhookWinEvent(winEventHook); } internal static bool UnionRect(out NativeMethods.Win32Rect rcDst, ref NativeMethods.Win32Rect rc1, ref NativeMethods.Win32Rect rc2) { bool result = SafeNativeMethods.UnionRect(out rcDst, ref rc1, ref rc2); int lastWin32Error = Marshal.GetLastWin32Error(); if (!result) { ThrowWin32ExceptionsIfError(lastWin32Error); } return result; } internal static bool UnregisterHotKey(IntPtr hwnd, short atom) { bool result = UnsafeNativeMethods.UnregisterHotKey(hwnd, atom); int lastWin32Error = Marshal.GetLastWin32Error(); if (!result) { ThrowWin32ExceptionsIfError(lastWin32Error); } return result; } internal static IntPtr VirtualAlloc(IntPtr address, UIntPtr size, int allocationType, int protect) { IntPtr result = UnsafeNativeMethods.VirtualAlloc(address, size, allocationType, protect); int lastWin32Error = Marshal.GetLastWin32Error(); if (result == IntPtr.Zero) { ThrowWin32ExceptionsIfError(lastWin32Error); } return result; } internal static IntPtr VirtualAllocEx(MS.Internal.AutomationProxies.SafeProcessHandle hProcess, IntPtr address, UIntPtr size, int allocationType, int protect) { IntPtr result = UnsafeNativeMethods.VirtualAllocEx(hProcess, address, size, allocationType, protect); int lastWin32Error = Marshal.GetLastWin32Error(); if (result == IntPtr.Zero) { ThrowWin32ExceptionsIfError(lastWin32Error); } return result; } internal static bool VirtualFree(IntPtr address, UIntPtr size, int freeType) { bool result = UnsafeNativeMethods.VirtualFree(address, size, freeType); int lastWin32Error = Marshal.GetLastWin32Error(); if (!result) { ThrowWin32ExceptionsIfError(lastWin32Error); } return result; } internal static bool VirtualFreeEx(MS.Internal.AutomationProxies.SafeProcessHandle hProcess, IntPtr address, UIntPtr size, int freeType) { bool result = UnsafeNativeMethods.VirtualFreeEx(hProcess, address, size, freeType); int lastWin32Error = Marshal.GetLastWin32Error(); if (!result) { ThrowWin32ExceptionsIfError(lastWin32Error); } return result; } internal static bool WriteProcessMemory(MS.Internal.AutomationProxies.SafeProcessHandle hProcess, IntPtr dest, IntPtr sourceAddress, IntPtr size, out int bytesWritten) { bool result = UnsafeNativeMethods.WriteProcessMemory(hProcess, dest, sourceAddress, size, out bytesWritten); int lastWin32Error = Marshal.GetLastWin32Error(); if (!result) { ThrowWin32ExceptionsIfError(lastWin32Error); } return result; } internal static bool IsWindowInGivenProcess(IntPtr hwnd, string targetprocess) { uint processId; //GetWindowThreadProcessId throws ElementNotAvailableException if the hwnd is no longer valid. //But, this exception should be handled by the client accessing this proxy. uint threadId = GetWindowThreadProcessId(hwnd, out processId); try { string processName = System.Diagnostics.Process.GetProcessById((int)processId).ProcessName; if (processName == targetprocess) { return true; } } catch (Exception ex) { if (IsCriticalException(ex)) throw; if (ex is ArgumentException || ex is SystemException) { //The process is no longer running which implies AutomationElement is no longer available. //Let the client handle it. throw new ElementNotAvailableException(); } //All other exceptions are ignored as the purpose of this method is to find whether the hwnd belongs to //a particular process or not. } return false; } internal static bool InTheShellProcess(IntPtr hwnd) { IntPtr hwndShell = SafeNativeMethods.GetShellWindow(); if (hwndShell == IntPtr.Zero) return false; uint idProcessUs; GetWindowThreadProcessId(hwnd, out idProcessUs); uint idProcessShell; GetWindowThreadProcessId(hwndShell, out idProcessShell); return idProcessUs == idProcessShell; } // the windows listview has feature (like group by) in v6 that only exist on // vista and beyond. This lets us test for that. internal static bool IsComctrlV6OnOsVerV6orHigher(IntPtr hwnd) { int commonControlVersion = Misc.ProxySendMessageInt(hwnd, NativeMethods.CCM_GETVERSION, IntPtr.Zero, IntPtr.Zero); if (Environment.OSVersion.Version.Major >= 6 && commonControlVersion >= 6) { return true; } return false; } #endregion // ------------------------------------------------------ // // Internal Fields // // ------------------------------------------------------ #region Internal Fields // Max length for the name internal const int MaxLengthNameProperty = 2000; // Timeout for clearing menus internal const long MenuTimeOut = 100; #endregion // ----------------------------------------------------- // // Private Methods // // ------------------------------------------------------ #region Private Methods private static bool EnumToolTipWindows(IntPtr hwnd, ref UnsafeNativeMethods.ENUMTOOLTIPWINDOWINFO lParam) { // Use ProxyGetClassName here instead of GetClassName(), // since for a winforms tooltip the latter will return // "WindowsForms10.tooltips_class32.app.0.b7ab7b". // Instead, ProxyGetClassName uses WM_GETOBJECT with // OBJID_QUERYCLASSNAMEIDX, which will return the correct answer. if (!ProxyGetClassName(hwnd).Equals("tooltips_class32")) { return true; } NativeMethods.TOOLINFO tool = new NativeMethods.TOOLINFO(); tool.Init(Marshal.SizeOf(typeof(NativeMethods.TOOLINFO))); // For tooltips with ids of 0, MFC will create the tooltip with the flag of TTF_IDISHWND. // TTF_IDISHWND indicates that the uId member is the window handle to the tool. if (lParam.id == 0) { tool.hwnd = Misc.GetParent(lParam.hwnd); tool.uId = unchecked((int)lParam.hwnd); tool.uFlags = NativeMethods.TTF_IDISHWND; } else { tool.hwnd = lParam.hwnd; tool.uId = lParam.id; } string name = XSendMessage.GetItemText(hwnd, tool); // Didn't get anything - continue looking... if (string.IsNullOrEmpty(name)) { return true; } lParam.name = name; // Got it - can stop iterating now. return false; } // Get the size of a page in memory for VirtualAlloc private static uint GetPageSize() { NativeMethods.SYSTEM_INFO sysInfo; UnsafeNativeMethods.GetSystemInfo(out sysInfo); return sysInfo.dwPageSize; } //This function throws corresponding exception depending on the last error. private static void EvaluateSendMessageTimeoutError(int error) { EvaluateSendMessageTimeoutError(error, false); } private static void EvaluateSendMessageTimeoutError(int error, bool ignoreTimeout) { // SendMessageTimeout Function // If the function fails or times out, the return value is zero. To get extended error information, // call GetLastError. If GetLastError returns zero, then the function timed out. // NOTE: The GetLastError after a SendMessageTimeout my also be an ERROR_TIMEOUT depending on the // message. // 1460 This operation returned because the timeout period expired. ERROR_TIMEOUT if (error == 0 || error == 1460) { if (!ignoreTimeout) { throw new TimeoutException(); } } else { ThrowWin32ExceptionsIfError(error); } } private static Rect[] GetTitlebarRectsXP(IntPtr hwnd) { Debug.Assert(System.Environment.OSVersion.Version.Major < 6); UnsafeNativeMethods.TITLEBARINFO tiDL; if (!Misc.ProxyGetTitleBarInfo(hwnd, out tiDL)) { return null; } // Titlebars that are invisible or may not exist should not have a rect if ((tiDL.rgstate[NativeMethods.INDEX_TITLEBAR_SELF] & (NativeMethods.STATE_SYSTEM_INVISIBLE | NativeMethods.STATE_SYSTEM_OFFSCREEN)) != 0) { return null; } // We really should be using the the theme APIs but they give incorrect results with the titlebar buttons so we are reverting back to system metrics // This is not perfect, its a looks like it may be a few pixels of here or there but clicking on the center of the button will be sucessfull. The only place this // does not work is on console windows when the theme is Windows Clasic Style. // The system metric seems to be just bit off, subtracting 1 seems to get a better result on all themes int buttonWidth = UnsafeNativeMethods.GetSystemMetrics(NativeMethods.SM_CXSIZE) - 1; int buttonHeight = UnsafeNativeMethods.GetSystemMetrics(NativeMethods.SM_CYSIZE) - 1; Rect[] rects = new Rect[NativeMethods.CCHILDREN_TITLEBAR + 1]; // Start at the end and work backwards to the system menu. Subtract buttonSize when a child is present. int leftEdge; if (Misc.IsLayoutRTL(hwnd)) { // Right to left mirroring style // This is to take in count for a bug in GetTitleBarInfo(). It does not calculate the // rcTitleBar correctly when the WS_EX_LAYOUTRTL extended style is set. It assumes // SYSMENU is always on the left and removes its space from the wrong side of rcTitleBar. // Use the bounding rectangle of the whole title bar to get the true left boundary. leftEdge = (int)(Misc.GetTitleBarRect(hwnd).Left); for (int i = NativeMethods.INDEX_TITLEBAR_MAC; i > NativeMethods.INDEX_TITLEBAR_SELF; i--) { if ((tiDL.rgstate[i] & NativeMethods.STATE_SYSTEM_INVISIBLE) == 0) { rects[i] = new Rect(leftEdge, tiDL.rcTitleBar.top, buttonWidth, buttonHeight); leftEdge += buttonWidth; } else { rects[i] = Rect.Empty; } } } else { leftEdge = tiDL.rcTitleBar.right - buttonWidth; for (int i = NativeMethods.INDEX_TITLEBAR_MAC; i > NativeMethods.INDEX_TITLEBAR_SELF; i--) { if ((tiDL.rgstate[i] & NativeMethods.STATE_SYSTEM_INVISIBLE) == 0) { rects[i] = new Rect(leftEdge, tiDL.rcTitleBar.top, buttonWidth, buttonHeight); leftEdge -= buttonWidth; } else { rects[i] = Rect.Empty; } } } return rects; } private static Rect[] GetTitlebarRectsEx(IntPtr hwnd) { Debug.Assert(System.Environment.OSVersion.Version.Major >= 6); UnsafeNativeMethods.TITLEBARINFOEX ti; if (!Misc.ProxyGetTitleBarInfoEx(hwnd, out ti)) { return null; } // Titlebars that are invisible or may not exist should not have a rect if ((ti.rgstate[NativeMethods.INDEX_TITLEBAR_SELF] & (NativeMethods.STATE_SYSTEM_INVISIBLE | NativeMethods.STATE_SYSTEM_OFFSCREEN)) != 0) { return null; } Rect[] rects = new Rect[NativeMethods.CCHILDREN_TITLEBAR + 1]; for (int i = 0; i <= NativeMethods.CCHILDREN_TITLEBAR; i++) { // Buttons that are invisible or may not exist should not have a rect if ((ti.rgstate[i] & NativeMethods.STATE_SYSTEM_INVISIBLE) != 0) { rects[i] = Rect.Empty; } else { rects[i] = new Rect(ti.rgrect[i].left, ti.rgrect[i].top, ti.rgrect[i].right - ti.rgrect[i].left, ti.rgrect[i].bottom - ti.rgrect[i].top); } } return rects; } #endregion // ----------------------------------------------------- // // Private Fields // // ----------------------------------------------------- #region Private Fields // Generic flags for SendMessages private const int _sendMessageFlags = NativeMethods.SMTO_BLOCK; // Generic time out for SendMessages // Most messages won't need anything near this - but there are a few - eg. WM_COMMAND/CBN_DROPDOWN // when sent to IE's address combo for the first time causes it to populate iself, and that can // take a couple of seconds on a slow machine. private const int _sendMessageTimeoutValue = 10000; // Array of known class names private static string[] _asClassNames = { "ListBox", "#32768", "Button", "Static", "Edit", "ComboBox", "#32770", "#32771", "MDIClient", "#32769", "ScrollBar", "msctls_statusbar32", "ToolbarWindow32", "msctls_progress32", "SysAnimate32", "SysTabControl32", "msctls_hotkey32", "SysHeader32", "msctls_trackbar32", "SysListView32", "OpenListView", "msctls_updown", "msctls_updown32", "tooltips_class", "tooltips_class32", "SysTreeView32", "SysMonthCal32", "SysDateTimePick32", "RICHEDIT", "RichEdit20A", "RichEdit20W", "SysIPAddress32" }; #endregion } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved. //---------------------------------------------------------------------------- // //// Copyright (C) Microsoft Corporation. All rights reserved. // // // // Description: Miscellaneous helper routines // // History: // 12/06/2004 : Created [....] // //--------------------------------------------------------------------------- // PRESHARP: In order to avoid generating warnings about unkown message numbers and unknown pragmas. #pragma warning disable 1634, 1691 using Microsoft.Win32.SafeHandles; using MS.Win32; using System; using System.Collections; using System.ComponentModel; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Security.Permissions; using System.Text; using System.Windows.Automation; using System.Windows.Automation.Provider; using System.Windows; using System.Windows.Input; using System.Diagnostics; namespace MS.Internal.AutomationProxies { static class Misc { //----------------------------------------------------- // // Internal Methods // //----------------------------------------------------- #region Internal Methods // // HrGetWindowShortcut() // internal static string AccessKey(string s) { // Get the index of the shortcut int iPosShortCut = s.IndexOf('&'); // Did we found an & or is it at the end of the string if (iPosShortCut < 0 || iPosShortCut + 1 >= s.Length) { return null; } // Build the result string return ST.Get(STID.KeyAlt) + "+" + s[iPosShortCut + 1]; } // Extend an existing RunTimeID by one element internal static int[] AppendToRuntimeId(int[] baseID, int id) { // For the base case, where parent is a hwnd, baseID will be null, // so use AppendRuntimeId instead. UIA will then glue that to the ID // of the parent HWND. if(baseID == null) baseID = new int[] { AutomationInteropProvider.AppendRuntimeId }; int len = baseID.Length; int[] newID = new int[len + 1]; baseID.CopyTo(newID, 0); newID[len] = id; return newID; } internal static double[] RectArrayToDoubleArray(Rect[] rectArray) { if (rectArray == null) return null; double[] doubles = new double[rectArray.Length * 4]; int scan = 0; for (int i = 0; i < rectArray.Length; i++) { doubles[scan++] = rectArray[i].X; doubles[scan++] = rectArray[i].Y; doubles[scan++] = rectArray[i].Width; doubles[scan++] = rectArray[i].Height; } return doubles; } // Ensure a window and all its parents are enabled. // If not, throw ElementNotEnabledException. internal static void CheckEnabled(IntPtr hwnd) { if (!IsEnabled(hwnd)) { throw new ElementNotEnabledException(); } } // Checks to see if the process owning the hwnd is currently in menu mode // and takes steps to exit menu mode if it is internal static void ClearMenuMode() { // Check if we're in menu mode with helper method. if (InMenuMode()) { // If we are, send an alt keypress to escape Input.SendKeyboardInput(Key.LeftAlt, true); Input.SendKeyboardInput(Key.LeftAlt, false); // Wait for a few milliseconds for this operation to be completed long dwTicks = (long)Environment.TickCount; // Wait until the action has been completed while (InMenuMode() && ((long)Environment.TickCount - dwTicks) < MenuTimeOut) { // Sleep the shortest amount of time possible while still guaranteeing that some sleep occurs System.Threading.Thread.Sleep(1); } } } internal static bool CloseHandle(IntPtr processHandle) { bool result = UnsafeNativeMethods.CloseHandle(processHandle); int lastWin32Error = Marshal.GetLastWin32Error(); if (!result) { ThrowWin32ExceptionsIfError(lastWin32Error); } return result; } // Compares 2 raw elements and returns true if equal, false otherwise internal static bool Compare(ProxySimple el1, ProxySimple el2) { int[] a1 = el1.GetRuntimeId(); int[] a2 = el2.GetRuntimeId(); int l = a1.Length; if (l != a2.Length) return false; for (int i = 0; i < l; i++) { if (a1[i] != a2[i]) { return false; } } return true; } internal static IntPtr DispatchMessage(ref NativeMethods.MSG msg) { // From the Windows SDK documentation: // The return value specifies the value returned by the window procedure. // Although its meaning depends on the message being dispatched, the return // value generally is ignored. #pragma warning suppress 6031, 6523 return UnsafeNativeMethods.DispatchMessage(ref msg); } internal unsafe static bool EnumChildWindows(IntPtr hwnd, NativeMethods.EnumChildrenCallbackVoid lpEnumFunc, void* lParam) { bool result = UnsafeNativeMethods.EnumChildWindows(hwnd, lpEnumFunc, lParam); int lastWin32Error = Marshal.GetLastWin32Error(); if (!result) { ThrowWin32ExceptionsIfError(lastWin32Error); } return result; } internal static IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string className, string wndName) { // The failure case of this API may also be a valid return. GetLastError() is need to determine a true failure state. // Clear the last error code to make sure we have a good starting condition to determine error state. UnsafeNativeMethods.SetLastError(0); IntPtr result = UnsafeNativeMethods.FindWindowEx(hwndParent, hwndChildAfter, className, wndName); int lastWin32Error = Marshal.GetLastWin32Error(); if (result == IntPtr.Zero) { ThrowWin32ExceptionsIfError(lastWin32Error); } return result; } internal static string GetClassName(IntPtr hwnd) { StringBuilder sb = new StringBuilder(NativeMethods.MAX_PATH + 1); int result = UnsafeNativeMethods.GetClassName(hwnd, sb, NativeMethods.MAX_PATH); int lastWin32Error = Marshal.GetLastWin32Error(); if (result == 0) { ThrowWin32ExceptionsIfError(lastWin32Error); return ""; } return sb.ToString(); } // Get the name of a control and conditionally strip mnemonic. // label is the hwnd of the control that is funtioning as the label. Use GetLabelhwnd to find this. // If stripMnemonic is true, amperstrands characters will be stripped out. internal static string GetControlName(IntPtr label, bool stripMnemonic) { if (label == IntPtr.Zero) { return null; } StringBuilder sb = new StringBuilder(MaxLengthNameProperty); int result = UnsafeNativeMethods.GetWindowText(label, sb, MaxLengthNameProperty); int lastWin32Error = Marshal.GetLastWin32Error(); if (result == 0) { ThrowWin32ExceptionsIfError(lastWin32Error); return null; } return stripMnemonic ? StripMnemonic(sb.ToString()) : sb.ToString(); } internal static bool GetClientRectInScreenCoordinates(IntPtr hwnd, ref NativeMethods.Win32Rect rc) { rc = NativeMethods.Win32Rect.Empty; if (!GetClientRect(hwnd, ref rc)) { return false; } NativeMethods.Win32Point leftTop = new NativeMethods.Win32Point(rc.left, rc.top); if (!MapWindowPoints(hwnd, IntPtr.Zero, ref leftTop, 1)) { return false; } NativeMethods.Win32Point rightBottom = new NativeMethods.Win32Point(rc.right, rc.bottom); if (!MapWindowPoints(hwnd, IntPtr.Zero, ref rightBottom, 1)) { return false; } rc = new NativeMethods.Win32Rect(leftTop.x, leftTop.y, rightBottom.x, rightBottom.y); return true; } internal static bool GetClientRect(IntPtr hwnd, ref NativeMethods.Win32Rect rc) { bool result = UnsafeNativeMethods.GetClientRect(hwnd, ref rc); int lastWin32Error = Marshal.GetLastWin32Error(); if (!result) { ThrowWin32ExceptionsIfError(lastWin32Error); } // When the control is right to left GetClentRect() will return a rectangle with left > right. // Normalize thesee rectangle back to left to right. rc.Normalize(IsLayoutRTL(hwnd)); return result; } internal static bool GetComboBoxInfo(IntPtr hwnd, ref NativeMethods.COMBOBOXINFO cbi) { bool result = UnsafeNativeMethods.GetComboBoxInfo(hwnd, ref cbi); int lastWin32Error = Marshal.GetLastWin32Error(); if (!result) { ThrowWin32ExceptionsIfError(lastWin32Error); } return result; } internal static bool GetCursorPos(ref NativeMethods.Win32Point pt) { // Vista and beyond use GetPhysicalCursorPos which handles DPI issues bool result = (System.Environment.OSVersion.Version.Major >= 6) ? UnsafeNativeMethods.GetPhysicalCursorPos(ref pt) : UnsafeNativeMethods.GetCursorPos(ref pt); int lastWin32Error = Marshal.GetLastWin32Error(); if (!result) { ThrowWin32ExceptionsIfError(lastWin32Error); } return result; } internal static IntPtr GetDC(IntPtr hwnd) { IntPtr hdc = UnsafeNativeMethods.GetDC(hwnd); int lastWin32Error = Marshal.GetLastWin32Error(); if (hdc == IntPtr.Zero) { ThrowWin32ExceptionsIfError(lastWin32Error); } return hdc; } internal static IntPtr GetFocusedWindow() { NativeMethods.GUITHREADINFO gui; return ProxyGetGUIThreadInfo(0, out gui) ? gui.hwndFocus : IntPtr.Zero; } internal static string GetItemToolTipText(IntPtr hwnd, IntPtr hwndToolTip, int item) { if (hwndToolTip != IntPtr.Zero) { // We've found the tooltip window, so we won't need to scan for it. // Got a tooltip window - use it. NativeMethods.TOOLINFO tool = new NativeMethods.TOOLINFO(); tool.Init(Marshal.SizeOf(typeof(NativeMethods.TOOLINFO))); tool.hwnd = hwnd; tool.uId = item; return XSendMessage.GetItemText(hwndToolTip, tool); } else { // Control doesn't know its tooltip window - instead scan for one... // Enum the top-level windows owned by this thread... uint processId; uint threadId = GetWindowThreadProcessId(hwnd, out processId); UnsafeNativeMethods.ENUMTOOLTIPWINDOWINFO info = new UnsafeNativeMethods.ENUMTOOLTIPWINDOWINFO(); info.hwnd = hwnd; info.id = item; info.name = ""; UnsafeNativeMethods.EnumThreadWndProc enumToolTipWindows = new UnsafeNativeMethods.EnumThreadWndProc(EnumToolTipWindows); GCHandle gch = GCHandle.Alloc(enumToolTipWindows); UnsafeNativeMethods.EnumThreadWindows(threadId, enumToolTipWindows, ref info); gch.Free(); return info.name; } } // -------------------------------------------------------------------------- // // GetLabelhwnd() // // This walks backwards among peer windows to find a static field. It stops // if it gets to the front or hits a group/tabstop, just like the dialog // manager does. // // Ported from OleAcc\Client.CPP // ------------------------------------------------------------------------- internal static IntPtr GetLabelhwnd(IntPtr hwnd) { // Sanity check if (!UnsafeNativeMethods.IsWindow(hwnd)) { return IntPtr.Zero; } // Only get labels for child windows - not top-level windows or desktop IntPtr hwndParent = Misc.GetParent(hwnd); if (hwndParent == IntPtr.Zero || hwndParent == UnsafeNativeMethods.GetDesktopWindow()) { return IntPtr.Zero; } IntPtr peer = hwnd; // If GetWindow fails we're going to exit, no need to call Marshal.GetLastWin32Error #pragma warning suppress 56523 while ((peer = UnsafeNativeMethods.GetWindow(peer, NativeMethods.GW_HWNDPREV)) != IntPtr.Zero) { // // Is this a static dude? // int code = Misc.ProxySendMessageInt(peer, NativeMethods.WM_GETDLGCODE, IntPtr.Zero, IntPtr.Zero); if ((code & NativeMethods.DLGC_STATIC) == NativeMethods.DLGC_STATIC) { // // Great, we've found our label. // return peer; } // // Skip invisible controls. // Note that we do this after checking if its a static, so that we give invisible statics a chance. // Using invisible statics is an easy workaround to add names to controls without changing the visual UI. // // If GetWindowLong fails we're going to exit, no need to call Marshal.GetLastWin32Error #pragma warning suppress 56523 int style = UnsafeNativeMethods.GetWindowLong(peer, NativeMethods.GWL_STYLE); if ((style & NativeMethods.WS_VISIBLE) != 0) continue; // // Is this a tabstop or group? If so, bail out now. // if ((style & (NativeMethods.WS_GROUP | NativeMethods.WS_TABSTOP)) != 0) break; } // Failed to find a suitable peer return IntPtr.Zero; } internal static bool GetMenuBarInfo(IntPtr hwnd, int idObject, uint item, ref NativeMethods.MENUBARINFO mbi) { // The failure case of this API may also be a valid return. GetLastError() is need to determine a true failure state. // Clear the last error code to make sure we have a good starting condition to determine error state. UnsafeNativeMethods.SetLastError(0); bool result = UnsafeNativeMethods.GetMenuBarInfo(hwnd, idObject, item, ref mbi); int lastWin32Error = Marshal.GetLastWin32Error(); if (!result) { ThrowWin32ExceptionsIfError(lastWin32Error); } return result; } internal static int GetMenuItemCount(IntPtr hmenu) { int count = UnsafeNativeMethods.GetMenuItemCount(hmenu); int lastWin32Error = Marshal.GetLastWin32Error(); if (count == -1) { ThrowWin32ExceptionsIfError(lastWin32Error); } return count; } internal static bool GetMenuItemInfo(IntPtr hmenu, int item, bool byPosition, ref NativeMethods.MENUITEMINFO menuItemInfo) { bool result = UnsafeNativeMethods.GetMenuItemInfo(hmenu, item, byPosition, ref menuItemInfo); int lastWin32Error = Marshal.GetLastWin32Error(); if (!result) { ThrowWin32ExceptionsIfError(lastWin32Error); } return result; } internal static bool GetMenuItemRect(IntPtr hwnd, IntPtr hmenu, int item, out NativeMethods.Win32Rect rc) { bool result = UnsafeNativeMethods.GetMenuItemRect(hwnd, hmenu, item, out rc); int lastWin32Error = Marshal.GetLastWin32Error(); if (!result) { ThrowWin32ExceptionsIfError(lastWin32Error); } return result; } internal static bool GetMessage(ref NativeMethods.MSG msg, IntPtr hwnd, int msgFilterMin, int msgFilterMax) { int result = UnsafeNativeMethods.GetMessage(ref msg, hwnd, msgFilterMin, msgFilterMax); int lastWin32Error = Marshal.GetLastWin32Error(); bool success = (result != 0 && result != -1); if (!success) { ThrowWin32ExceptionsIfError(lastWin32Error); } return success; } internal static int GetObjectW(IntPtr hObject, int size, ref NativeMethods.LOGFONT lf) { int result = UnsafeNativeMethods.GetObjectW(hObject, size, ref lf); int lastWin32Error = Marshal.GetLastWin32Error(); if (result == 0) { ThrowWin32ExceptionsIfError(lastWin32Error); } return result; } internal static IntPtr GetParent(IntPtr hwnd) { // The failure case of this API may also be a valid return. GetLastError() is need to determine a true failure state. // Clear the last error code to make sure we have a good starting condition to determine error state. UnsafeNativeMethods.SetLastError(0); IntPtr hwndParent = UnsafeNativeMethods.GetAncestor(hwnd, NativeMethods.GA_PARENT); int lastWin32Error = Marshal.GetLastWin32Error(); if (hwndParent == IntPtr.Zero) { ThrowWin32ExceptionsIfError(lastWin32Error); } return hwndParent; } internal static bool GetScrollBarInfo(IntPtr hwnd, int fnBar, ref NativeMethods.ScrollBarInfo sbi) { bool result = UnsafeNativeMethods.GetScrollBarInfo(hwnd, fnBar, ref sbi); int lastWin32Error = Marshal.GetLastWin32Error(); if (!result) { ThrowWin32ExceptionsIfError(lastWin32Error); } return result; } internal static bool GetScrollInfo(IntPtr hwnd, int fnBar, ref NativeMethods.ScrollInfo si) { bool result = UnsafeNativeMethods.GetScrollInfo(hwnd, fnBar, ref si); int lastWin32Error = Marshal.GetLastWin32Error(); if (!result) { // 1447 ERROR_NO_SCROLLBARS The window does not have scroll bars. // If GetScrollInfo() fails with ERROR_NO_SCROLLBARS then there is no scroll information // to get. Just return false saying that GetScrollInfo() could not get the information if (lastWin32Error == 1447) { return false; } ThrowWin32ExceptionsIfError(lastWin32Error); } return result; } internal static int GetTextExtentPoint32(IntPtr hdc, string text, int length, out NativeMethods.SIZE size) { // The failure case of this API may also be a valid return. GetLastError() is need to determine a true failure state. // Clear the last error code to make sure we have a good starting condition to determine error state. UnsafeNativeMethods.SetLastError(0); int result = UnsafeNativeMethods.GetTextExtentPoint32(hdc, text, length, out size); int lastWin32Error = Marshal.GetLastWin32Error(); if (result == 0) { ThrowWin32ExceptionsIfError(lastWin32Error); } return result; } // Calls a message that retrieves a string, but doesn't take a length argument, in a relatively safe manner. // Attempts to rapidly resize in hopes of crashing UI Automation should just crash whatever is rapidly resizing. // Param "hwnd" the Window Handle // Param "uMsg" the Windows Message // Param "wParam" the Windows wParam // Param "maxLength" the size of the string internal static unsafe string GetUnsafeText(IntPtr hwnd, int uMsg, IntPtr wParam, int maxLength) { uint pageSize = GetPageSize(); IntPtr memAddr = IntPtr.Zero; // Ptr to remote mem // calculate the size needed for the string uint cbSize = (uint)((maxLength + 1) * sizeof(char)); // resize it to include enough pages for the string, and an extra guarding page, and one extra page to account for shifts. cbSize = ((cbSize / pageSize) + 3) * pageSize; try { // Allocate the space memAddr = VirtualAlloc(IntPtr.Zero, new UIntPtr(cbSize), UnsafeNativeMethods.MEM_COMMIT, UnsafeNativeMethods.PAGE_READWRITE); // Allocate the Final page as No Access, so any attempt to write to it will GPF VirtualAlloc(new IntPtr((byte *)memAddr.ToPointer() + cbSize - pageSize), new UIntPtr(pageSize), UnsafeNativeMethods.MEM_COMMIT, UnsafeNativeMethods.PAGE_NOACCESS); // Send the message... if (ProxySendMessage(hwnd, uMsg, wParam, memAddr) == IntPtr.Zero) { return ""; } String str = new string((char*)memAddr.ToPointer(), 0, maxLength); // Note: lots of "old world" strings are null terminated // Leaving the null termination in the System.String may lead // to some issues when used with the StringBuilder int nullTermination = str.IndexOf('\0'); if (-1 != nullTermination) { // We need to strip null terminated char and everything behind it from the str str = str.Remove(nullTermination, maxLength - nullTermination); } return str; } finally { // Free the memory if (memAddr != IntPtr.Zero) { VirtualFree(memAddr, UIntPtr.Zero, UnsafeNativeMethods.MEM_RELEASE); } } } internal static IntPtr GetWindow(IntPtr hwnd, int cmd) { // The failure case of this API may also be a valid return. GetLastError() is need to determine a true failure state. // Clear the last error code to make sure we have a good starting condition to determine error state. UnsafeNativeMethods.SetLastError(0); IntPtr resultHwnd = UnsafeNativeMethods.GetWindow(hwnd, cmd); int lastWin32Error = Marshal.GetLastWin32Error(); if (resultHwnd == IntPtr.Zero) { ThrowWin32ExceptionsIfError(lastWin32Error); } return resultHwnd; } // Gets the extended style of the window internal static int GetWindowExStyle(IntPtr hwnd) { // The failure case of this API may also be a valid return. GetLastError() is need to determine a true failure state. // Clear the last error code to make sure we have a good starting condition to determine error state. UnsafeNativeMethods.SetLastError(0); int exstyle = UnsafeNativeMethods.GetWindowLong(hwnd, NativeMethods.GWL_EXSTYLE); int lastWin32Error = Marshal.GetLastWin32Error(); if (exstyle == 0) { ThrowWin32ExceptionsIfError(lastWin32Error); } return exstyle; } // Gets the id of the window internal static int GetWindowId(IntPtr hwnd) { // The failure case of this API may also be a valid return. GetLastError() is need to determine a true failure state. // Clear the last error code to make sure we have a good starting condition to determine error state. UnsafeNativeMethods.SetLastError(0); int id = UnsafeNativeMethods.GetWindowLong(hwnd, NativeMethods.GWL_ID); int lastWin32Error = Marshal.GetLastWin32Error(); if (id == 0) { ThrowWin32ExceptionsIfError(lastWin32Error); } return id; } // Gets the parent of the window internal static IntPtr GetWindowParent(IntPtr hwnd) { // NOTE: This may have issues in 64-bit. // The failure case of this API may also be a valid return. GetLastError() is need to determine a true failure state. // Clear the last error code to make sure we have a good starting condition to determine error state. UnsafeNativeMethods.SetLastError(0); int result = UnsafeNativeMethods.GetWindowLong(hwnd, NativeMethods.GWL_HWNDPARENT); int lastWin32Error = Marshal.GetLastWin32Error(); if (result == 0) { ThrowWin32ExceptionsIfError(lastWin32Error); } return (IntPtr)result; } internal static bool GetWindowRect(IntPtr hwnd, ref NativeMethods.Win32Rect rc) { bool result = UnsafeNativeMethods.GetWindowRect(hwnd, ref rc); int lastWin32Error = Marshal.GetLastWin32Error(); if (!result) { ThrowWin32ExceptionsIfError(lastWin32Error); } return result; } // Gets the style of the window internal static int GetWindowStyle(IntPtr hwnd) { // The failure case of this API may also be a valid return. GetLastError() is need to determine a true failure state. // Clear the last error code to make sure we have a good starting condition to determine error state. UnsafeNativeMethods.SetLastError(0); int style = UnsafeNativeMethods.GetWindowLong(hwnd, NativeMethods.GWL_STYLE); int lastWin32Error = Marshal.GetLastWin32Error(); if (style == 0) { ThrowWin32ExceptionsIfError(lastWin32Error); } return style; } internal static uint GetWindowThreadProcessId(IntPtr hwnd, out uint processId) { // GetWindowThreadProcessId does use SetLastError(). So a call to GetLastError() would be meanless. // Disabling the PreSharp warning. #pragma warning suppress 6523 uint threadId = UnsafeNativeMethods.GetWindowThreadProcessId(hwnd, out processId); if (threadId == 0) { throw new ElementNotAvailableException(); } return threadId; } internal static short GlobalAddAtom(string atomName) { short atom = UnsafeNativeMethods.GlobalAddAtom(atomName); int lastWin32Error = Marshal.GetLastWin32Error(); if (atom == 0) { ThrowWin32ExceptionsIfError(lastWin32Error); } return atom; } internal static short GlobalDeleteAtom(short atom) { // This API does not have an error condition. GetLastError is used to determine if an error occured. // So, clear the last error code to make sure we have a good starting condition to determine error state. UnsafeNativeMethods.SetLastError(0); short result = UnsafeNativeMethods.GlobalDeleteAtom(atom); ThrowWin32ExceptionsIfError(Marshal.GetLastWin32Error()); return result; } // detect if we're in the menu mode internal static bool InMenuMode() { NativeMethods.GUITHREADINFO gui; return (ProxyGetGUIThreadInfo(0, out gui) && (IsBitSet(gui.dwFlags, NativeMethods.GUI_INMENUMODE))); } internal static bool IsBitSet(int flags, int bit) { return (flags & bit) == bit; } // Check if window is really enabled, taking parent state into account. internal static bool IsEnabled(IntPtr hwnd) { // Navigate up parent chain. If any ancestor window is // not enabled, then that has the effect of disabling this window. // All ancestor windows must be enabled for this window to be enabled. for (; ; ) { if (!SafeNativeMethods.IsWindowEnabled(hwnd)) { return false; } hwnd = UnsafeNativeMethods.GetAncestor(hwnd, NativeMethods.GA_PARENT); if (hwnd == IntPtr.Zero) { return true; } } } internal static bool IsControlRTL(IntPtr hwnd) { int exStyle = GetWindowExStyle(hwnd); return IsBitSet(exStyle, NativeMethods.WS_EX_LAYOUTRTL) || IsBitSet(exStyle, NativeMethods.WS_EX_RTLREADING); } internal static bool IsLayoutRTL(IntPtr hwnd) { return IsBitSet(GetWindowExStyle(hwnd), NativeMethods.WS_EX_LAYOUTRTL); } internal static bool IsReadingRTL(IntPtr hwnd) { return IsBitSet(GetWindowExStyle(hwnd), NativeMethods.WS_EX_RTLREADING); } internal static bool IntersectRect(ref NativeMethods.Win32Rect rcDest, ref NativeMethods.Win32Rect rc1, ref NativeMethods.Win32Rect rc2) { bool result = SafeNativeMethods.IntersectRect(ref rcDest, ref rc1, ref rc2); int lastWin32Error = Marshal.GetLastWin32Error(); if (!result) { ThrowWin32ExceptionsIfError(lastWin32Error); } return result; } // Call IsCriticalException w/in a catch-all-exception handler to allow critical exceptions // to be thrown (this is copied from exception handling code in WinForms but feel free to // add new critical exceptions). Usage: // try // { // Somecode(); // } // catch (Exception e) // { // if (Misc.IsCriticalException(e)) // throw; // // ignore non-critical errors from external code // } internal static bool IsCriticalException(Exception e) { return e is NullReferenceException || e is StackOverflowException || e is OutOfMemoryException || e is System.Threading.ThreadAbortException; } // this is to determine is an item is visible. The assumption is that the items here are not hwnds // and that they are clipped by there parent. For example this is called by the WindowsListBox. // In that case the hwnd is the list box and the itemRect would be a list item this code checks to see // if the item is scrolled out of view. static internal bool IsItemVisible(IntPtr hwnd, ref NativeMethods.Win32Rect itemRect) { NativeMethods.Win32Rect clientRect = new NativeMethods.Win32Rect(0, 0, 0, 0); if (!GetClientRectInScreenCoordinates(hwnd, ref clientRect)) return false; NativeMethods.Win32Rect intersection = new NativeMethods.Win32Rect(0, 0, 0, 0); // Returns true if the passed in itemRect overlaps with the client area of the hwnd this API // does not modify clientRect or itemRect return IntersectRect(ref intersection, ref clientRect, ref itemRect); } static internal bool IsItemVisible(ref NativeMethods.Win32Rect parentRect, ref NativeMethods.Win32Rect itemRect) { NativeMethods.Win32Rect intersection = new NativeMethods.Win32Rect(0, 0, 0, 0); // Returns true if the passed in itemRect overlaps with the client area of the hwnd this API // does not modify clientRect or itemRect return IntersectRect(ref intersection, ref parentRect, ref itemRect); } static internal bool IsItemVisible(ref NativeMethods.Win32Rect parentRect, ref Rect itemRect) { NativeMethods.Win32Rect itemRc = new NativeMethods.Win32Rect(itemRect); NativeMethods.Win32Rect intersection = new NativeMethods.Win32Rect(0, 0, 0, 0); // Returns true if the passed in itemRect overlaps with the client area of the hwnd this API // does not modify clientRect or itemRect return IntersectRect(ref intersection, ref parentRect, ref itemRc); } static internal bool IsItemVisible(ref Rect parentRect, ref NativeMethods.Win32Rect itemRect) { NativeMethods.Win32Rect parentRc = new NativeMethods.Win32Rect(parentRect); NativeMethods.Win32Rect intersection = new NativeMethods.Win32Rect(0, 0, 0, 0); // Returns true if the passed in itemRect overlaps with the client area of the hwnd this API // does not modify clientRect or itemRect return IntersectRect(ref intersection, ref parentRc, ref itemRect); } static internal bool IsItemVisible(ref Rect parentRect, ref Rect itemRect) { NativeMethods.Win32Rect itemRc = new NativeMethods.Win32Rect(itemRect); NativeMethods.Win32Rect parentRc = new NativeMethods.Win32Rect(parentRect); NativeMethods.Win32Rect intersection = new NativeMethods.Win32Rect(0, 0, 0, 0); // Returns true if the passed in itemRect overlaps with the client area of the hwnd this API // does not modify clientRect or itemRect return IntersectRect(ref intersection, ref parentRc, ref itemRc); } internal static bool IsProgmanWindow(IntPtr hwnd) { while (hwnd != IntPtr.Zero) { if (GetClassName(hwnd).CompareTo("Progman") == 0) { return true; } hwnd = UnsafeNativeMethods.GetAncestor(hwnd, NativeMethods.GA_PARENT); } return false; } internal static bool IsWow64Process(MS.Internal.AutomationProxies.SafeProcessHandle hProcess, out bool Wow64Process) { bool result = UnsafeNativeMethods.IsWow64Process(hProcess, out Wow64Process); int lastWin32Error = Marshal.GetLastWin32Error(); if (!result) { ThrowWin32ExceptionsIfError(lastWin32Error); } return result; } // wrapper for MapWindowPoints internal static bool MapWindowPoints(IntPtr hWndFrom, IntPtr hWndTo, ref NativeMethods.Win32Rect rect, int cPoints) { // The failure case of this API may also be a valid return. GetLastError() is need to determine a true failure state. // Clear the last error code to make sure we have a good starting condition to determine error state. UnsafeNativeMethods.SetLastError(0); int mappingOffset = UnsafeNativeMethods.MapWindowPoints(hWndFrom, hWndTo, ref rect, cPoints); int lastWin32Error = Marshal.GetLastWin32Error(); if (mappingOffset == 0) { // When mapping points to/from Progman and its children MapWindowPoints may fail with error code 1400 // Invalid Window Handle. Since Progman is the desktop no mapping is need. if ((IsProgmanWindow(hWndFrom) && hWndTo == IntPtr.Zero) || (hWndFrom == IntPtr.Zero && IsProgmanWindow(hWndTo))) { lastWin32Error = 0; } ThrowWin32ExceptionsIfError(lastWin32Error); // If the coordinates is at the origin a zero return is valid. // Use GetLastError() to check that. Error code 0 is "Operation completed successfull". return lastWin32Error == 0; } return true; } // wrapper for MapWindowPoints internal static bool MapWindowPoints(IntPtr hWndFrom, IntPtr hWndTo, ref NativeMethods.Win32Point pt, int cPoints) { // The failure case of this API may also be a valid return. GetLastError() is need to determine a true failure state. // Clear the last error code to make sure we have a good starting condition to determine error state. UnsafeNativeMethods.SetLastError(0); int mappingOffset = UnsafeNativeMethods.MapWindowPoints(hWndFrom, hWndTo, ref pt, cPoints); int lastWin32Error = Marshal.GetLastWin32Error(); if (mappingOffset == 0) { // When mapping points to/from Progman and its children MapWindowPoints may fail with error code 1400 // Invalid Window Handle. Since Progman is the desktop no mapping is need. if ((IsProgmanWindow(hWndFrom) && hWndTo == IntPtr.Zero) || (hWndFrom == IntPtr.Zero && IsProgmanWindow(hWndTo))) { lastWin32Error = 0; } ThrowWin32ExceptionsIfError(lastWin32Error); // If the coordinates is at the origin a zero return is valid. // Use GetLastError() to check that. Error code 0 is "Operation completed successfull". return lastWin32Error == 0; } return true; } // Move the mouse to the x, y location and perfoms a mouse clik // The mouse is then brough back to the original location. internal static void MouseClick(int x, int y) { MouseClick(x, y, false); } // Move the mouse to the x, y location and perfoms either // a single of double clik depending on the fDoubleClick parameter // The mouse is then brough back to the original location. internal static void MouseClick(int x, int y, bool fDoubleClick) { NativeMethods.Win32Point ptPrevious = new NativeMethods.Win32Point(); bool fSetOldCursorPos = GetCursorPos(ref ptPrevious); bool mouseSwapped = UnsafeNativeMethods.GetSystemMetrics(NativeMethods.SM_SWAPBUTTON) != 0; Input.SendMouseInput(x, y, 0, SendMouseInputFlags.Move | SendMouseInputFlags.Absolute); Input.SendMouseInput(0, 0, 0, mouseSwapped ? SendMouseInputFlags.RightDown : SendMouseInputFlags.LeftDown); Input.SendMouseInput(0, 0, 0, mouseSwapped ? SendMouseInputFlags.RightUp : SendMouseInputFlags.LeftUp); if (fDoubleClick) { Input.SendMouseInput(0, 0, 0, mouseSwapped ? SendMouseInputFlags.RightDown : SendMouseInputFlags.LeftDown); Input.SendMouseInput(0, 0, 0, mouseSwapped ? SendMouseInputFlags.RightUp : SendMouseInputFlags.LeftUp); } // toolbar items don't have time to proccess the mouse click if we move it back too soon // so wait a small amount of time to give them a chance. A value of 10 made this work // on a 2gig dual proc machine so 50 should cover a slower machine. System.Threading.Thread.Sleep(50); // Set back the mouse position where it was if (fSetOldCursorPos) { Input.SendMouseInput(ptPrevious.x, ptPrevious.y, 0, SendMouseInputFlags.Move | SendMouseInputFlags.Absolute); } } [SecurityPermission(SecurityAction.Demand, UnmanagedCode = true)] internal static int MsgWaitForMultipleObjects(SafeWaitHandle handle, bool waitAll, int milliseconds, int wakeMask) { int terminationEvent, lastWin32Error; if (handle == null) { terminationEvent = UnsafeNativeMethods.MsgWaitForMultipleObjects(0, null, waitAll, milliseconds, wakeMask); lastWin32Error = Marshal.GetLastWin32Error(); } else { RuntimeHelpers.PrepareConstrainedRegions(); bool fRelease = false; try { handle.DangerousAddRef(ref fRelease); IntPtr[] handles = { handle.DangerousGetHandle() }; terminationEvent = UnsafeNativeMethods.MsgWaitForMultipleObjects(1, handles, waitAll, milliseconds, wakeMask); lastWin32Error = Marshal.GetLastWin32Error(); } finally { if (fRelease) { handle.DangerousRelease(); } } } if (terminationEvent == NativeMethods.WAIT_FAILED) { ThrowWin32ExceptionsIfError(lastWin32Error); } return terminationEvent; } internal static IntPtr OpenProcess(int flags, bool inherit, uint processId, IntPtr hwnd) { IntPtr processHandle = UnsafeNativeMethods.OpenProcess(flags, inherit, processId); int lastWin32Error = Marshal.GetLastWin32Error(); // If we fail due to permission issues, if we're on vista, try the hooking technique // to access the process instead. if (processHandle == IntPtr.Zero && lastWin32Error == 5/*ERROR_ACCESS_DENIED*/ && System.Environment.OSVersion.Version.Major >= 6) { try { processHandle = UnsafeNativeMethods.GetProcessHandleFromHwnd(hwnd); lastWin32Error = Marshal.GetLastWin32Error(); } catch(EntryPointNotFoundException) { // Ignore; until OLEACC propogates into Vista builds, the entry point may not be present. } } if (processHandle == IntPtr.Zero) { ThrowWin32ExceptionsIfError(lastWin32Error); } return processHandle; } // wrapper for PostMessage internal static void PostMessage(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam) { bool result = UnsafeNativeMethods.PostMessage(hwnd, msg, wParam, lParam); int lastWin32Error = Marshal.GetLastWin32Error(); if (!result) { ThrowWin32ExceptionsIfError(lastWin32Error); } } // Returns the Win32 Class Name for an hwnd internal static string ProxyGetClassName(IntPtr hwnd) { const int OBJID_QUERYCLASSNAMEIDX = unchecked(unchecked((int)0xFFFFFFF4)); const int QUERYCLASSNAME_BASE = 65536; // Call ProxySendMessage ignoring the timeout // int index = ProxySendMessageInt(hwnd, NativeMethods.WM_GETOBJECT, IntPtr.Zero, (IntPtr)OBJID_QUERYCLASSNAMEIDX, true); if (index >= QUERYCLASSNAME_BASE && index - QUERYCLASSNAME_BASE < _asClassNames.Length) { return _asClassNames[index - QUERYCLASSNAME_BASE]; } else { return RealGetWindowClass(hwnd); } } // wrapper for GetGuiThreadInfo internal static bool ProxyGetGUIThreadInfo(uint idThread, out NativeMethods.GUITHREADINFO gui) { gui = new NativeMethods.GUITHREADINFO(); gui.cbSize = Marshal.SizeOf(gui.GetType()); bool result = UnsafeNativeMethods.GetGUIThreadInfo(idThread, ref gui); int lastWin32Error = Marshal.GetLastWin32Error(); if (!result) { // If the focused thread is on another [secure] desktop, GetGUIThreadInfo // will fail with ERROR_ACCESS_DENIED - don't throw an exception for that case, // instead treat as a failure. Callers will treat this as though no window has // focus. if (lastWin32Error == 5 /*ERROR_ACCESS_DENIED*/) return false; ThrowWin32ExceptionsIfError(lastWin32Error); } #if _NEED_DEBUG_OUTPUT bool fCaretBlink = (gui.dwFlags & NativeMethods.GUI_CARETBLINKING) != 0; bool fMoveSize = (gui.dwFlags & NativeMethods.GUI_INMOVESIZE) != 0; bool fMenuMode = (gui.dwFlags & NativeMethods.GUI_INMENUMODE) != 0; bool fSystemMenuMode = (gui.dwFlags & NativeMethods.GUI_SYSTEMMENUMODE) != 0; bool fPopupMenuMode = (gui.dwFlags & NativeMethods.GUI_POPUPMENUMODE) != 0; StringBuilder sbFlag = new StringBuilder(NativeMethods.MAX_PATH); if (fCaretBlink) { sbFlag.Append("GUI_CARETBLINKING"); } if (fMoveSize) { sbFlag.Append(sbFlag.Length > 0 ? " | GUI_INMOVESIZE" : "GUI_INMOVESIZE"); } if (fMenuMode) { sbFlag.Append(sbFlag.Length > 0 ? " | GUI_INMENUMODE" : "GUI_INMENUMODE"); } if (fSystemMenuMode) { sbFlag.Append(sbFlag.Length > 0 ? " | GUI_SYSTEMMENUMODE" : "GUI_SYSTEMMENUMODE"); } if (fPopupMenuMode) { sbFlag.Append(sbFlag.Length > 0 ? " | GUI_POPUPMENUMODE" : "GUI_POPUPMENUMODE"); } StringBuilder sb = new StringBuilder(NativeMethods.MAX_PATH); sb.Append("GUITHREADINFO \n\r{"); sb.AppendFormat("\n\r\tcbSize = {0}", gui.cbSize); sb.AppendFormat("\n\r\tdwFlags = {0}", gui.dwFlags); if (sbFlag.Length > 0) { sb.Append(" ("); sb.Append(sbFlag); sb.Append(")"); } sb.AppendFormat("\n\r\thwndActive = 0x{0:x8}", gui.hwndActive.ToInt32()); sb.AppendFormat("\n\r\thwndFocus = 0x{0:x8}", gui.hwndFocus.ToInt32()); sb.AppendFormat("\n\r\thwndCapture = 0x{0:x8}", gui.hwndCapture.ToInt32()); sb.AppendFormat("\n\r\thwndMenuOwner = 0x{0:x8}", gui.hwndMenuOwner.ToInt32()); sb.AppendFormat("\n\r\thwndMoveSize = 0x{0:x8}", gui.hwndMoveSize.ToInt32()); sb.AppendFormat("\n\r\thwndCaret = 0x{0:x8}", gui.hwndCaret.ToInt32()); sb.AppendFormat("\n\r\trc = ({0}, {1}, {2}, {3})", gui.rc.left, gui.rc.top, gui.rc.right, gui.rc.bottom); sb.Append("\n\r}"); System.Diagnostics.Debug.WriteLine(sb.ToString()); #endif return result; } // The name text based on the WM_GETTEXT message. The text is truncated to a predefined character // length. internal static string ProxyGetText(IntPtr hwnd) { return ProxyGetText(hwnd, MaxLengthNameProperty); } internal static string ProxyGetText(IntPtr hwnd, int length) { // if the length is zero don't bother asking for the text. if (length == 0) { return ""; } // Length passes to SendMessage includes terminating NUL StringBuilder str = new StringBuilder(length + 1); // Send the message... ProxySendMessage(hwnd, NativeMethods.WM_GETTEXT, (IntPtr)str.Capacity, str); // We don't try to decifer between a zero length string and an error return str.ToString(); } // wrapper for GetTitleBarInfo internal static bool ProxyGetTitleBarInfo(IntPtr hwnd, out UnsafeNativeMethods.TITLEBARINFO ti) { ti = new UnsafeNativeMethods.TITLEBARINFO(); ti.cbSize = Marshal.SizeOf(ti.GetType()); bool result = UnsafeNativeMethods.GetTitleBarInfo(hwnd, ref ti); int lastWin32Error = Marshal.GetLastWin32Error(); if (!result) { ThrowWin32ExceptionsIfError(lastWin32Error); return false; } return true; } internal static bool ProxyGetTitleBarInfoEx(IntPtr hwnd, out UnsafeNativeMethods.TITLEBARINFOEX ti) { ti = new UnsafeNativeMethods.TITLEBARINFOEX(); ti.cbSize = Marshal.SizeOf(ti.GetType()); IntPtr result; IntPtr resultSendMessage = UnsafeNativeMethods.SendMessageTimeout(hwnd, NativeMethods.WM_GETTITLEBARINFOEX, IntPtr.Zero, ref ti, _sendMessageFlags, _sendMessageTimeoutValue, out result); int lastWin32Error = Marshal.GetLastWin32Error(); if (resultSendMessage == IntPtr.Zero) { //Window owner failed to process the message WM_GETTITLEBARINFOEX EvaluateSendMessageTimeoutError(lastWin32Error); } return true; } // Return the bounding rects for titlebar items or null if they are invisible or offscreen internal static Rect [] GetTitlebarRects(IntPtr hwnd) { // Vista and beyond if (System.Environment.OSVersion.Version.Major >= 6) { return GetTitlebarRectsEx(hwnd); } // Up through XP return GetTitlebarRectsXP(hwnd); } internal static Rect GetTitleBarRect(IntPtr hwnd) { UnsafeNativeMethods.TITLEBARINFO ti; if (!Misc.ProxyGetTitleBarInfo(hwnd, out ti) || ti.rcTitleBar.IsEmpty) { return Rect.Empty; } NativeMethods.MENUBARINFO mbi; bool retValue = WindowsMenu.GetMenuBarInfo(hwnd, NativeMethods.OBJID_SYSMENU, 0, out mbi); // Possible that there is no menu int left = (!retValue || mbi.rcBar.IsEmpty) ? ti.rcTitleBar.left : mbi.rcBar.left; return new Rect(left, ti.rcTitleBar.top, ti.rcTitleBar.right - left, ti.rcTitleBar.bottom - ti.rcTitleBar.top); } internal static IntPtr ProxySendMessage(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam) { IntPtr result; IntPtr resultSendMessage = UnsafeNativeMethods.SendMessageTimeout(hwnd, msg, wParam, lParam, _sendMessageFlags, _sendMessageTimeoutValue, out result); int lastWin32Error = Marshal.GetLastWin32Error(); if (resultSendMessage == IntPtr.Zero) { EvaluateSendMessageTimeoutError(lastWin32Error); } return result; } // On a 64-bit platform, the value of the IntPtr is too large to represent as a 32-bit signed integer. // An int is a System.Int32. When an explicit cast of IntPtr to int is done on a 64-bit platform an // OverflowException will occur when the IntPtr value exceeds the range of int. In cases where using // SendMessage to get back int (e.g. an item index or an enum value), this version safely truncates // from IntPtr to int. internal static int ProxySendMessageInt(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam) { IntPtr result = ProxySendMessage(hwnd, msg, wParam, lParam); return unchecked((int)(long)result); } // Same as above but does not throw on timeout // @ internal static IntPtr ProxySendMessage(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, bool ignoreTimeout) { IntPtr result; IntPtr resultSendMessage = UnsafeNativeMethods.SendMessageTimeout(hwnd, msg, wParam, lParam, _sendMessageFlags, _sendMessageTimeoutValue, out result); int lastWin32Error = Marshal.GetLastWin32Error(); if (resultSendMessage == IntPtr.Zero) { EvaluateSendMessageTimeoutError(lastWin32Error, ignoreTimeout); } return result; } // On a 64-bit platform, the value of the IntPtr is too large to represent as a 32-bit signed integer. // An int is a System.Int32. When an explicit cast of IntPtr to int is done on a 64-bit platform an // OverflowException will occur when the IntPtr value exceeds the range of int. In cases where using // SendMessage to get back int (e.g. an item index or an enum value), this version safely truncates // from IntPtr to int. internal static int ProxySendMessageInt(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, bool ignoreTimeout) { IntPtr result = ProxySendMessage(hwnd, msg, wParam, lParam, ignoreTimeout); return unchecked((int)(long)result); } internal static IntPtr ProxySendMessage(IntPtr hwnd, int msg, IntPtr wParam, StringBuilder sb) { IntPtr result; IntPtr resultSendMessage = UnsafeNativeMethods.SendMessageTimeout(hwnd, msg, wParam, sb, _sendMessageFlags, _sendMessageTimeoutValue, out result); int lastWin32Error = Marshal.GetLastWin32Error(); if (resultSendMessage == IntPtr.Zero) { EvaluateSendMessageTimeoutError(lastWin32Error); } return result; } // On a 64-bit platform, the value of the IntPtr is too large to represent as a 32-bit signed integer. // An int is a System.Int32. When an explicit cast of IntPtr to int is done on a 64-bit platform an // OverflowException will occur when the IntPtr value exceeds the range of int. In cases where using // SendMessage to get back int (e.g. an item index or an enum value), this version safely truncates // from IntPtr to int. internal static int ProxySendMessageInt(IntPtr hwnd, int msg, IntPtr wParam, StringBuilder sb) { IntPtr result = ProxySendMessage(hwnd, msg, wParam, sb); return unchecked((int)(long)result); } internal static IntPtr ProxySendMessage(IntPtr hwnd, int msg, IntPtr wParam, ref NativeMethods.Win32Rect lParam) { IntPtr result; IntPtr resultSendMessage = UnsafeNativeMethods.SendMessageTimeout(hwnd, msg, wParam, ref lParam, _sendMessageFlags, _sendMessageTimeoutValue, out result); int lastWin32Error = Marshal.GetLastWin32Error(); if (resultSendMessage == IntPtr.Zero) { EvaluateSendMessageTimeoutError(lastWin32Error); } return result; } internal static IntPtr ProxySendMessage(IntPtr hwnd, int msg, out int wParam, out int lParam) { IntPtr result; IntPtr resultSendMessage = UnsafeNativeMethods.SendMessageTimeout(hwnd, msg, out wParam, out lParam, _sendMessageFlags, _sendMessageTimeoutValue, out result); int lastWin32Error = Marshal.GetLastWin32Error(); if (resultSendMessage == IntPtr.Zero) { EvaluateSendMessageTimeoutError(lastWin32Error); } return result; } // Check if a point is within the bounding Rect of a window internal static bool PtInRect(ref NativeMethods.Win32Rect rc, int x, int y) { return x >= rc.left && x < rc.right && y >= rc.top && y < rc.bottom; } internal static bool PtInRect(ref Rect rc, int x, int y) { return x >= rc.Left && x < rc.Right && y >= rc.Top && y < rc.Bottom; } // Check if a point is within the client Rect of a window internal static bool PtInWindowRect(IntPtr hwnd, int x, int y) { NativeMethods.Win32Rect rc = new NativeMethods.Win32Rect(); if (!GetWindowRect(hwnd, ref rc)) { return false; } return x >= rc.left && x < rc.right && y >= rc.top && y < rc.bottom; } internal static bool ReadProcessMemory(MS.Internal.AutomationProxies.SafeProcessHandle hProcess, IntPtr source, IntPtr dest, IntPtr size, out int bytesRead) { bool result = UnsafeNativeMethods.ReadProcessMemory(hProcess, source, dest, size, out bytesRead); int lastWin32Error = Marshal.GetLastWin32Error(); if (!result) { ThrowWin32ExceptionsIfError(lastWin32Error); } return result; } internal static bool ReadProcessMemory(MS.Internal.AutomationProxies.SafeProcessHandle hProcess, IntPtr source, MS.Internal.AutomationProxies.SafeCoTaskMem destAddress, IntPtr size, out int bytesRead) { bool result = UnsafeNativeMethods.ReadProcessMemory(hProcess, source, destAddress, size, out bytesRead); int lastWin32Error = Marshal.GetLastWin32Error(); if (!result) { ThrowWin32ExceptionsIfError(lastWin32Error); } return result; } // Get the class name internal static string RealGetWindowClass(IntPtr hwnd) { System.Text.StringBuilder className = new System.Text.StringBuilder(NativeMethods.MAX_PATH + 1); uint result = UnsafeNativeMethods.RealGetWindowClass(hwnd, className, NativeMethods.MAX_PATH); int lastWin32Error = Marshal.GetLastWin32Error(); if (result == 0) { ThrowWin32ExceptionsIfError(lastWin32Error); return ""; } return className.ToString(); } internal static bool RegisterHotKey(IntPtr hwnd, short atom, int modifiers, int vk) { bool result = UnsafeNativeMethods.RegisterHotKey(hwnd, atom, modifiers, vk); int lastWin32Error = Marshal.GetLastWin32Error(); if (!result) { ThrowWin32ExceptionsIfError(lastWin32Error); } return result; } internal static int ReleaseDC(IntPtr hwnd, IntPtr hdc) { // If ReleaseDC fails we will not do anything with that information so just ignore the // PRESHARP warnings. #pragma warning suppress 6031, 6523 return UnsafeNativeMethods.ReleaseDC(hwnd, hdc); } internal static int RegisterWindowMessage(string msg) { int result = SafeNativeMethods.RegisterWindowMessage(msg); int lastWin32Error = Marshal.GetLastWin32Error(); if (result == 0) { ThrowWin32ExceptionsIfError(lastWin32Error); } return result; } internal static IntPtr SelectObject(IntPtr hdc, IntPtr hObject) { // There is no indication in the Windows SDK documentation that SelectObject() // will set an error to be retrieved with GetLastError, so set the pragma to ignore // the PRESHARP warning. Anyway if ReleaseDC() fails here, nothing more can be done // since the code is restoring the orginal object and discarding the temp object. #pragma warning suppress 6031, 6523 return UnsafeNativeMethods.SelectObject(hdc, hObject); } internal static int SendInput(int inputs, ref NativeMethods.INPUT ki, int size) { int eventCount = UnsafeNativeMethods.SendInput(inputs, ref ki, size); int lastWin32Error = Marshal.GetLastWin32Error(); if (eventCount <= 0) { ThrowWin32ExceptionsIfError(lastWin32Error); } return eventCount; } // The Win32 call to SetFocus does not do it for hwnd that are // not in the same process as the caller. // This is implemented here to work around this behavior. // Fake keystroke are sent to a specific hwnd to force // Windows to give the focus to that hwnd. static internal bool SetFocus(IntPtr hwnd) { // First Check for ComboLBox // Because it uses Keystrokes it dismisses the ComboLBox string className = RealGetWindowClass(hwnd); if (className == "ComboLBox") return true; // If window is currently Disabled or Invisible no need // to continue if (!SafeNativeMethods.IsWindowVisible(hwnd) || !SafeNativeMethods.IsWindowEnabled(hwnd)) { return false; } // If already focused, leave as-is. Calling SetForegroundWindow // on an already focused HWND will remove focus! if (GetFocusedWindow().Equals(hwnd)) { return true; } // Try calling SetForegroundWindow directly first; it should succeed if we // already have the focus or have UIAccess if (UnsafeNativeMethods.SetForegroundWindow(hwnd)) { return true; } // Use the hotkey technique: // Register a hotkey and send it to ourselves - this gives us the // input, and allows us to call SetForegroundWindow. short atom = GlobalAddAtom("FocusHotKey"); if (atom == 0) { return false; } short vk = 0xB9; bool gotHotkey = false; for (int tries = 0; tries < 10; tries++) { if (RegisterHotKey(IntPtr.Zero, atom, 0, vk)) { gotHotkey = true; break; } vk++; // try another key } if (gotHotkey) { // Get state of modifiers - and temporarilly release them... bool fShiftDown = (UnsafeNativeMethods.GetAsyncKeyState(UnsafeNativeMethods.VK_SHIFT) & unchecked((int)0x80000000)) != 0; bool fAltDown = (UnsafeNativeMethods.GetAsyncKeyState(UnsafeNativeMethods.VK_MENU) & unchecked((int)0x80000000)) != 0; bool fCtrlDown = (UnsafeNativeMethods.GetAsyncKeyState(UnsafeNativeMethods.VK_CONTROL) & unchecked((int)0x80000000)) != 0; if (fShiftDown) Input.SendKeyboardInputVK(UnsafeNativeMethods.VK_SHIFT, false); if (fAltDown) Input.SendKeyboardInputVK(UnsafeNativeMethods.VK_MENU, false); if (fCtrlDown) Input.SendKeyboardInputVK(UnsafeNativeMethods.VK_CONTROL, false); Input.SendKeyboardInputVK(vk, true); Input.SendKeyboardInputVK(vk, false); // Restore release modifier keys... if (fShiftDown) Input.SendKeyboardInputVK(UnsafeNativeMethods.VK_SHIFT, true); if (fAltDown) Input.SendKeyboardInputVK(UnsafeNativeMethods.VK_MENU, true); if (fCtrlDown) Input.SendKeyboardInputVK(UnsafeNativeMethods.VK_CONTROL, true); // Spin in this message loop until we get the hot key while (true) { // If the hotkey input gets lost (eg due to desktop switch), GetMessage may not return - // so use MsgWait first so we can timeout if there's no message present instead of blocking. int result = MsgWaitForMultipleObjects(null, false, 2000, NativeMethods.QS_ALLINPUT); if (result == NativeMethods.WAIT_FAILED || result == NativeMethods.WAIT_TIMEOUT) break; NativeMethods.MSG msg = new NativeMethods.MSG(); if (!GetMessage(ref msg, IntPtr.Zero, 0, 0)) break; // TranslateMessage() will not set an error to be retrieved with GetLastError, // so set the pragma to ignore the PERSHARP warning. // the PERSHARP warning. #pragma warning suppress 6031, 6523 UnsafeNativeMethods.TranslateMessage(ref msg); // From the Windows SDK documentation: // The return value specifies the value returned by the window procedure. // Although its meaning depends on the message being dispatched, the return // value generally is ignored. #pragma warning suppress 6031, 6523 UnsafeNativeMethods.DispatchMessage(ref msg); if (msg.message == NativeMethods.WM_HOTKEY && (short)msg.wParam == atom) { break; } } UnregisterHotKey(IntPtr.Zero, atom); } GlobalDeleteAtom(atom); return UnsafeNativeMethods.SetForegroundWindow(hwnd); } internal static int SetScrollPos(IntPtr hwnd, int bar, int pos, bool redraw) { // NOTE: From Windows SDK Documentaion: // If the function succeeds, the return value is the previous position of the scroll // box. If the desktop is themed and the parent window is a message-only window, // the function returns an incorrect value. // The failure case of this API may also be a valid return. GetLastError() is need to determine a true failure state. // Clear the last error code to make sure we have a good starting condition to determine error state. UnsafeNativeMethods.SetLastError(0); int prevPos = UnsafeNativeMethods.SetScrollPos(hwnd, bar, pos, redraw); int lastWin32Error = Marshal.GetLastWin32Error(); if (prevPos == 0) { ThrowWin32ExceptionsIfError(lastWin32Error); } return prevPos; } internal static IntPtr SetWinEventHook(int eventMin, int eventMax, IntPtr hmodWinEventProc, NativeMethods.WinEventProcDef WinEventReentrancyFilter, uint idProcess, uint idThread, int dwFlags) { // There is no indication in the Windows SDK documentation that SetWinEventHook() // will set an error to be retrieved with GetLastError, so set the pragma to ignore // the PERSHARP warning. #pragma warning suppress 6523 return UnsafeNativeMethods.SetWinEventHook(eventMin, eventMax, hmodWinEventProc, WinEventReentrancyFilter, idProcess, idThread, dwFlags); } // this strips the mnemonic prefix for short cuts as well as leading spaces // If we find && leave one & there. internal static string StripMnemonic(string s) { // If there are no spaces or & then it's ok just return it if (string.IsNullOrEmpty(s) || s.IndexOfAny(new char[2] { ' ', '&' }) < 0) { return s; } char[] ach = s.ToCharArray(); bool amper = false; bool leadingSpace = false; int dest = 0; for (int source = 0; source < ach.Length; source++) { // get rid of leading spaces if (ach[source] == ' ' && leadingSpace == false) { continue; } else { leadingSpace = true; } // get rid of & if (ach[source] == '&' && amper == false) { amper = true; } else { ach[dest++] = ach[source]; } } return new string(ach, 0, dest); } internal static void ThrowWin32ExceptionsIfError(int errorCode) { switch (errorCode) { case 0: // 0 ERROR_SUCCESS The operation completed successfully. // The error code indicates that there is no error, so do not throw an exception. break; case 6: // 6 ERROR_INVALID_HANDLE The handle is invalid. case 1400: // 1400 ERROR_INVALID_WINDOW_HANDLE Invalid window handle. case 1401: // 1401 ERROR_INVALID_MENU_HANDLE Invalid menu handle. case 1402: // 1402 ERROR_INVALID_CURSOR_HANDLE Invalid cursor handle. case 1403: // 1403 ERROR_INVALID_ACCEL_HANDLE Invalid accelerator table handle. case 1404: // 1404 ERROR_INVALID_HOOK_HANDLE Invalid hook handle. case 1405: // 1405 ERROR_INVALID_DWP_HANDLE Invalid handle to a multiple-window position structure. case 1406: // 1406 ERROR_TLW_WITH_WSCHILD Cannot create a top-level child window. case 1407: // 1407 ERROR_CANNOT_FIND_WND_CLASS Cannot find window class. case 1408: // 1408 ERROR_WINDOW_OF_OTHER_THREAD Invalid window; it belongs to other thread. throw new ElementNotAvailableException(); // We're getting this in AMD64 when calling RealGetWindowClass; adding this code // to allow the DRTs to pass while we continue investigation. case 87: // 87 ERROR_INVALID_PARAMETER throw new ElementNotAvailableException(); case 8: // 8 ERROR_NOT_ENOUGH_MEMORY Not enough storage is available to process this command. case 14: // 14 ERROR_OUTOFMEMORY Not enough storage is available to complete this operation. throw new OutOfMemoryException(); case 998: // 998 ERROR_NOACCESS Invalid access to memory location. case 5: // 5 ERROR_ACCESS_DENIED throw new InvalidOperationException(); case 121: // 121 ERROR_SEM_TIMEOUT The semaphore timeout period has expired. case 258: // 258 WAIT_TIMEOUT The wait operation timed out. case 1053: // 1053 ERROR_SERVICE_REQUEST_TIMEOUT The service did not respond to the start or control request in a timely fashion. case 1460: // 1460 ERROR_TIMEOUT This operation returned because the timeout period expired. throw new TimeoutException(); default: // Not sure how to map the reset of the error codes so throw generic Win32Exception. throw new Win32Exception(errorCode); } } internal static bool UnhookWinEvent(IntPtr winEventHook) { // There is no indication in the Windows SDK documentation that UnhookWinEvent() // will set an error to be retrieved with GetLastError, so set the pragma to ignore // the PERSHARP warning. #pragma warning suppress 6523 return UnsafeNativeMethods.UnhookWinEvent(winEventHook); } internal static bool UnionRect(out NativeMethods.Win32Rect rcDst, ref NativeMethods.Win32Rect rc1, ref NativeMethods.Win32Rect rc2) { bool result = SafeNativeMethods.UnionRect(out rcDst, ref rc1, ref rc2); int lastWin32Error = Marshal.GetLastWin32Error(); if (!result) { ThrowWin32ExceptionsIfError(lastWin32Error); } return result; } internal static bool UnregisterHotKey(IntPtr hwnd, short atom) { bool result = UnsafeNativeMethods.UnregisterHotKey(hwnd, atom); int lastWin32Error = Marshal.GetLastWin32Error(); if (!result) { ThrowWin32ExceptionsIfError(lastWin32Error); } return result; } internal static IntPtr VirtualAlloc(IntPtr address, UIntPtr size, int allocationType, int protect) { IntPtr result = UnsafeNativeMethods.VirtualAlloc(address, size, allocationType, protect); int lastWin32Error = Marshal.GetLastWin32Error(); if (result == IntPtr.Zero) { ThrowWin32ExceptionsIfError(lastWin32Error); } return result; } internal static IntPtr VirtualAllocEx(MS.Internal.AutomationProxies.SafeProcessHandle hProcess, IntPtr address, UIntPtr size, int allocationType, int protect) { IntPtr result = UnsafeNativeMethods.VirtualAllocEx(hProcess, address, size, allocationType, protect); int lastWin32Error = Marshal.GetLastWin32Error(); if (result == IntPtr.Zero) { ThrowWin32ExceptionsIfError(lastWin32Error); } return result; } internal static bool VirtualFree(IntPtr address, UIntPtr size, int freeType) { bool result = UnsafeNativeMethods.VirtualFree(address, size, freeType); int lastWin32Error = Marshal.GetLastWin32Error(); if (!result) { ThrowWin32ExceptionsIfError(lastWin32Error); } return result; } internal static bool VirtualFreeEx(MS.Internal.AutomationProxies.SafeProcessHandle hProcess, IntPtr address, UIntPtr size, int freeType) { bool result = UnsafeNativeMethods.VirtualFreeEx(hProcess, address, size, freeType); int lastWin32Error = Marshal.GetLastWin32Error(); if (!result) { ThrowWin32ExceptionsIfError(lastWin32Error); } return result; } internal static bool WriteProcessMemory(MS.Internal.AutomationProxies.SafeProcessHandle hProcess, IntPtr dest, IntPtr sourceAddress, IntPtr size, out int bytesWritten) { bool result = UnsafeNativeMethods.WriteProcessMemory(hProcess, dest, sourceAddress, size, out bytesWritten); int lastWin32Error = Marshal.GetLastWin32Error(); if (!result) { ThrowWin32ExceptionsIfError(lastWin32Error); } return result; } internal static bool IsWindowInGivenProcess(IntPtr hwnd, string targetprocess) { uint processId; //GetWindowThreadProcessId throws ElementNotAvailableException if the hwnd is no longer valid. //But, this exception should be handled by the client accessing this proxy. uint threadId = GetWindowThreadProcessId(hwnd, out processId); try { string processName = System.Diagnostics.Process.GetProcessById((int)processId).ProcessName; if (processName == targetprocess) { return true; } } catch (Exception ex) { if (IsCriticalException(ex)) throw; if (ex is ArgumentException || ex is SystemException) { //The process is no longer running which implies AutomationElement is no longer available. //Let the client handle it. throw new ElementNotAvailableException(); } //All other exceptions are ignored as the purpose of this method is to find whether the hwnd belongs to //a particular process or not. } return false; } internal static bool InTheShellProcess(IntPtr hwnd) { IntPtr hwndShell = SafeNativeMethods.GetShellWindow(); if (hwndShell == IntPtr.Zero) return false; uint idProcessUs; GetWindowThreadProcessId(hwnd, out idProcessUs); uint idProcessShell; GetWindowThreadProcessId(hwndShell, out idProcessShell); return idProcessUs == idProcessShell; } // the windows listview has feature (like group by) in v6 that only exist on // vista and beyond. This lets us test for that. internal static bool IsComctrlV6OnOsVerV6orHigher(IntPtr hwnd) { int commonControlVersion = Misc.ProxySendMessageInt(hwnd, NativeMethods.CCM_GETVERSION, IntPtr.Zero, IntPtr.Zero); if (Environment.OSVersion.Version.Major >= 6 && commonControlVersion >= 6) { return true; } return false; } #endregion // ------------------------------------------------------ // // Internal Fields // // ------------------------------------------------------ #region Internal Fields // Max length for the name internal const int MaxLengthNameProperty = 2000; // Timeout for clearing menus internal const long MenuTimeOut = 100; #endregion // ----------------------------------------------------- // // Private Methods // // ------------------------------------------------------ #region Private Methods private static bool EnumToolTipWindows(IntPtr hwnd, ref UnsafeNativeMethods.ENUMTOOLTIPWINDOWINFO lParam) { // Use ProxyGetClassName here instead of GetClassName(), // since for a winforms tooltip the latter will return // "WindowsForms10.tooltips_class32.app.0.b7ab7b". // Instead, ProxyGetClassName uses WM_GETOBJECT with // OBJID_QUERYCLASSNAMEIDX, which will return the correct answer. if (!ProxyGetClassName(hwnd).Equals("tooltips_class32")) { return true; } NativeMethods.TOOLINFO tool = new NativeMethods.TOOLINFO(); tool.Init(Marshal.SizeOf(typeof(NativeMethods.TOOLINFO))); // For tooltips with ids of 0, MFC will create the tooltip with the flag of TTF_IDISHWND. // TTF_IDISHWND indicates that the uId member is the window handle to the tool. if (lParam.id == 0) { tool.hwnd = Misc.GetParent(lParam.hwnd); tool.uId = unchecked((int)lParam.hwnd); tool.uFlags = NativeMethods.TTF_IDISHWND; } else { tool.hwnd = lParam.hwnd; tool.uId = lParam.id; } string name = XSendMessage.GetItemText(hwnd, tool); // Didn't get anything - continue looking... if (string.IsNullOrEmpty(name)) { return true; } lParam.name = name; // Got it - can stop iterating now. return false; } // Get the size of a page in memory for VirtualAlloc private static uint GetPageSize() { NativeMethods.SYSTEM_INFO sysInfo; UnsafeNativeMethods.GetSystemInfo(out sysInfo); return sysInfo.dwPageSize; } //This function throws corresponding exception depending on the last error. private static void EvaluateSendMessageTimeoutError(int error) { EvaluateSendMessageTimeoutError(error, false); } private static void EvaluateSendMessageTimeoutError(int error, bool ignoreTimeout) { // SendMessageTimeout Function // If the function fails or times out, the return value is zero. To get extended error information, // call GetLastError. If GetLastError returns zero, then the function timed out. // NOTE: The GetLastError after a SendMessageTimeout my also be an ERROR_TIMEOUT depending on the // message. // 1460 This operation returned because the timeout period expired. ERROR_TIMEOUT if (error == 0 || error == 1460) { if (!ignoreTimeout) { throw new TimeoutException(); } } else { ThrowWin32ExceptionsIfError(error); } } private static Rect[] GetTitlebarRectsXP(IntPtr hwnd) { Debug.Assert(System.Environment.OSVersion.Version.Major < 6); UnsafeNativeMethods.TITLEBARINFO tiDL; if (!Misc.ProxyGetTitleBarInfo(hwnd, out tiDL)) { return null; } // Titlebars that are invisible or may not exist should not have a rect if ((tiDL.rgstate[NativeMethods.INDEX_TITLEBAR_SELF] & (NativeMethods.STATE_SYSTEM_INVISIBLE | NativeMethods.STATE_SYSTEM_OFFSCREEN)) != 0) { return null; } // We really should be using the the theme APIs but they give incorrect results with the titlebar buttons so we are reverting back to system metrics // This is not perfect, its a looks like it may be a few pixels of here or there but clicking on the center of the button will be sucessfull. The only place this // does not work is on console windows when the theme is Windows Clasic Style. // The system metric seems to be just bit off, subtracting 1 seems to get a better result on all themes int buttonWidth = UnsafeNativeMethods.GetSystemMetrics(NativeMethods.SM_CXSIZE) - 1; int buttonHeight = UnsafeNativeMethods.GetSystemMetrics(NativeMethods.SM_CYSIZE) - 1; Rect[] rects = new Rect[NativeMethods.CCHILDREN_TITLEBAR + 1]; // Start at the end and work backwards to the system menu. Subtract buttonSize when a child is present. int leftEdge; if (Misc.IsLayoutRTL(hwnd)) { // Right to left mirroring style // This is to take in count for a bug in GetTitleBarInfo(). It does not calculate the // rcTitleBar correctly when the WS_EX_LAYOUTRTL extended style is set. It assumes // SYSMENU is always on the left and removes its space from the wrong side of rcTitleBar. // Use the bounding rectangle of the whole title bar to get the true left boundary. leftEdge = (int)(Misc.GetTitleBarRect(hwnd).Left); for (int i = NativeMethods.INDEX_TITLEBAR_MAC; i > NativeMethods.INDEX_TITLEBAR_SELF; i--) { if ((tiDL.rgstate[i] & NativeMethods.STATE_SYSTEM_INVISIBLE) == 0) { rects[i] = new Rect(leftEdge, tiDL.rcTitleBar.top, buttonWidth, buttonHeight); leftEdge += buttonWidth; } else { rects[i] = Rect.Empty; } } } else { leftEdge = tiDL.rcTitleBar.right - buttonWidth; for (int i = NativeMethods.INDEX_TITLEBAR_MAC; i > NativeMethods.INDEX_TITLEBAR_SELF; i--) { if ((tiDL.rgstate[i] & NativeMethods.STATE_SYSTEM_INVISIBLE) == 0) { rects[i] = new Rect(leftEdge, tiDL.rcTitleBar.top, buttonWidth, buttonHeight); leftEdge -= buttonWidth; } else { rects[i] = Rect.Empty; } } } return rects; } private static Rect[] GetTitlebarRectsEx(IntPtr hwnd) { Debug.Assert(System.Environment.OSVersion.Version.Major >= 6); UnsafeNativeMethods.TITLEBARINFOEX ti; if (!Misc.ProxyGetTitleBarInfoEx(hwnd, out ti)) { return null; } // Titlebars that are invisible or may not exist should not have a rect if ((ti.rgstate[NativeMethods.INDEX_TITLEBAR_SELF] & (NativeMethods.STATE_SYSTEM_INVISIBLE | NativeMethods.STATE_SYSTEM_OFFSCREEN)) != 0) { return null; } Rect[] rects = new Rect[NativeMethods.CCHILDREN_TITLEBAR + 1]; for (int i = 0; i <= NativeMethods.CCHILDREN_TITLEBAR; i++) { // Buttons that are invisible or may not exist should not have a rect if ((ti.rgstate[i] & NativeMethods.STATE_SYSTEM_INVISIBLE) != 0) { rects[i] = Rect.Empty; } else { rects[i] = new Rect(ti.rgrect[i].left, ti.rgrect[i].top, ti.rgrect[i].right - ti.rgrect[i].left, ti.rgrect[i].bottom - ti.rgrect[i].top); } } return rects; } #endregion // ----------------------------------------------------- // // Private Fields // // ----------------------------------------------------- #region Private Fields // Generic flags for SendMessages private const int _sendMessageFlags = NativeMethods.SMTO_BLOCK; // Generic time out for SendMessages // Most messages won't need anything near this - but there are a few - eg. WM_COMMAND/CBN_DROPDOWN // when sent to IE's address combo for the first time causes it to populate iself, and that can // take a couple of seconds on a slow machine. private const int _sendMessageTimeoutValue = 10000; // Array of known class names private static string[] _asClassNames = { "ListBox", "#32768", "Button", "Static", "Edit", "ComboBox", "#32770", "#32771", "MDIClient", "#32769", "ScrollBar", "msctls_statusbar32", "ToolbarWindow32", "msctls_progress32", "SysAnimate32", "SysTabControl32", "msctls_hotkey32", "SysHeader32", "msctls_trackbar32", "SysListView32", "OpenListView", "msctls_updown", "msctls_updown32", "tooltips_class", "tooltips_class32", "SysTreeView32", "SysMonthCal32", "SysDateTimePick32", "RICHEDIT", "RichEdit20A", "RichEdit20W", "SysIPAddress32" }; #endregion } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- UnsafeMethods.cs
- ListViewUpdateEventArgs.cs
- BrowserDefinitionCollection.cs
- TypeExtensionSerializer.cs
- OleServicesContext.cs
- Filter.cs
- ServicePointManager.cs
- StrongTypingException.cs
- XamlPointCollectionSerializer.cs
- PeerContact.cs
- ConnectionStringSettingsCollection.cs
- PathGeometry.cs
- MetadataArtifactLoaderCompositeFile.cs
- CodeSubDirectoriesCollection.cs
- Compensate.cs
- _OSSOCK.cs
- DataServiceEntityAttribute.cs
- FrameworkElementFactoryMarkupObject.cs
- Currency.cs
- HtmlGenericControl.cs
- EntityDataSourceContainerNameConverter.cs
- ComponentSerializationService.cs
- ComMethodElement.cs
- AttachedAnnotation.cs
- WebZone.cs
- RegexWriter.cs
- TextTreeRootNode.cs
- AutomationElementIdentifiers.cs
- TypeConverterAttribute.cs
- DataDocumentXPathNavigator.cs
- PeerNode.cs
- WebPartMovingEventArgs.cs
- DesignerTextBoxAdapter.cs
- RadioButtonBaseAdapter.cs
- ReadWriteSpinLock.cs
- TemplateColumn.cs
- FormViewDesigner.cs
- Screen.cs
- ClientConvert.cs
- ImageIndexConverter.cs
- WebControlAdapter.cs
- Separator.cs
- CompilerCollection.cs
- PropertySourceInfo.cs
- FileUtil.cs
- Ports.cs
- EventDescriptorCollection.cs
- XmlSchemaAnyAttribute.cs
- mactripleDES.cs
- PropertyDescriptorCollection.cs
- FeedUtils.cs
- DropShadowBitmapEffect.cs
- WebServiceParameterData.cs
- MonthCalendar.cs
- DataSourceControl.cs
- EventLogTraceListener.cs
- ImageList.cs
- FolderLevelBuildProviderCollection.cs
- UnaryNode.cs
- WebRequest.cs
- Directory.cs
- TreeBuilderBamlTranslator.cs
- TextServicesProperty.cs
- CharAnimationBase.cs
- EdmProperty.cs
- MetadataProperty.cs
- ApplicationServicesHostFactory.cs
- CookieProtection.cs
- GeneralTransform3DTo2D.cs
- DataTable.cs
- BridgeDataRecord.cs
- OpacityConverter.cs
- SerializationInfoEnumerator.cs
- GetParentChain.cs
- XsltConvert.cs
- HttpResponseHeader.cs
- DataGridViewImageCell.cs
- HostSecurityManager.cs
- FlowDecision.cs
- NetworkAddressChange.cs
- DirectionalLight.cs
- SolidBrush.cs
- FreezableCollection.cs
- ToolboxComponentsCreatingEventArgs.cs
- SqlClientFactory.cs
- Match.cs
- XmlChoiceIdentifierAttribute.cs
- SafeRightsManagementEnvironmentHandle.cs
- GridViewCellAutomationPeer.cs
- ConfigurationStrings.cs
- Cloud.cs
- Descriptor.cs
- TriggerActionCollection.cs
- FixedNode.cs
- ParentUndoUnit.cs
- DoubleLinkList.cs
- SqlDataSourceCommandEventArgs.cs
- FrameworkContentElementAutomationPeer.cs
- ItemDragEvent.cs
- LicenseManager.cs