Передача массива байтов из ActiveX в javascript и наоборот

Мне нужно передать данные (массив байтов, т.е. 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 = ""
  • Передать безопасный массив байтовых данных из С++

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

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

Кристин


person Kristin    schedule 18.12.2009    source источник


Ответы (4)


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

person Rob    schedule 18.12.2009

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

  • Нить
  • Интерн.
  • Двойной
  • Буль
  • IDispatch*

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

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

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

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

person taxilian    schedule 26.12.2009

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

Перед этим я хотел бы отметить, что также возможно построить SAFEARRAY из двоичных данных и отправить этот объект обратно в JS. Единственная проблема заключается в том, что для распаковки этого объекта необходимо использовать VBScript, преобразовать его в тип данных, распознаваемый только JScript (диалект Microsoft Javascript), который затем можно использовать для построения традиционного массива 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. . Метод GetIDsOfNames используется для получения DISPID (идентификатора отправки) метода Array, а затем мы, наконец, создаем новый массив, вызывая метод Array для нашего объекта window_obj. В параметре ret_val (типа VARIANT) мы получим указатель IDispatch*, представляющий наш JS-массив.

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

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

person dbajgoric    schedule 08.07.2015

person    schedule
comment
Вы не можете использовать VBArray. Его нет в JScript, по крайней мере, для IE8. - person SineSwiper; 22.02.2012
comment
документы MSDN для VBArray кажется, указывает на обратное: Поддерживается в следующих режимах документа: Quirks, стандарты Internet Explorer 6, стандарты Internet Explorer 7, стандарты Internet Explorer 8, стандарты Internet Explorer 9 и стандарты Internet Explorer 10. Не поддерживается в приложениях Магазина Windows. - person 80x25; 05.11.2014
comment
Я могу подтвердить, что это работает. В качестве небольшого улучшения, если вам нужен массив байтов, вы можете заменить SAFEARRAY(VARIANT) на SAFEARRAY(BYTE) в файле *.idl. - person Alex Che; 01.07.2015
comment
@AlexChe для меня он перестает работать, когда я переключаюсь с SAFEARRAY (VARIANT) на SAFEARRAY (BSTR). У вас есть идеи, почему это происходит? Спасибо - person Julien M; 20.01.2017
comment
@JulienM, быстрый поиск указал на сообщение в блоге от парня, в котором говорится, что это ограничение JScript, который поддерживает только SafeArray of Variants. Я знаю, что это несколько противоречит моему предыдущему комментарию, так что, возможно, это не совсем так. Я не могу сказать вам больше, потому что я давно не играл с этим. - person Alex Che; 21.01.2017
comment
@JulienM, в любом случае, поскольку VARIANT может фактически содержать BSTR внутри, я думаю, вы можете просто использовать SAFEARRAY (VARIANT) для передачи массива строк. - person Alex Che; 21.01.2017
comment
@AlexChe Ну, это то, что я сделал, но чувствовал, что это плохое слово, и я хотел бы понять, почему? Спасибо за ваши ответы! - person Julien M; 21.01.2017
comment
@AlexChe Знаете ли вы, есть ли способ, чтобы JScript поддерживал определяемую пользователем структуру, возвращаемую ActiveX? Я вижу их определение в idl, но не могу работать с ними в JS. - person Julien M; 23.01.2017