2015-11-03 10 views
5

バッファ(pByte)とサイズからコピーせずにVarArray OleVariantを作成できますか?

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に私のポインタとサイズを渡す方法があるように私は安全な配列に、バッファからメモリをコピーすることができますか?

TVarArray、設定の値を取り込むことにより、これを行う方法があるはずのようにそれはそうので、私は、OleVariant内部の配列は、(PVarArray = ^TVarArrayとして定義)SAFEARRAYであることがわかります

[編集] OleVariantVTypeVArrayの値です。

答えて

8

私のポインタとサイズをメモリをコピーせずにvarArray型OleVariantに直接渡す方法はありますか?

デルファイのOleVariantタイプは、OLEのVARIANTレコードのラッパーです。 OLEがサポートする唯一のタイプの配列はSAFEARRAYであり、Win32 SafeArrayCreate...()によって作成されたSAFEARRAY関数は、それが指すデータブロックを割り当てて所有します。そのブロックにソースデータをコピーする必要があります。それを回避するには

、あなたはそれがデータブロックを割り当てません(SafeArrayCreate()を呼び出す)VarArrayCreate()をスキップしてSafeArrayAllocDescriptor/Ex()を使用してSAFEARRAY自分を割り当てる必要があります。次に、配列のpvDataフィールドを既存のメモリブロックを指すように設定して、fFeaturesフィールドのFADF_AUTOフラグにSafeArrayDestroy()(これはSAFEARRAYが不要になったときにOleVariantが呼び出されます)がメモリブロックを解放しないようにします。

このような何か試してください:あなたが実際にOLEを使用する必要がない場合は、そのようなあなたは、あなたがDelphiのVariantタイプを使用する必要があり、OLEを介して他の人のアプリケーションにあなたの配列を渡すされていないかのように、

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; 

を代わりに。 Custom Variant Typeには、必要なデータ(既存のメモリブロックへの参照)を格納してから、必要に応じてVariantを使用して、カスタムタイプの実装で必要に応じてデータを管理できます。

+0

ありがとうございました。 –

4

OleVariantをコピーしなくても、配列データを持つことができます。

しかし、問題は、OleVariant変数が範囲外になる場合です。

RTLは、oleaut32.dllのSafeArrayDestroyを呼び出して、安全な配列に関連付けられたメモリを破棄します。メモリはWindowsが予想した場所から来なかったために失敗します。

+3

Windowsが 'SAFEARRAY'のためにメモリを割り当てさせるようにすることができます。' SafeArrayDestroy() 'はそれを解放することができますが、独自の要素ブロックではなくユーザー定義の要素ブロックで' SAFEARRAY'点を作ることができます。そのトリックは、SafeArrayCreate()の代わりに 'SafeArrayAllocDescriptor/Ex()'を使用して(SafeArrayCreate() 'が使用する))、SAFEARRAYの' fFeatures'フィールドを直接変更して 'SafeArrayDestroyブロック。 –

関連する問題