Ci sono due bug qui.
Prima di tutto in Variants.DynArrayVariantBounds
. Quando l'array dinamico è nil
restituisce erroneamente una coppia limite basso/alto di (0, 0)
. Dovrebbe restituire (0, -1)
. Questo bug è stato risolto nelle ultime versioni di Delphi. Ciò causa che V := sa
restituisce un array variante con un elemento singolo, vuoto.
Il secondo errore riguarda l'altra direzione, sa := V
. Questo bug è ancora presente nelle ultime versioni di Delphi. Questo errore si trova in Variants.DynArrayFromVariant
. Esiste un ciclo repeat/until
che passa sopra l'array di varianti di input e popola l'array dinamico di output. Quando l'array della variante di input è vuoto, non deve entrare nel ciclo repeat/until
. Tuttavia, il codice lo fa erroneamente e tenta di leggere un elemento dell'array variante con VarArrayGet
. Poiché la matrice è vuota, ciò provoca un errore di runtime. Ho segnalato questo: QC#109445.
Ecco un bit di codice molto semplice che corregge i bug. Si noti che ho considerato solo il caso in cui gli array sono unidimensionali. Se è necessario supportare matrici di dimensioni superiori, è possibile estendere questo approccio per farlo.
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.
fonte
2012-10-11 08:44:20
forse typecast è 'variante -> string -> array di strings' piuttosto che' variante -> pointer -> array di strings' –