我知道这是一篇很老的帖子,但我自己偶然发现了将二进制数据从 ActiveX 传递到 Javascript 的相同问题,并决定根据出租车人的提议提出一个解决方案。
在此之前,我想指出,也可以构建二进制数据的 SAFEARRAY 并将此对象发送回 JS。唯一的问题是必须使用 VBScript 来解压这个对象,将其转换为只有 JScript(微软的 Javascript 方言)才能识别的数据类型,而不是用于构建传统的 JS 数组。
在不讨论这个解决方案背后的原因(检查出租车司机的答案)的情况下,这里有一个方法,它将在 ActiveX 控件中构建 Javascript 数组并将这个数组返回给 JS。
/** NOTE: you have to include MsHTML.h header in order to access IServiceProvider,
IHTMLWindow2 and related constants. **/
IDispatch* CActiveX_TutorialCtrl::GetJSArrayObject(void)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
LPOLECLIENTSITE site = this->GetClientSite();
IServiceProvider* serviceProvider = nullptr;
site->QueryInterface(IID_IServiceProvider, reinterpret_cast<void**>(&serviceProvider));
IHTMLWindow2* window_obj = nullptr;
serviceProvider->QueryService(SID_SHTMLWindow, IID_IHTMLWindow2, reinterpret_cast<void**>(&window_obj));
DISPPARAMS disparam = { nullptr, nullptr, 0, 0 };
VARIANT ret_val;
DISPID dispid;
LPOLESTR method_name = L"Array";
HRESULT hr = window_obj->GetIDsOfNames(IID_NULL, &method_name, 1, LOCALE_SYSTEM_DEFAULT, &dispid);
hr = window_obj->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, &disparam, &ret_val, nullptr, nullptr);
if (ret_val.vt != VT_DISPATCH)
return nullptr;
VARIANTARG push_arg;
method_name = L"push";
hr = ret_val.pdispVal->GetIDsOfNames(IID_NULL, &method_name, 1, LOCALE_SYSTEM_DEFAULT, &dispid);
if (hr != S_OK)
return nullptr;
::VariantInit(&push_arg);
::VariantChangeType(&push_arg, &push_arg, 0, VT_I4);
for (int i = -10; i <= 10; ++i)
{
push_arg.intVal = i;
disparam.rgvarg = &push_arg;
disparam.rgdispidNamedArgs = nullptr;
disparam.cArgs = 1;
disparam.cNamedArgs = 0;
hr = ret_val.pdispVal->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, &disparam, nullptr, nullptr, nullptr);
if (hr != S_OK)
return nullptr;
}
::VariantClear(&push_arg);
serviceProvider->Release();
window_obj->Release();
serviceProvider = nullptr;
window_obj = nullptr;
return ret_val.pdispVal;
}
您在此处看到的大部分代码都是典型的 COM 编程。首先,我们检索指向托管我们控件的客户端站点的指针。然后,我们对 IServiceProvider 进行 QI(查询接口),它是一个 IE 接口,实现了许多支持的服务。其中之一是 IHTMLWindow2,它是 Javascript 中 window 对象的类型。现在我们有了一个指向窗口对象的指针,我们可以创建一个 Array 对象。 Array 只是 IHTMLWindow2 对象的一个方法,为了创建一个新的数组,我们必须调用这个函数。
为了调用 COM 对象上的方法(而 IHTMLWindow2 只是某个 COM 对象实现的接口),该对象必须实现 IDispatch 接口,该接口允许用户使用 Invoke强>方法。 GetIDsOfNames 方法用于检索 Array 方法的 DISPID(dispatch id),然后我们最终通过在 window_obj 对象上调用 Array 方法来创建一个新数组。在 ret_val 参数(VARIANT 类型)中,我们将获得一个 IDispatch* 指针,表示我们的 JS 数组。
接下来要做什么很明显了:使用这个指针来获取push方法的DISPID,然后通过一遍又一遍地“调用”这个方法来填充数组。示例函数还展示了如何构建 IDispatch::Invoke 方法所需的 DISPARAMS 和 VARIANTARG 对象。
最后,我们从方法中返回 IDispatch* 指针。 JS 会将此对象识别为原生 JS 数组,因为这实际上是它的内部实现。