IWebbrowser2: использование массива Uint8 (заполнение без зацикливания)

Я могу создать массив Uint8 в окне IWebbrowser2:

IHTMLWindow2 window = ...;
DISPID dispid_uint8array = ...;

VARIANT self;
self.vt = VT_NULL;

VARIANT length;
length.vt = VT_I4;
length.lVal = 100;

VARIANT args[2] = { self, length };
DISPID named_args[1] = { DISPID_THIS };

DISPPARAMS params;
params.rgvarg = args;
params.rgdispidNamedArgs = named_args;
params.cArgs = 2;
params.cNamedArgs = 1;

VARIANT result;
result.vt = VT_EMPTY; 
HRESULT hr = container->Invoke(
    dispid_uint8array, IID_NULL, LOCALE_USER_DEFAULT,
    DISPATCH_METHOD, &params, &result, nullptr, nullptr
);

assert(hr == S_OK);
assert(result.vt == VT_DISPATCH);

IDispatch my_new_uint8array = result.pdispVal;

Теперь я могу установить элементы полей my_new_uint8array с помощью IDispatch::Invoke(..., DISPATCH_PROPERTYPUT, ...) в петле.

Но не существует ли надлежащего интерфейса для заполнения всего буфера одним вызовом? Например, я могу как-то получить содержащийся буфер?

Где-то есть определение интерфейса, что-то вроде IUint8Array?

1 ответ

Решение

Я придумал невероятно уродливый хак: использование ArrayBuffer <canvas>, Я буду публиковать только псевдокод, потому что полный C++, включая проверку ошибок, распаковку и т. Д., Слишком длинный:

Прелюдия:

  • FEATURE_BROWSER_EMULATION был установлен на 11001
  • IWebBrowser2::get_ReadyState возвращается READYSTATE_COMPLETE
  • IHTMLDocument6::get_documentMode возвращается 11
  • IHTMLDocument5::get_compatMode возвращается "CSS1Compat"
  • IHTMLDocument2 *doc а также IHTMLWindow2 *win установлены.
  • Я использую простые строки в своем псевдокоде, но вы должны использовать BSTR конечно!
  • Возможно, вам придется queryInterface один или два раза, чтобы результаты соответствовали.
  • Не игнорируйте ошибки!

Как получить "Uint8Array":

ULONG len_in_dwords = (LENGTH_I_WANT + 3) / 4;

IHTMLCanvasElement *canvas = doc->createElement("canvas");
ICanvasRenderingContext2D *context = canvas->getContext("2d");
ICanvasPixelArrayData *array_data = context->createImageData(len_in_dwords, 1);

// use this variable for interfaces that accept an ArrayBuffer
IDispatch *array_buffer = Get property "buffer" of array_data;

// use this variable to edit the content:
BYTE *byte_buffer;
ULONG buffer_length_in_bytes;
array_data->GetBufferPointer(&byte_buffer, &buffer_length_in_bytes);

// no need for that anymore:
canvas->Release();
context->Release();
array_data->Release();

ArrayBuffer array_buffer всегда имеет размер, кратный четырем. Это работает для меня, но может не работать для других случаев использования. Ты можешь использовать array_buffer метод slice(0, LENGTH_I_WANT) удалить лишние байты после memcpy'ing byte_buffer,

Другие вопросы по тегам