/Visual Studio 2013/Source/wpf/src/UIAutomation/Win32Providers/MS/Internal/AutomationProxies/Misc.cs
C# | 1298 lines | 888 code | 219 blank | 191 comment | 167 complexity | 069eff079837835ae7ff313a55fee2c4 MD5 | raw file
- //---------------------------------------------------------------------------
- //
- // <copyright file="Misc.cs" company="Microsoft">
- // Copyright (C) Microsoft Corporation. All rights reserved.
- // </copyright>
- //
- //
- // 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;
- using NativeMethodsSetLastError = MS.Internal.UIAutomationClientSideProviders.NativeMethodsSetLastError;
- 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)
- {
- IntPtr result = NativeMethodsSetLastError.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 = NativeMethodsSetLastError.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 = NativeMethodsSetLastError.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 error = 0;
- int style = UnsafeNativeMethods.GetWindowLong(peer, NativeMethods.GWL_STYLE, out error);
- 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)
- {
- bool result = NativeMethodsSetLastError.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)
- {
- IntPtr hwndParent = NativeMethodsSetLastError.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)
- {
- int result = NativeMethodsSetLastError.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)
- {
- IntPtr resultHwnd = NativeMethodsSetLastError.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)
- {
- int lastWin32Error = 0;
- int exstyle = UnsafeNativeMethods.GetWindowLong(hwnd, NativeMethods.GWL_EXSTYLE, out lastWin32Error);
- if (exstyle == 0)
- {
- ThrowWin32ExceptionsIfError(lastWin32Error);
- }
- return exstyle;
- }
- // Gets the id of the window
- internal static int GetWindowId(IntPtr hwnd)
- {
- int lastWin32Error = 0;
- int id = UnsafeNativeMethods.GetWindowLong(hwnd, NativeMethods.GWL_ID, out lastWin32Error);
- 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.
- int lastWin32Error = 0;
- int result = UnsafeNativeMethods.GetWindowLong(hwnd, NativeMethods.GWL_HWNDPARENT, out lastWin32Error);
- 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)
- {
- int lastWin32Error = 0;
- int style = UnsafeNativeMethods.GetWindowLong(hwnd, NativeMethods.GWL_STYLE, out lastWin32Error);
- 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)
- {
- short result = NativeMethodsSetLastError.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 = NativeMethodsSetLastError.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 [....] 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 = NativeMethodsSetLastError.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)
- {
- int mappingOffset = NativeMethodsSetLastError.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)
- {
- int mappingOffset = NativeMethodsSetLastError.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);
- int left = 0;
- int right = 0;
- if(Misc.IsControlRTL(hwnd))
- {
- // Possible that there is no menu
- left = ti.rcTitleBar.left;
- right = (!retValue || mbi.rcBar.IsEmpty) ? ti.rcTitleBar.right : mbi.rcBar.right;
- }
- else
- {
- // Possible that there is no menu
- left = (!retValue || mbi.rcBar.IsEmpty) ? ti.rcTitleBar.left : mbi.rcBar.left;
- right = ti.rcTitleBar.right;
- }
- return new Rect(left, ti.rcTitleBar.top, 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)
- {
- In