I can copy the memory from the buffer into the safe array as follows
function GetVarArrayFromBuffer(ABuffer : pByte; ASizeInBytes: Cardinal) : OleVariant;
var
LVarArrayPtr: Pointer;
begin
Result := VarArrayCreate([0, ASizeInBytes - 1], varByte);
LVarArrayPtr := VarArrayLock(Result);
try
Move(ABuffer^, LVarArrayPtr^, ASizeInBytes);
finally
VarArrayUnLock(Result);
end;
end;
But, is there a way to directly pass my pointer and size into a varArray
type OleVariant
without copying memory?
[Edit]
I can see that the array inside the OleVariant
is a SAFEARRAY
(defined as PVarArray = ^TVarArray
), so it seems like there should be a way to do this by populating the values in a TVarArray
and setting the VType
and VArray
values in the OleVariant
.
is there a way to directly pass my pointer and size into a varArray type OleVariant without copying memory?
Delphi's OleVariant
type is a wrapper for OLE's VARIANT
record. The only type of array that OLE supports is SAFEARRAY
, and any SAFEARRAY
created by a Win32 SafeArrayCreate...()
function allocates and owns the data block that it points to. You have to copy your source data into that block.
To bypass that, you would have to skip VarArrayCreate()
(which calls SafeArrayCreate()
) and allocate the SAFEARRAY
yourself using SafeArrayAllocDescriptor/Ex()
so it does not allocate a data block. Then you can set the array's pvData
field to point at your existing memory block, and enable the FADF_AUTO
flag in its fFeatures
field to tell SafeArrayDestroy()
(which OleVariant
calls when it does not need the SAFEARRAY
anymore) to not free your memory block.
Try something like this:
uses
..., Ole2, ComObj;
// Delphi's Ole2 unit declares SafeArrayAllocDescriptor()
// but does not declare SafeArrayAllocDescriptorEx()...
function SafeArrayAllocDescriptorEx(vt: TVarType; cDims: Integer; var psaOut: PSafeArray): HResult; stdcall; external 'oleaut32.dll';
function GetVarArrayFromBuffer(ABuffer : pByte; ASizeInBytes: Cardinal) : OleVariant;
var
SA: PSafeArray;
begin
OleCheck(SafeArrayAllocDescriptorEx(VT_UI1, 1, SA));
SA.fFeatures := SA.fFeatures or FADF_AUTO or FADF_FIXEDSIZE;
SA.cbElements := SizeOf(Byte);
SA.pvData := ABuffer;
SA.rgsabound[0].lLbound := 0;
SA.rgsabound[0].cElements := ASizeInBytes;
TVarData(Result).VType := varByte or varArray;
TVarData(Result).VArray := PVarArray(SA);
end;
If you don't actually need to use OLE, such as if you are not passing your array to other people's applications via OLE, then you should use Delphi's Variant
type instead. You can write a Custom Variant Type
to hold whatever data you want, even a reference to your existing memory block, and then use Variant
as needed and let your custom type implementation manage the data as needed.