Rob*_*ler 5 delphi variant dynamic-arrays delphi-6
考虑低于该编译并在Delphi 6.当我恢复动态字符串数组没有错误运行,而不是看到空数组的代码SA,我看到的1与含有一个空字符串的单个元件的长度的数组.为什么这样,我如何安全地将NIL动态数组分配给Variant并正确恢复?这是代码:
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;
Run Code Online (Sandbox Code Playgroud)
这里有两个错误.
首先是Variants.DynArrayVariantBounds.当动态数组nil错误地返回一个低/高边界对时(0, 0).它应该回来(0, -1).最新版本的Delphi中修复了此错误.这导致V := sa返回具有单个空元素的变量数组.
第二个错误会影响另一个方向sa := V.最新版本的Delphi中仍然存在此错误.这个bug就在Variants.DynArrayFromVariant.有一个repeat/until循环遍历输入变量数组并填充输出动态数组.当输入变量数组为空时,它不应该进入该repeat/until循环.但是,代码错误地这样做并尝试读取变量数组的元素VarArrayGet.由于数组为空,因此会引发运行时错误.我已经报告了这个问题:QC#109445.
这是修复错误的一小段代码.请注意,我只考虑数组是一维的情况.如果您需要支持更高维度的数组,那么您可以扩展此方法.
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.
Run Code Online (Sandbox Code Playgroud)