c++ - get_accChildCount 在不应该返回 0 的情况下返回 0

标签 c++ internet-explorer debugging com ui-automation

我正在尝试从扩展程序和独立应用程序枚举 IE 选项卡。对于 MSAA 节点之一,从扩展调用时,get_accChildCount 返回 0,而根据 inspect 和来自独立应用程序的调用,它应返回 1。

  • 已描述问题 previously在 StackOverflow 上,但它是通过对我不起作用的 hack 解决的。 /clr/MT 不兼容。
  • 还有a topic on MSDN有同样的问题。那里没有单一的答案。
  • 如果您以管理员权限运行 IE,则它可以正常工作。
  • API Monitor在一个最小的示例中显示了数千个调用,并且不清楚其中哪些是相关的。下面附有最小的示例。

get_accChildCount返回错误的子计数时,有哪些未记录的情况?

在大多数版本的 IE 中,我还可以使用什么其他方法通过 URL 激活选项卡?

#include <atlbase.h>
#include <atlcom.h>
#include <atlctl.h>
#include <atltypes.h>
#include <atlsafe.h>
#include <io.h>
#include <fcntl.h>
#include <windows.h>

#include <iostream>
#include <string>
#include <vector>
#include <boost/format.hpp>
#include <fstream>
using namespace std;

CComPtr<IAccessible> get_acc_by_hwnd(HWND hwnd) {
    CComPtr<IAccessible> ret;
    HRESULT hr = ::AccessibleObjectFromWindow(hwnd, OBJID_WINDOW, IID_IAccessible, (void**) &ret);
    if (FAILED(hr) || !ret) {
        wcout << L"Accessible::Accessible invalid hwnd" << endl;
    }
    return ret;
}

std::vector<CComPtr<IAccessible>> get_acc_children(CComPtr<IAccessible> acc) {
    std::vector<CComPtr<IAccessible>> ret;
    long count;
    if (FAILED(acc->get_accChildCount(&count))) return ret;
    long count_obtained = 0;
    if (!count) return ret;
    std::vector<CComVariant> accessors(count);
    if (FAILED(::AccessibleChildren(acc, 0, count, &*accessors.begin(), &count_obtained))) return ret;
    accessors.resize(count_obtained);
    for (auto vtChild : accessors) {
        if (vtChild.vt != VT_DISPATCH) continue;
        CComQIPtr<IAccessible> pChild = vtChild.pdispVal;
        if (pChild) ret.push_back(pChild);
    }
    return ret;
}

bool is_client(CComPtr<IAccessible> acc) {
    CComVariant var;
    HRESULT hr = acc->get_accRole(CComVariant(CHILDID_SELF), &var);
    return SUCCEEDED(hr) && var.vt == VT_I4 && var.lVal == 0xA;
}

std::wstring get_descr(CComPtr<IAccessible> acc) {
    CComBSTR str;
    HRESULT hr = acc->get_accDescription(CComVariant(CHILDID_SELF), &str);
    return SUCCEEDED(hr) && str ? std::wstring(str) : L"";
}

int main() {
    ::CoInitialize(nullptr);
    _setmode(_fileno(stdout), _O_U16TEXT);

    // put HWND of the window that contains tab labels
    // it's hardcoded to minimize quantity of API calls
    HWND hwnd = reinterpret_cast<HWND>(0x002D0696);
    CComPtr<IAccessible> iaccessible;
    HRESULT hr = ::AccessibleObjectFromWindow(hwnd, OBJID_WINDOW, IID_IAccessible, (void**) &iaccessible);
    if (FAILED(hr) || !iaccessible) {
        wcout << L"AccessibleBrowser::activate_tab " L"failed to get IAccessible for IE" << endl;
        return EXIT_FAILURE;
    }

    wstring const sentinel = L"\r\n";
    for (auto child : get_acc_children(iaccessible)) if (is_client(child)) {
        for (auto child1 : get_acc_children(child)) { // fails here in extension
            for (auto child2 : get_acc_children(child1)) {
                std::wstring descr = get_descr(child2);
                auto pos = descr.find(sentinel);
                if (pos == string::npos) continue;
                auto tab_url = descr.substr(pos + sentinel.size());
                wcout << tab_url << endl;
            }
        }
    }
}

最佳答案

我研究了你的程序一段时间,但没有什么可展示的。也许我意识到它不应该重现这个问题已经太晚了:(我只能提供一些可能有用的提示来让你看看正确的岩石类型。

yet it was solved via a hack that doesn't work for me

这些程序员犯了一个简单的错误,他们忘记调用CoInitialize/Ex()。这是一个非常常见的疏忽。使用/clr 构建选项可以解决该错误,因为现在是 CLR 调用它。您可以轻松地重现此事故,只需注释掉 CoInitialize() 调用即可。不幸的是,它工作了一段时间,没有产生任何严重的错误,但对于某些 accobjects,您确实得到了 0。您会注意到您的程序不再找到选项卡。

不太确定我能否清楚地解释这一点,某些 COM 风格的对象模型实际上并不使用 COM 基础结构。 DirectX 是最好的例子,我们可以将 UIAutomation 添加到该列表中。我认为当客户端应用程序的组件是基于 COM 的时,它会像这样默默地失败。不清楚是否如此,DirectUIHWnd 完全没有文档记录。

所以不要再寻找解决方法了,您没有忘记调用 CoInitialize(),IE 会在激活您的扩展之前处理它。

If you run IE with administrator privileges, it works properly.

那是一 block 更好的岩石。许多程序员一直在提升 VS 的运行速度,在 UIA 的情况下,角色可能会颠倒过来。请记住,您的扩展在 IE 内的沙箱中运行。不知道提升 IE 会如何影响这一点。在低完整性沙箱中运行的代码无法执行的一件事是刺探在较高完整性模式下运行的代码所拥有的 UI 组件。谷歌“禁用 IE 增强保护模式”并按照指南查看这对您的插件有何影响。

关于c++ - get_accChildCount 在不应该返回 0 的情况下返回 0,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37458778/

相关文章:

javascript - 使用元标记 "X-UA-Compatible"

internet-explorer - IE 11 在 Google Analytics 中作为 Mozilla 出现

php - IE : Sidebar Won't Appear 中的 CSS 问题

debugging - 如何检查 rable View 文件中的错误

java - 如何在windows上远程调试tomcat 7.0?

c++ - 将 Qt Creator 设置为在 Windows 上使用最新版本的 g++ 和 gdb

c++ - 需要一种方法让这段代码运行得更快

c++ - linux下如何运行ps调试多线程程序?

c++ - 使用 void* 位作为存储的新布局

sql-server - 查找 3930 SQL Server 错误的原因