【问题标题】:Passing array of bytes from ActiveX to javascript and vice versa将字节数组从 ActiveX 传递到 javascript,反之亦然
【发布时间】:2010-12-27 22:58:15
【问题描述】:

我需要将数据(字节数组,即 char*)从 ActiveX 对象(使用带有 ATL 的 Visual C++)传递到我的 javascript 代码(反之亦然)。我已经在网上挖掘了这样的问题并尝试了很多解决方案,但都没有成功。我尝试了以下方法:

  • 将 char* 转换为 BSTR 并将其传递给 javascript (JS),但我在 JS 中的结果是“”,因为我的数据的性质不是字符串。
//in C++:
STDMETHODIMP CActiveXObj::f(BSTR* msg) // msg is the return value in ATL automation function
{
    char *buffer; // byte data is stored in buffer
    *msg = SysAllocStringByteLen((LPCSTR)buffer, bufferLen+1);
}
//////////////////////////////////////////////////////////////////////////
//in JavaScript:
var myobj= new ActiveXObject("IGCE.ActiveXObj");
var result = myobj.f(); // result = ""
  • 从 C++ 传递安全的字节数据数组

谁能给我最简单的工作代码?

非常感谢!

克里斯汀

【问题讨论】:

    标签: javascript c++ activex binary


    【解决方案1】:
    // In *.idl file 
    [propget, id(0)] HRESULT ArrayProperty([out, retval] SAFEARRAY(VARIANT) *pArray);
    [propput, id(0)] HRESULT ArrayProperty([in] SAFEARRAY(VARIANT) Array);
    
    
    // Somewhere in javascript
    
    function ax2js(axArray) {    
        return new VBArray(array).toArray();
    }
    
    function js2ax(jsArray) {
        var dict = new ActiveXObject("Scripting.Dictionary");
    
        for (var i = 0; i < jsArray.length; i++) {
            dict.add(i, jsArray[i]);
        }
    
        return dict.Items();
    }
    
    function fooHandler() {
        var ax = new ActiveXObject("My.My");
    
        var ar = ax2js(ax.ArrayProperty);
    
        ax.ArrayProperty = js2ax(ar);
    }
    

    【讨论】:

    • 您不能使用 VBArray。它在 JScript 中不存在,至少对于 IE8。
    • MSDN docs for VBArray 似乎另有说明:“支持以下文档模式:Quirks、Internet Explorer 6 标准、Internet Explorer 7 标准、Internet Explorer 8 标准、Internet Explorer 9 标准和 Internet Explorer 10 个标准。在 Windows 应用商店应用中不受支持。"
    • 我可以确认这是可行的。作为一个小改进,如果您需要一个字节数组,您可以在 *.idl 文件中将 SAFEARRAY(VARIANT) 替换为 SAFEARRAY(BYTE)。
    • @AlexChe 对我来说,当我从 SAFEARRAY(VARIANT) 切换到 SAFEARRAY(BSTR) 时它停止工作你知道为什么会这样吗?谢谢
    • @JulienM,快速搜索指向一个人的blog post,说这是JScript 的限制,它只支持SafeArray of Variants。我知道这与我之前的评论有些矛盾,所以可能并不完全正确。我不能告诉你更多,因为我已经很久没有玩这个了。
    【解决方案2】:

    您可能需要使用 SAFEARRAY 来传递数据。有一个名为CComSafeArray 的ATL 包装器。希望这足以让您开始,如果没有的话 我会挖掘一些代码。

    【讨论】:

      【解决方案3】:

      据我所知(和我的经验),在与 javascript 对话时,您只能使用以下基本数据类型:

      • 字符串
      • 内部
      • 布尔
      • IDispatch*

      其他任何方法似乎都不起作用。我从未尝试过使用 SAFEARRAY,但我可以提出一个可能的替代方案。

      如果您获得对 DOM 窗口的引用(我不会在这里介绍;如果您不知道如何搜索和/或提交新问题,我可以在那里回答),您可以使用 IDispatch在窗口上调用方法“Array”,它将为空的 javascript 数组返回 IDispatch*。然后,您可以为要作为 int 发送到 javascript 的每个字节在 Array IDispatch* 上调用“推送”,然后将 Array 的 IDispatch* 作为相关方法或属性的返回值返回。您将在 javascript 中以整数数组的形式获取数据,但每个元素都是一个字节,您可以这样使用它。

      如果您能建议另一种在 javascript 中使用二进制数据的方法(暂时忘记 activex 控件),我或许可以告诉您如何以这种方式从控件返回数据。

      这本质上是 FireBreath(IE 和 Firefox 的开源插件框架;http://www.firebreath.org)在您从 JSAPI(javascript 脚本对象)方法返回向量以将数据作为数组返回给 javascript 时使用的方法。您可以在兼容 NPAPI 的浏览器上使用类似(几乎相同)的方法。

      【讨论】:

        【解决方案4】:

        我知道这是一篇很老的帖子,但我自己偶然发现了将二进制数据从 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 数组,因为这实际上是它的内部实现。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2010-11-10
          • 1970-01-01
          • 2020-10-18
          • 2010-09-29
          • 2019-02-14
          • 2014-01-09
          • 2014-04-16
          相关资源
          最近更新 更多