I can create a Uint8array in an IWebbrowser2 window:
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, ¶ms, &result, nullptr, nullptr
);
assert(hr == S_OK);
assert(result.vt == VT_DISPATCH);
IDispatch my_new_uint8array = result.pdispVal;
Now I can set items fields of my_new_uint8array
using IDispatch::Invoke(..., DISPATCH_PROPERTYPUT, ...)
in a loop.
But isn't there a proper proper interface to fill the whole buffer with just one call? E.g. can I somehow retrieve the contained buffer?
Is there a definition of the interface somewhere, something like IUint8Array
?
I came up with an incredibly ugly hack: Using the ArrayBuffer of a <canvas>
. I'll only post the pseudo code, because the full C++, including error checking, unwrapping etc, is just too long:
Prelude:
FEATURE_BROWSER_EMULATION
was set to 11001
IWebBrowser2::get_ReadyState
returns READYSTATE_COMPLETE
IHTMLDocument6::get_documentMode
returns 11
IHTMLDocument5::get_compatMode
returns "CSS1Compat"
IHTMLDocument2 *doc
and IHTMLWindow2 *win
are set.BSTR
s of course!queryInterface
once or twice, so that the results fit.How to get a "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();
The ArrayBuffer array_buffer
has always a size divisible by four. That works for me, but might not work for other use cases. You can use array_buffer
's method slice(0, LENGTH_I_WANT)
to remove the extra bytes after memcpy'ing to byte_buffer
.