Can I create a VarArray OleVariant from a buffer (pByte) and size without copying?

I can copy memory from a buffer to a 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 to varArray OleVariant type without copying the memory?

[Change]

I see that the array inside OleVariant is SAFEARRAY (defined as PVarArray = ^TVarArray ), so there seems to be a way to do this by filling in the values ​​in TVarArray and setting the VType and VArray to OleVariant .

+5
source share
2 answers

Is there a way to directly pass my pointer and size to varArray OleVariant type without copying the memory?

Delphi OleVariant type is a wrapper for an OLE VARIANT record. The only array type supported by OLE is SAFEARRAY , and any SAFEARRAY created by the Win32 SafeArrayCreate...() function selects and owns the data block that it points to. You need to copy the source data to this block.

To get around this, you need to skip VarArrayCreate() (which calls SafeArrayCreate() ) and allocate SAFEARRAY yourself using SafeArrayAllocDescriptor/Ex() so that it does not allocate a data block. You can then set the pvData array field in your existing memory block and enable the FADF_AUTO flag in the fFeatures field to tell SafeArrayDestroy() (which OleVariant calls when it does not need SAFEARRAY >) so as not to free the memory block.

Try something like this:

 uses ..., Ole2, ComObj; // Delphi 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 really do not need to use OLE, for example, if you do not pass your array to other applications through OLE, you should use Delphi VARIANT . You can write a Custom Variant Type to store any necessary data, even a link to an existing memory block, and then use VARIANT as needed and let your custom type implementation manage the data as needed.

+8
source

You can hack your way into OleVariant with the array data in it without copying it.

However, the problem you have to face is when the OleVariant variable goes out of scope.

RTL is going to call SafeArrayDestroy in oleaut32.dll to destroy the memory associated with the safe array, and this will happen because the memory did not come from the expected Windows.

+4
source

Source: https://habr.com/ru/post/1235147/


All Articles