我有一个多线程UI测试工具,可以启动Internet Explorer实例。我想找到一个使用PInvoke API的javascript警告框。
在全球范围内找到它可以正常工作:
IntPtr globalAlertHwnd = Pinvoke.FindWindow("#32770", "Message from webpage");
但是,由于我并行运行多个IE实例,因此我希望根据其IE父目标来定位特定的警告框。
我也可以在全球指针中找到它:
IntPtr desktopHwnd = Pinvoke.GetDesktopWindow();
List<IntPtr> allDesktopChilds = Pinvoke.GetChildWindows(desktopHwnd).ToList();
bool match1 = allDesktopChilds.Any(hwnd => hwnd == globalAlertHwnd); // true
但是一旦我使用IE进程,我找不到它。 mainWindowHnadle
是IE的窗口句柄。
List<IntPtr> ieChildren = Pinvoke.EnumerateProcessWindowHandles(mainWindowHnadle).ToList();
bool match2 = ieChildren.Any(hwnd => hwnd == globalAlertHwnd); // false
这就是EnumerateProcessWindowHandles
的样子:
public static IEnumerable<IntPtr> EnumerateProcessWindowHandles(IntPtr hwnd)
{
List<IntPtr> handles = new List<IntPtr>();
uint processId;
GetWindowThreadProcessId(hwnd, out processId);
foreach (ProcessThread thread in Process.GetProcessById((int)processId).Threads)
{
EnumThreadWindows(thread.Id, (parentHwnd, lParam) =>
{
handles.Add(parentHwnd);
List<IntPtr> childHwnds = GetChildWindows(parentHwnd);
handles.AddRange(childHwnds);
return true;
}, IntPtr.Zero);
}
return handles;
}
public static List<IntPtr> GetChildWindows(IntPtr parent)
{
List<IntPtr> result = new List<IntPtr>();
GCHandle listHandle = GCHandle.Alloc(result);
try
{
Win32Callback childProc = new Win32Callback(EnumWindow);
EnumChildWindows(parent, childProc, GCHandle.ToIntPtr(listHandle));
}
finally
{
if (listHandle.IsAllocated)
listHandle.Free();
}
return result;
}
我知道EnumChildWindows()
得到所有孩子,而不仅仅是顶层(由我的第二个例子验证)。
我验证了一个IE线程中存在警报框及其OK按钮。 Spy ++截图:
我错过了什么?此方法适用于Firefox和Chrome。
更新
似乎出现此问题是因为IE为主窗口创建了一个进程,并为每个选项卡创建了另一个进程。我必须考虑如何基于此获取其他进程。
答案 0 :(得分:0)
通过强制IE为每个实例创建单个进程来解决:
在TabProcGrowth
中创建或更新注册表项HKEY_CURRENT_USER\Software\MicrosoftInternet Explorer\Main
。它应该是REG_DWORD 32位,值为0.