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.
You may be able to hack your way into having an OleVariant with your array data in it without copying it.
However, a problem you are going to have is when the OleVariant variable falls out of scope.
The RTL is going to call SafeArrayDestroy in oleaut32.dll to destroy the memory associated with the safe array, and that's going to fail because the memory did not come from where Windows expected.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With