2012-10-11 31 views
5

Considere el siguiente código que se compila y se ejecuta sin errores en Delphi 6. Cuando recupero la matriz de cadenas dinámicas, en lugar de ver una matriz vacía en sa, veo una matriz con una longitud de 1 con un solo elemento que contiene cuerda vacía. ¿Por qué es esto y cómo puedo asignar con seguridad una matriz dinámica NIL a una variante y recuperarla correctamente? Aquí está el código:¿Por qué la asignación de una matriz NIL a una Variante causa que se devuelva una matriz no vacía en 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

quizá encasillado es 'variante -> string -> gama de strings' en lugar de' variante -> puntero -> gama de strings' –

Respuesta

5

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. 
+0

Gracias. Ese es un error realmente importante. –

Cuestiones relacionadas