2015-11-03 7 views
5

kann ich den Speicher aus dem Puffer in den sicheren Array kopieren, wieKann ich ein VarArray OleVariant aus einem Puffer (pByte) und einer Größe erstellen, ohne zu kopieren?

folge
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; 

Aber ist es eine Möglichkeit, direkt OleVariant Speicher ohne das Kopieren meine Zeiger und Größe in einen varArray Typen passieren?

[Bearbeiten]

ich, dass die Anordnung im Inneren des OleVariant ist ein SAFEARRAY (definiert als PVarArray = ^TVarArray) sehen können, so dass es wie es scheint eine Möglichkeit, dies in einer TVarArray und Einstellung der Werte zu tun sein sollte bevöl die VType und VArray Werte in der OleVariant.

Antwort

8

Gibt es eine Möglichkeit, meinen Zeiger und meine Größe direkt in einen VarArray-Typ OleVariant zu übergeben, ohne Speicher zu kopieren?

OleVariant Typ Delphi ist ein Wrapper für VARIANT Rekord OLE. Der einzige Array-Typ, den OLE unterstützt, ist SAFEARRAY, und jeder SAFEARRAY, der von einer Win32 SafeArrayCreate...()-Funktion erstellt wird, weist den Datenblock zu, auf den er verweist, und besitzt ihn. Sie müssen Ihre Quelldaten in diesen Block kopieren.

Um das zu umgehen, würden Sie VarArrayCreate() überspringen müssen die SAFEARRAY selbst und zuweisen (die SafeArrayCreate() nennt) mit SafeArrayAllocDescriptor/Ex() so dass es nicht um einen Datenblock zugewiesen werden. Dann können Sie das Feld pvData des Arrays so einstellen, dass es auf Ihren vorhandenen Speicherblock zeigt, und das FADF_AUTO Flag in fFeatures aktivieren, um SafeArrayDestroy() (OleVariant Aufrufe, wenn es die SAFEARRAY nicht mehr benötigt) den Speicherblock nicht freizugeben.

versuchen, etwas wie folgt aus:

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; 

Wenn Sie nicht wirklich OLE verwenden müssen, wie zum Beispiel, wenn Sie nicht zu anderen Menschen die Anwendungen über OLE Array sind vorbei, dann sollten Sie die Verwendung Delphi Variant Typ stattdessen. Sie können eine Custom Variant Type schreiben, um alle gewünschten Daten zu speichern, sogar einen Verweis auf Ihren vorhandenen Speicherblock, und dann Variant nach Bedarf verwenden und Ihre benutzerdefinierte Implementierung die Daten nach Bedarf verwalten lassen.

+0

Vielen Dank. –

4

Sie können sich einen Weg in den OleVariant mit Ihren Array-Daten hineinhacken, ohne ihn zu kopieren.

Ein Problem, das Sie haben werden, ist jedoch, wenn die OleVariant-Variable außerhalb des Gültigkeitsbereichs liegt.

Die RTL wird SafeArrayDestroy in oleaut32.dll aufrufen, um den Speicher zu zerstören, der dem sicheren Array zugeordnet ist, und das wird fehlschlagen, weil der Speicher nicht von dem erwarteten Windows stammt.

+3

Sie können Windows den Speicher für das 'SAFEARRAY' selbst zuweisen lassen, so dass 'SafeArrayDestroy()' es freigeben kann, während der 'SAFEARRAY'-Punkt immer noch an einem benutzerdefinierten Elementblock erstellt werden kann. Der Trick besteht darin, 'SafeArrayAllocDescriptor/Ex()' anstelle von 'SafeArrayCreate()' zu verwenden (was VarArrayCreate() 'verwendet) und dann das' fFeatures'-Feld des SAFEARRAY direkt zu ändern, um 'SafeArrayDestroy()' das Element nicht freizugeben Block. –

Verwandte Themen