Передача массива байтов из ActiveX в JavaScript и наоборот - PullRequest
4 голосов
/ 18 декабря 2009

Мне нужно передать данные (байтовый массив, то есть char *) из объекта ActiveX (используя Visual C ++ с ATL) в мой код 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 ++

Может ли кто-нибудь дать мне рабочий код в его простейшем виде?

Большое спасибо!

Kristin

Ответы [ 4 ]

3 голосов
/ 03 декабря 2010
// 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);
}
0 голосов
/ 08 июля 2015

Я понимаю, что это очень старый пост, но я сам наткнулся на ту же проблему передачи двоичных данных из ActiveX в Javascript и решил представить решение, основанное на предложении таксиста.

Перед этим я хотел бы отметить, что также возможно создать SAFEARRAY из двоичных данных и отправить этот объект обратно в JS. Единственная проблема заключается в том, что для распаковки этого объекта необходимо использовать VBScript, преобразовать его в тип данных, распознаваемый только JScript (диалект Javascript от Microsoft), который затем можно использовать для создания традиционного массива JS.

Не вдаваясь в причину этого решения (для проверки ответа таксиста), вот метод, который создаст массив Javascript в элементе управления ActiveX и вернет этот массив 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. Во-первых, мы получаем указатель на клиентский сайт, где находится наш элемент управления. Затем мы используем QI (интерфейс запросов) для IServiceProvider, который является интерфейсом IE, который реализует множество поддерживаемых сервисов. Одним из них является IHTMLWindow2 , который является типом window объекта в Javascript. Теперь, когда у нас есть указатель на наш оконный объект, мы можем создать объект Array. Массив - это просто метод объекта IHTMLWindow2, и для создания нового массива мы должны вызвать эту функцию.

Чтобы вызвать метод для COM-объекта (а IHTMLWindow2 - это просто интерфейс, реализованный некоторым COM-объектом), этот объект должен реализовать интерфейс IDispatch, который позволяет пользователю вызывать метод этого объекта с помощью Invoke * 1015. * метод. GetIDsOfNames метод используется для извлечения DISPID (идентификатор отправки) метода Array, а затем мы наконец создаем новый массив, вызывая метод Array для нашего window_obj объекта. В параметре ret_val (типа VARIANT) мы получим указатель IDispatch *, представляющий наш массив JS.

Очевидно, что делать дальше: используйте этот указатель, чтобы получить DISPID метода push , а затем заполните массив, вызывая этот метод снова и снова. В примере функции также показано, как построить объекты DISPPARAMS и VARIANTARG, необходимые для метода IDispatch :: Invoke.

Наконец, мы возвращаем указатель IDispatch * из метода. JS распознает этот объект как собственный массив JS, потому что на самом деле это его внутренняя реализация.

0 голосов
/ 26 декабря 2009

Насколько мне известно (и по моему опыту), вы можете использовать только следующие основные типы данных при общении с JavaScript:

  • Строка
  • Int
  • Double
  • Bool
  • IDispatch *

Все остальное, похоже, не работает. Я никогда не пробовал использовать SAFEARRAY, но могу предложить возможную альтернативу.

Если вы получите ссылку на окно DOM (я не буду здесь это освещать; если вы не знаете, как, найдите и / или отправьте новый вопрос, и я могу ответить на него там), вы можете использовать IDispatch для Вызовите метод «Массив» в окне, и он вернет IDispatch * для пустого массива javascript. Затем вы можете вызвать «push» в массиве IDispatch * для каждого байта, который вы хотите отправить в javascript как целое число, и затем вернуть IDispatch * массива в качестве значения, возвращаемого из рассматриваемого метода или свойства. Вы получите данные в javascript в виде массива целых чисел, но каждый элемент является байтом, и вы можете использовать его таким образом.

Если вы можете предложить другой способ использования двоичных данных в javascript (на мгновение забудьте элемент управления activex), я мог бы рассказать вам, как таким способом вернуть данные из элемента управления.

По сути, это метод, который FireBreath (инфраструктура плагинов с открытым исходным кодом для IE и Firefox; http://www.firebreath.org)) использует, когда вы возвращаете вектор из метода JSAPI (javascript scriptted object), чтобы вернуть данные в javascript в виде массива. . Вы можете использовать аналогичный (почти идентичный) метод в браузерах, совместимых с NPAPI.

0 голосов
/ 18 декабря 2009

Возможно, вам нужно использовать SAFEARRAY для передачи данных. Для этого есть оболочка ATL, которая называется CComSafeArray . Надеюсь, этого будет достаточно для начала, если нет, то Я выкопаю код.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...