我试图从一个扩展和一个独立的应用程序中枚举IE的选项卡。对于其中一个MSAA节点,当从扩展调用时,get_accChildCount返回0,而它应该根据inspect返回1和从独立应用程序返回调用。
/clr和/MT是不兼容的。当get_accChildCount返回错误的子计数时,有哪些无文档的情况?
在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;
}
}
}
}发布于 2016-05-29 02:33:02
我戳了你的节目一段时间,没有什么可展示的。也许我意识到太晚了,它不应该重现这个问题:(我只能提供一些可能有用的提示,让你在正确的岩石下面寻找。)
但它是通过一次对我不起作用的黑客来解决的
这些程序员犯了一个简单的错误,他们忘了打电话给CoInitialize/Ex()。很常见的疏忽。使用/clr构建选项可以避免这个错误,因为现在调用它的是CLR。您可以轻松地复制这一不幸,只需注释掉CoInitialize()调用即可。不幸的是,它工作了一段时间,没有产生任何响亮的错误,但是对于某些accobjects,您确实得到了0。您会注意到您的程序不再找到选项卡。
不太确定我是否能清楚地解释这一点,某些COM样式的对象模型实际上并不使用COM基础结构。DirectX是最好的例子,我们可以将UIAutomation添加到这个列表中。当客户端应用程序的组件是基于COM的时,我猜想它会像这样默默地失败。不清楚是否是,DirectUIHWnd是完全没有文件的。
因此,停止寻找它作为一个解决方案,您没有忘记调用CoInitialize(),它将由IE在激活您的扩展之前处理。
如果您以管理员权限运行IE,它将正常工作。
那是块更好的石头。许多程序员一直在运行VS,在UIA的情况下,角色可能会被逆转。请记住,您的扩展在IE内部的沙箱中运行。没有真正的想法,提升IE如何影响这一点。在运行在低完整性沙箱中的代码中,您不能做的一件事是戳到运行在较高完整性模式下的代码所拥有的UI组件。谷歌“禁用IE增强保护模式”,并遵循指导方针,看看这对你的加载项有什么影响。
https://stackoverflow.com/questions/37458778
复制相似问题