get_accChildCount不应该返回0 [英] get_accChildCount returns 0 when it shouldn't

查看:303
本文介绍了get_accChildCount不应该返回0的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试从扩展名和独立应用程序枚举IE的标签。对于其中一个MSAA节点 get_accChildCount 从扩展名调用时返回0,而根据 inspect 返回1来自独立应用程序的呼叫。

I'm trying to enumerate tabs of IE from an extension and from a standalone application. For one of the MSAA nodes get_accChildCount returns 0 when called from extension, while it should return 1 according to inspect and a call from standalone application.

  • The problem was described previously at StackOverflow, yet it was solved via a hack that doesn't work for me. /clr and /MT are incompatible.
  • Also there was a topic on MSDN with the same issue. There's no single answer there.
  • If you run IE with administrator privileges, it works properly.
  • API Monitor shows several thousand calls in a minimal example, and it's unclear which of these are related. The minimal example is attached below.

get_accChildCount 返回错误的孩子计数?

What are the undocumented cases when get_accChildCount returns wrong child count?

我们可以使用哪些其他方法在大多数版本的IE中通过URL激活标签页? em>

What other method could I use to activate the tab by URL in most versions of IE?

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


推荐答案

我戳了你的程序一段时间没有多少展现。也许我意识到太晚了,不应该重现这个问题:(我只能提供一些可能有帮助的提示,让你看看正确的摇滚。

I poked at your program for a while without having much to show for it. Perhaps I realized too late that it was not supposed to reproduce the problem :( I can only provide some possibly helpful hints to get you to look under the right kind of rock.


但是它是通过一个不能为我工作的黑客解决

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

这些程序员做了一个简单的错误,他们忘了调用 CoInitialize / Ex()。一个非常常见的监督。使用/ clr build选项可以解决这个错误,因为它现在是调用它的CLR。您可以轻松地重新设置这个事故,只需注释掉CoInitialize()调用,不幸的是它工作了一段时间,没有任何大的错误被产生,但是你确定为某些 accobjects为0,你会注意到程序不再找到选项卡。

These programmers made a simple mistake, they forgot to call CoInitialize/Ex(). A very common oversight. Using the /clr build option works around that mistake because it is now the CLR that calls it. You can easily repro this mishap, just comment out the CoInitialize() call. Unfortunately it works for a while without any loud errors being produced, but you do get 0 for certain accobjects. You'll notice your program no longer finds the tabs.

不太确定我可以清楚地解释这一点,某些COM风格的对象模型实际上并不使用COM基础架构DirectX是最好的例如,我们可以将UIAutomation添加到该列表中当客户端应用程序的组件是基于COM的时候,病人会静静地失败。不明白,DirectUIHWnd是相当无证的。

Not so sure I can cleanly explain this, certain COM-style object models don't actually use the COM infrastructure. DirectX is the best example, we can add UIAutomation to that list. I assume it will silently fail like this when the client app's component is COM-based. Unclear if it is, DirectUIHWnd is quite undocumented.

所以停止寻找这个解决方法,你没有忘记调用CoInitialize(),它将被照顾通过IE激活您的扩展名。

So stop looking for that as a workaround, you did not forget to call CoInitialize() and it will be taken care of by IE before it activates your extension.


如果您以管理员权限运行IE,它可以正常工作。

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

这是一个更好的摇滚。许多程序员一直运行VS升级,在UIA的情况下,角色可能会颠倒。请记住,您的扩展程序在IE内的沙箱中运行。没有真正的想法如何升高IE影响这一点。在低完整性沙箱中运行的代码不能做的一件事就是在一个运行在较高完整性模式下的代码所拥有的UI组件上。 Google禁用IE增强保护模式,并遵循指南,看看您的插件有什么影响。

That's a better rock. Many programmers run VS elevated all the time, the roles might be reversed in the case of UIA. Do keep in mind that your extension runs in a sandbox inside IE. No real idea how elevating IE affects this. One thing you cannot do from code running in the low-integrity sandbox is poke at UI components owned by a code that runs in a higher integrity mode. Google "disable IE enhanced protected mode" and follow the guideline to see what effect that has on your addin.

这篇关于get_accChildCount不应该返回0的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆