在 IE 进程中查找 javascript 警报 window
Find javascript alert window in IE process
我有一个多线程 UI 测试工具,可以启动 Internet Explorer 的实例。我想使用 PInvoke API.
找到一个 javascript 警告框
在全球范围内找到它工作正常:
IntPtr globalAlertHwnd = Pinvoke.FindWindow("#32770", "Message from webpage");
但是,由于我是 运行 多个并行的 IE 实例,我想根据其 IE parent.
定位特定的警告框
我在全局指针堆里也能找到:
IntPtr desktopHwnd = Pinvoke.GetDesktopWindow();
List<IntPtr> allDesktopChilds = Pinvoke.GetChildWindows(desktopHwnd).ToList();
bool match1 = allDesktopChilds.Any(hwnd => hwnd == globalAlertHwnd); // true
但是我一用IE进程就找不到了。 mainWindowHnadle
是 IE 的 window 句柄。
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()
获得 所有 children,而不仅仅是顶级(由我的第二个示例验证)。
我确认警告框存在于其中一个 IE 线程及其确定按钮中。间谍++截图:
我错过了什么?此方法在 Firefox 和 Chrome.
中均适用
更新:
出现这个问题似乎是因为 IE 为主 window 创建一个进程,为每个选项卡创建另一个进程。我得考虑怎么根据这个去fetch另一个进程了。
通过强制 IE 为每个实例创建一个进程解决:
在 HKEY_CURRENT_USER\Software\MicrosoftInternet Explorer\Main
中创建或更新注册表项 TabProcGrowth
。它应该是一个 REG_DWORD 32 位,值为 0.
我有一个多线程 UI 测试工具,可以启动 Internet Explorer 的实例。我想使用 PInvoke API.
找到一个 javascript 警告框在全球范围内找到它工作正常:
IntPtr globalAlertHwnd = Pinvoke.FindWindow("#32770", "Message from webpage");
但是,由于我是 运行 多个并行的 IE 实例,我想根据其 IE parent.
定位特定的警告框我在全局指针堆里也能找到:
IntPtr desktopHwnd = Pinvoke.GetDesktopWindow();
List<IntPtr> allDesktopChilds = Pinvoke.GetChildWindows(desktopHwnd).ToList();
bool match1 = allDesktopChilds.Any(hwnd => hwnd == globalAlertHwnd); // true
但是我一用IE进程就找不到了。 mainWindowHnadle
是 IE 的 window 句柄。
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()
获得 所有 children,而不仅仅是顶级(由我的第二个示例验证)。
我确认警告框存在于其中一个 IE 线程及其确定按钮中。间谍++截图:
我错过了什么?此方法在 Firefox 和 Chrome.
中均适用更新:
出现这个问题似乎是因为 IE 为主 window 创建一个进程,为每个选项卡创建另一个进程。我得考虑怎么根据这个去fetch另一个进程了。
通过强制 IE 为每个实例创建一个进程解决:
在 HKEY_CURRENT_USER\Software\MicrosoftInternet Explorer\Main
中创建或更新注册表项 TabProcGrowth
。它应该是一个 REG_DWORD 32 位,值为 0.