5

我可以将缓冲区中的内存复制到安全数组中,如下所示

  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是 a SAFEARRAY(定义为PVarArray = ^TVarArray),所以似乎应该有一种方法可以通过填充 a 中的值并TVarArray设置.VTypeVArrayOleVariant

4

2 回答 2

8

有没有办法直接将我的指针和大小传递给 varArray 类型的 OleVariant 而无需复制内存?

Delphi 的OleVariant类型是 OLEVARIANT记录的包装器。OLE 支持的唯一数组类型是SAFEARRAY,并且SAFEARRAY由 Win32SafeArrayCreate...()函数创建的任何数组都分配并拥有它指向的数据块。您必须将源数据复制到该块中。

要绕过它,您必须跳过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类型。您可以编写 aCustom Variant Type来保存您想要的任何数据,甚至是对现有内存块的引用,然后Variant根据需要使用并让您的自定义类型实现根据需要管理数据。

于 2015-11-04T00:58:30.060 回答
4

您也许可以破解自己的方式来拥有一个包含数组数据的 OleVariant,而无需复制它。

但是,您将遇到的一个问题是 OleVariant 变量超出范围时。

RTL 将调用 oleaut32.dll 中的 SafeArrayDestroy 来销毁与安全数组关联的内存,这将失败,因为内存不是来自 Windows 预期的位置。

于 2015-11-03T22:36:59.320 回答