get_accChildCount在不应该返回 0 时返回 0
get_accChildCount returns 0 when it shouldn't
我正试图从扩展和独立应用程序中枚举IE的选项卡。对于其中一个MSAA节点,从扩展调用get_accChildCount
时返回0,而根据inspect
和独立应用程序的调用,它应该返回1。
- 这个问题之前在StackOverflow中描述过,但通过一个对我不起作用的破解解决了。
/clr
和/MT
不兼容 - 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"rn";
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;
}
}
}
}
我对你的程序进行了一段时间的研究,但没有太多内容。也许我意识到它不应该重现这个问题太晚了:(我只能提供一些可能有用的提示,让你找到合适的岩石。
但它是通过一个不适用于我的黑客解决的
这些程序员犯了一个简单的错误,他们忘记调用CoInitialize/Ex()
。一个非常常见的疏忽。使用/clr build选项可以解决这个错误,因为现在是clr调用它。您可以很容易地重新处理这个错误,只需注释掉CoInitialize()调用即可。不幸的是,它可以工作一段时间,不会产生任何大的错误,但对于某些对象,您确实会得到0。您会注意到您的程序已找不到选项卡。
我不太确定我是否能清楚地解释这一点,某些COM风格的对象模型实际上并没有使用COM基础设施。DirectX就是最好的例子,我们可以将UIAutomation添加到该列表中。我认为当客户端应用程序的组件是基于COM的时,它会像这样默默地失败。如果是不清楚的话,DirectUIHWnd是完全没有记录的。
因此,不要再把它当作一种变通方法了,你没有忘记调用CoInitialize(),它将在IE激活你的扩展之前得到处理。
如果您以管理员权限运行IE,它将正常工作。
那是块更好的石头。许多程序员一直运行VS提升,在UIA的情况下,角色可能会颠倒。请记住,您的扩展是在IE内部的沙盒中运行的。不知道提升IE会如何影响这一点。在低完整性沙箱中运行的代码不能做的一件事是,戳一下在高完整性模式中运行的程序所拥有的UI组件。谷歌"禁用IE增强的保护模式",并遵循指南,看看这对你的插件有什么影响。
- 条件断点在不应该触发时触发
- 你好。。。id_public变量不应该给出结果为 81 和 86 吗?为什么它为两个派生类占用不同的内存位置?
- 在C++中返回不正确的楼层函数值
- 为什么我不应该把所有东西都放在标题中?
- CreateDIBSection为同一图像返回不一致的位图位值
- 找不到 QRegularExpression 行为的任何解释。它有效,但不应该
- 返回不需要的值的二叉搜索程序
- 在清除 istream 之前,我不应该需要取消获取它吗?
- inet_ntop返回不存在的地址
- c++ 为什么我不应该从不同的线程解锁互斥锁
- "typename"不应该只在模板函数或模板类中使用吗?
- 解释为什么它不返回它应该返回的内容
- get_accChildCount在不应该返回 0 时返回 0
- 返回引用 - 为什么我的代码工作正常?不应该
- 为什么我们不应该使用在类中返回数组或指针的函数呢
- 为什么C/C++编码标准说我们不应该在函数中有多个返回
- 此函数如何在不应该返回值时返回值?
- 这种递归方法不应该在返回后立即结束吗?
- 赋值运算符在不应该返回"empty"实例时返回?
- C++:函数返回指针不应该是常量的任何原因?