Я понимаю, что это очень старый пост, но я сам столкнулся с той же проблемой передачи двоичных данных из 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