随着IE11的出现,IHTMLWindow2::execScript()
已被弃用。建议的方法是use eval()
instead。我通过其C ++ COM接口自动化IE,我一直无法找到如何实现这一点。有人能指出我在搜索中明显错过的例子吗?如果无法通过eval
执行代码,那么现在execScript
不再可用,将JavaScript代码注入正在运行的Internet Explorer实例的方法是什么?
编辑:任何适用于我正在进行的项目的解决方案都必须在进程外进行。我没有使用浏览器助手对象(BHO)或任何类型的IE插件。因此,任何涉及无法正确编组交叉过程的接口的解决方案都不适用于我。
答案 0 :(得分:13)
我现在已经验证eval
方法与IE9,IE10和IE11一致(错误检查跳过了错误):
CComVariant result;
CComDispatchDriver disp = m_htmlWindow; // of IHTMLWindow2
disp.Invoke1(L"eval", &CComVariant(L"confirm('See this?')"), &result);
result.ChangeType(VT_BSTR);
MessageBoxW(V_BSTR(&result));
感觉甚至比execScript
更好,因为它实际上会返回result
。
它也可以在C#中使用WinForms'WebBrowser
:
var result = webBrowser1.Document.InvokeScript("eval", new object[] { "confirm('see this?')" });
MessageBox.Show(result.ToString());
那就是说,execScript
仍适用于IE11预览:
CComVariant result;
m_htmlWindow->execScript(CComBSTR(L"confirm('See this too?')"), CComBSTR(L"JavaScript"), &result);
result.ChangeType(VT_BSTR);
MessageBoxW(V_BSTR(&result));
它仍然丢弃result
,就像它一直一样。
有点偏离主题,但你不必坚持使用eval
。此方法允许执行加载页面的JavaScript window
对象的名称空间内可用的任何命名方法(通过IDispatch接口)。您可以调用自己的函数并将实时COM对象传递给它,而不是字符串参数,例如:
// JavaScript
function AlertUser(user)
{
alert(user.name);
return user.age;
}
// C++
CComDispatchDriver disp = m_htmlWindow; // of IHTMLWindow2
disp.Invoke1(L"AlertUser", &CComVariant(userObject), &result);
我希望在可能的情况下直接调用eval
。
<强> [EDITED] 强>
需要进行一些调整才能使此方法适用于进程外调用。正如@JimEvans在评论中指出的那样,Invoke
返回错误0x80020006(“未知名称”)。但是,test HTA app工作得很好,是什么让我考虑尝试IDispatchEx::GetDispId进行名称解析。确实有效(跳过错误检查):
CComDispatchDriver dispWindow;
htmlWindow->QueryInterface(&dispWindow);
CComPtr<IDispatchEx> dispexWindow;
htmlWindow->QueryInterface(&dispexWindow);
DISPID dispidEval = -1;
dispexWindow->GetDispID(CComBSTR("eval"), fdexNameCaseSensitive, &dispidEval);
dispWindow.Invoke1(dispidEval, &CComVariant("function DoAlert(text) { alert(text); }")); // inject
DISPID dispidDoAlert = -1;
dispexWindow->GetDispID(CComBSTR("DoAlert"), fdexNameCaseSensitive, &dispidDoAlert) );
dispWindow.Invoke1(dispidDoAlert, &CComVariant("Hello, World!")); // call
完整的C ++测试应用程序位于:http://pastebin.com/ccZr0cG2
<强> [UPDATE] 强>
此更新会在子进程__execScript
的{{1}}对象上创建window
方法。要注入的代码已经过优化,可以返回目标iframe
对象供以后使用(不需要进行一系列的out-of-proc调用来获取window
对象,它是在上下文中完成的。主窗口):
iframe
下面是C ++控制台应用程序(pastebin)的代码,跳过了一些错误检查。还有一个相应的prototype in .HTA,它更具可读性。
CComBSTR __execScriptCode(L"(window.__execScript = function(exp) { return eval(exp); }, window.self)");