我正在开发一个最终将成为驱动WPF应用程序的UI测试的api的应用程序。
在我们正在进行的初始测试的某一时刻,我们得到2个Windows安全性弹出窗口。我们有一些循环执行10次的代码,它使用FindWindowByCaption方法获取其中一个弹出窗口的句柄,然后输入信息并单击“确定”。
10的9倍可以正常工作,但是我们偶尔会看到看起来像是种族的情况。我的怀疑是,仅当其中一个窗口打开时,循环才开始,而在输入信息时,第二个窗口打开并窃取焦点。之后,它会无限期地挂起。
我想知道的是,是否有任何方法可以获取给定标题的所有窗口句柄,以便我们可以等到2个之后才能开始循环。
使用EnumWindows并枚举所有窗口,使用GetWindowText来获取每个窗口的文本,然后根据需要对其进行过滤。
EnumWindows
GetWindowText
[DllImport("user32.dll", CharSet = CharSet.Unicode)] private static extern int GetWindowText(IntPtr hWnd, StringBuilder strText, int maxCount); [DllImport("user32.dll", CharSet = CharSet.Unicode)] private static extern int GetWindowTextLength(IntPtr hWnd); [DllImport("user32.dll")] private static extern bool EnumWindows(EnumWindowsProc enumProc, IntPtr lParam); // Delegate to filter which windows to include public delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam); /// <summary> Get the text for the window pointed to by hWnd </summary> public static string GetWindowText(IntPtr hWnd) { int size = GetWindowTextLength(hWnd); if (size > 0) { var builder = new StringBuilder(size + 1); GetWindowText(hWnd, builder, builder.Capacity); return builder.ToString(); } return String.Empty; } /// <summary> Find all windows that match the given filter </summary> /// <param name="filter"> A delegate that returns true for windows /// that should be returned and false for windows that should /// not be returned </param> public static IEnumerable<IntPtr> FindWindows(EnumWindowsProc filter) { IntPtr found = IntPtr.Zero; List<IntPtr> windows = new List<IntPtr>(); EnumWindows(delegate(IntPtr wnd, IntPtr param) { if (filter(wnd, param)) { // only add the windows that pass the filter windows.Add(wnd); } // but return true here so that we iterate all windows return true; }, IntPtr.Zero); return windows; } /// <summary> Find all windows that contain the given title text </summary> /// <param name="titleText"> The text that the window title must contain. </param> public static IEnumerable<IntPtr> FindWindowsWithText(string titleText) { return FindWindows(delegate(IntPtr wnd, IntPtr param) { return GetWindowText(wnd).Contains(titleText); }); }
例如,要获得所有标题中带有“记事本”的窗口:
var windows = FindWindowsWithText("Notepad");
这个答案非常受欢迎,以至于我创建了一个OSS项目Win32Interop.WinHandles,以为Win32 Windows提供基于IntPtrs的抽象。使用该库,获取标题中包含“记事本”的所有窗口:
var allNotepadWindows = TopLevelWindowUtils.FindWindows(wh => wh.GetWindowText().Contains("Notepad"));