2012-10-11 10 views
5

Betrachten Sie den folgenden Code, der kompiliert und ohne Fehler in Delphi 6 ausgeführt wird. Wenn ich das dynamische String-Array wiederherstelle, sehe ich in sa ein Array mit einer Länge von 1 mit einem einzelnen Element, das ein enthält leerer String. Warum ist dies und wie kann ich einem Variant ein dynamisches NIL-Array zuweisen und es ordnungsgemäß wiederherstellen? Hier ist der Code:Warum führt die Zuweisung eines NIL-Arrays zu einem Variant dazu, dass in Delphi 6 ein nicht leeres Array zurückgegeben wird?

TDynamicStringArray = array of string; 

var 
    V: Variant; 
    sa: TDynamicStringArray; 
begin 
    sa := nil; 

    V := sa; 

    sa := V; 

    OutputDebugString('sa has a single element now with an empty string in it when I expect it to be empty.'); 
end; 
+0

vielleicht Typumwandlung ist "Variante -> String -> Array von Strings" anstatt "Variante -> Zeiger -> Array von Strings" –

Antwort

5

Es gibt zwei Fehler hier.

Zuerst in Variants.DynArrayVariantBounds. Wenn das dynamische Array nil ist, wird fälschlicherweise ein Low/High-Paar von (0, 0) zurückgegeben. Es sollte (0, -1) zurückgeben. Dieser Fehler wurde in den neuesten Versionen von Delphi behoben. Das verursacht V := sa, um ein Variantenarray mit einem einzelnen leeren Element zurückzugeben. Der zweite Fehler betrifft die andere Richtung, sa := V. Dieser Fehler ist immer noch in den neuesten Versionen von Delphi vorhanden. Dieser Fehler ist in Variants.DynArrayFromVariant. Es gibt eine repeat/until Schleife, die über das Array mit der Eingabevariante läuft und das dynamische Ausgabe-Array auffüllt. Wenn das Eingabe-Varianten-Array leer ist, sollte es nicht in die repeat/until-Schleife eintreten. Der Code tut dies jedoch fälschlicherweise und versucht, ein Element des Varianten-Arrays mit zu lesen. Da das Array leer ist, verursacht das einen Laufzeitfehler. Ich habe dies gemeldet: QC#109445.

Hier ist ein sehr einfaches Stück Code, das die Fehler behebt. Beachten Sie, dass ich nur den Fall betrachte, in dem die Arrays eindimensional sind. Wenn Sie höherdimensionale Arrays unterstützen müssen, können Sie diesen Ansatz erweitern, um dies zu tun.

program Project1; 

{$APPTYPE CONSOLE} 

uses 
    Variants; 

var 
    OriginalVarFromDynArray: procedure(var V: Variant; const DynArray: Pointer; TypeInfo: Pointer); 
    OriginalVarToDynArray: procedure(var DynArray: Pointer; const V: Variant; TypeInfo: Pointer); 

function DynArrayVarType(typeInfo: PDynArrayTypeInfo): Integer; 
const 
    tkDynArray = 17; 
begin 
    Result := varNull; 
    if (typeInfo<>nil) and (typeInfo.Kind=tkDynArray) then 
    begin 
    Inc(PChar(typeInfo), Length(typeInfo.name)); 
    Result := typeInfo.varType; 
    if Result=$48 then 
     Result := varString; 
    end; 
    if (Result<=varNull) or (Result=$000E) or (Result=$000F) or ((Result>varInt64) and not (Result=varString)) then 
    VarCastError; 
end; 

procedure VarFromDynArray(var V: Variant; const DynArray: Pointer; TypeInfo: Pointer); 
var 
    VarType, DynDim: Integer; 
begin 
    DynDim := DynarrayDim(PDynArrayTypeInfo(TypeInfo)); 
    if DynDim=1 then 
    begin 
    //only attempt to deal with 1 dimensional arrays 
    if DynArray=nil then begin 
     VarClear(V); 
     VarType := DynArrayVarType(PDynArrayTypeInfo(TypeInfo)); 
     if VarType = varString then 
     VarType := varOleStr; 
     V := VarArrayCreate([0, -1], VarType); 
     exit; 
    end; 
    end; 
    OriginalVarFromDynArray(V, DynArray, TypeInfo); 
end; 

procedure VarToDynArray(var DynArray: Pointer; const V: Variant; TypeInfo: Pointer); 
var 
    DimCount: Integer; 
    Len: Integer; 
begin 
    DimCount:= VarArrayDimCount(V); 
    if DimCount=1 then 
    begin 
    //only attempt to deal with 1 dimensional arrays 
    Len := VarArrayHighBound(V, 1) - VarArrayLowBound(V, 1) + 1; 
    if Len=0 then begin 
     DynArraySetLength(DynArray, PDynArrayTypeInfo(TypeInfo), 1, @Len); 
     exit; 
    end; 
    end; 
    OriginalVarToDynArray(DynArray, V, TypeInfo); 
end; 

procedure FixVariants; 
var 
    VarMgr: TVariantManager; 
begin 
    GetVariantManager(VarMgr); 
    OriginalVarFromDynArray := VarMgr.VarFromDynArray; 
    VarMgr.VarFromDynArray := VarFromDynArray; 
    OriginalVarToDynArray := VarMgr.VarToDynArray; 
    VarMgr.VarToDynArray := VarToDynArray; 
    SetVariantManager(VarMgr); 
end; 

type 
    TDynamicStringArray = array of string; 

var 
    V: Variant; 
    sa: TDynamicStringArray; 
begin 
    FixVariants; 

    sa := nil; 
    V := sa; 
    sa := V; 

    Writeln(Length(sa)); 
    Readln; 
end. 
+0

Vielen Dank. Das ist ein wirklich großer Fehler. –