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