2012-10-11 4 views
5

コンパイルしてDelphi 6でエラーなく実行するコードを考えてみましょう。saに空の配列を表示する代わりに、動的文字列配列を復元すると、長さが1の配列が表示されます。空の文字列。これはなぜですか?また、NILダイナミックアレイをバリアントに安全に割り当てて、それを適切に復元するにはどうすればよいですか?コードは次のとおりです。VariantにNIL配列を割り当てると、空でない配列がDelphi 6で返されるのはなぜですか?

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

おそらくtypecastは 'variant - > pointer - >文字列の配列'ではなく 'variant - > string - > array of strings'です。 –

答えて

5

ここに2つのバグがあります。

まずはVariants.DynArrayVariantBoundsです。動的配列がnilである場合、これは(0, 0)の下限/上限のペアを誤って返します。それは(0, -1)を返す必要があります。このバグは、Delphiの最新バージョンで修正されています。これにより、V := saは、単一の空の要素を持つバリアント配列を返すようになります。

第2のバグは、他の方向のsa := Vに影響します。このバグはDelphiの最新バージョンにはまだ存在します。このバグはVariants.DynArrayFromVariantにあります。 repeat/untilループがあり、入力バリアント配列上を歩み、出力ダイナミック配列に移入します。入力バリアント配列が空の場合は、repeat/untilループには入力しないでください。しかし、コードは誤ってそのようにして、VarArrayGetでバリアント配列の要素を読み込もうとします。配列が空であるため、ランタイムエラーが発生します。私はこれを報告した:QC#109445

ここには、バグを修正する非常に単純なコードがあります。私は、配列が1次元である場合のみを考慮していることに注意してください。より高次元の配列をサポートする必要がある場合は、このアプローチを拡張することができます。

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

ありがとうございました。それは本当に大きなバグです。 –

関連する問題