C# 在IE进程中查找javascript警报窗口

C# 在IE进程中查找javascript警报窗口,c#,winforms,pinvoke,C#,Winforms,Pinvoke,我有一个多线程UI测试工具,可以启动Internet Explorer的实例。我想找到一个使用PInvoke API的javascript警报框 在全球范围内找到它很好: IntPtr globalAlertHwnd = Pinvoke.FindWindow("#32770", "Message from webpage"); 但是,由于我并行运行多个IE实例,因此我希望基于其IE父对象来定位特定的警报框 我也可以在全局指针堆中找到它: IntPtr desktopHwnd = Pinvoke

我有一个多线程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
以下是
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;
}
公共静态IEnumerable EnumerateProcessWindowHandles(IntPtr hwnd)
{
列表句柄=新列表();
uint进程id;
GetWindowThreadProcessId(hwnd,OutProcessId);
foreach(Process.GetProcessById((int)processId.Threads中的ProcessThread线程)
{
EnumThreadWindows(thread.Id,(parentHwnd,lParam)=>
{
句柄。添加(parentHwnd);
List childhwnd=GetChildWindows(parentHwnd);
handles.AddRange(childhwns);
返回true;
},IntPtr.Zero);
}
返回手柄;
}
公共静态列表GetChildWindows(IntPtr父级)
{
列表结果=新列表();
GCHandle listHandle=GCHandle.Alloc(结果);
尝试
{
Win32Callback childProc=新的Win32Callback(枚举窗口);
EnumChildWindows(父、childProc、GCHandle.ToIntPtr(listHandle));
}
最后
{
if(listHandle.IsAllocated)
Free();
}
返回结果;
}
我知道
EnumChildWindows()
获取所有子级,而不仅仅是顶层(通过我的第二个示例验证)

我验证了一个IE线程中存在警报框及其OK按钮。Spy++屏幕截图:

我错过了什么?这种方法在Firefox和Chrome中都能很好地工作

更新:


似乎出现这个问题是因为IE为主窗口创建了一个进程,为每个选项卡创建了另一个进程。我必须考虑如何在此基础上获取其他进程。

通过强制IE为每个实例创建单个进程来解决:

HKEY\u CURRENT\u USER\Software\MicrosoftInternet Explorer\Main
中创建或更新注册表项
TabProcGrowth
。它应该是一个REG_DWORD 32位,值为0

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;
}