我可以在不复制的情况下从缓冲区 (pByte) 和大小创建 VarArray OleVariant 吗?

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

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

  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 中的值并在 OleVariant.

中设置 VTypeVArray

您或许可以通过破解获得包含数组数据的 OleVariant,而无需复制它。

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

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

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

Delphi 的 OleVariant type is a wrapper for OLE's VARIANT record. The only type of array that OLE supports is SAFEARRAY 和任何由 ​​Win32 SafeArrayCreate...() 函数创建的 SAFEARRAY 分配并拥有它指向的数据块。您必须将源数据复制到该块中。

要绕过它,您必须跳过 VarArrayCreate()(调用 SafeArrayCreate())并使用 SafeArrayAllocDescriptor/Ex() 自己分配 SAFEARRAY,这样它就不会分配数据堵塞。然后你可以设置数组的 pvData 字段指向你现有的内存块,并在它的 fFeatures 字段中启用 FADF_AUTO 标志来告诉 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 type instead. You can write a Custom Variant Type 来保存无论您想要什么数据,甚至是对现有内存块的引用,然后根据需要使用 Variant 并让您的自定义类型实现根据需要管理数据。