Aquí hay dos errores.
Primero de todos en Variants.DynArrayVariantBounds
. Cuando la matriz dinámica es nil
, esto devuelve erróneamente un par de límites bajos/altos de (0, 0)
. Debería devolver (0, -1)
. Este error se corrigió en las últimas versiones de Delphi. Eso ocasiona que V := sa
devuelva una matriz variante con un solo elemento vacío.
El segundo error afecta a la otra dirección, sa := V
. Este error todavía está presente en las últimas versiones de Delphi. Este error está en Variants.DynArrayFromVariant
. Hay un bucle repeat/until
que recorre la matriz de variante de entrada y rellena la matriz dinámica de salida. Cuando la matriz de variante de entrada está vacía, no debe ingresar ese bucle repeat/until
. Sin embargo, el código lo hace erróneamente e intenta leer un elemento de la matriz variante con VarArrayGet
. Como la matriz está vacía, eso provoca un error de tiempo de ejecución. He informado esto: QC#109445.
Aquí hay un código muy simple que corrige los errores. Tenga en cuenta que solo tengo en cuenta el caso en que las matrices son unidimensionales. Si necesita admitir matrices dimensionales superiores, puede ampliar este enfoque para hacerlo.
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.
quizá encasillado es 'variante -> string -> gama de strings' en lugar de' variante -> puntero -> gama de strings' –