ここに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.
おそらくtypecastは 'variant - > pointer - >文字列の配列'ではなく 'variant - > string - > array of strings'です。 –