我可以将内存从缓冲区复制到安全数组中,如下所示
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;
但是,有没有办法直接将我的指针和大小传递到varArray
类型OleVariant
而不复制内存?
[编辑]
我可以看到OleVariant
中的数组是SAFEARRAY
(定义为PVarArray = ^TVarArray
),所以看起来应该有一种方法可以通过填充值来实现一个TVarArray
并在VType
中设置VArray
和OleVariant
值。
答案 0 :(得分:8)
有没有办法直接将我的指针和大小传递给varArray类型OleVariant而不复制内存?
Delphi的OleVariant
类型是OLE VARIANT
记录的包装器。 OLE支持的唯一类型的数组是SAFEARRAY
,由Win32 SAFEARRAY
函数创建的任何SafeArrayCreate...()
都会分配并拥有它指向的数据块。您必须将源数据复制到该块中。
要绕过它,您必须跳过VarArrayCreate()
(调用SafeArrayCreate()
)并使用SAFEARRAY
自行分配SafeArrayAllocDescriptor/Ex()
,这样它就不会分配数据块。然后,您可以将数组的pvData
字段设置为指向现有内存块,并在其FADF_AUTO
字段中启用fFeatures
标志以告知SafeArrayDestroy()
(其中OleVariant
调用时不再需要SAFEARRAY
)来释放内存块。
尝试这样的事情:
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;
如果您实际上不需要使用OLE,例如,如果您没有通过OLE将数组传递给其他人的应用程序,那么您应该使用Delphi的Variant
键入而不是。您可以编写Custom Variant Type
来保存您想要的任何数据,甚至是对现有内存块的引用,然后根据需要使用Variant
,并让您的自定义类型实现根据需要管理数据。
答案 1 :(得分:4)
您可以在不使用数组数据的情况下修改OleVariant,而无需复制它。
但是,您将遇到的问题是OleVariant变量超出范围时。
RTL将调用oleaut32.dll中的SafeArrayDestroy来销毁与安全阵列相关联的内存,并且这会因为内存不是来自Windows所期望的内存而失败。