我正在尝试将带有
TdxDBGrid
的 Delphi 6 应用程序迁移到 Delphi 2009,暂时我想保留 TdxDBGrid
,因为它具有 TcxGrid
没有的功能(我们正在转向 TcxGrid
)
一般情况下)。当用户在 TdxDBGrid
: 中输入新行和新数值时,我陷入了这个错误
无法将类型 (UnicodeString) 的变体转换为类型 (Double)
我发现这个错误非常普遍 - 这一切都归结为
''
如何转换为 Double
(例如转换为 333)。 Delphi 2009 有这个例程(来自 Delphi RTL Variants.pas
):
function VarToDoubleAsString(const V: TVarData): Double;
var
S: WideString;
LValue: Extended;
LResult: HResult;
begin
_VarToWStr(S, V);
LResult := VarR8FromStr(S, VAR_LOCALE_USER_DEFAULT, 0, Result);
case LResult of
VAR_OK:; // in this case the OS function has put the value into result
VAR_TYPEMISMATCH:
if TryStrToFloat(S, LValue) then
Result := LValue
else
VarResultCheck(VAR_TYPEMISMATCH, V.VType, varDouble);
else
VarResultCheck(LResult, V.VType, varDouble);
end;
end;
但是Delphi 6有这个例程:
function VarToRealAsString(const V: TVarData): Extended;
var
S: String;
LValue: Double;
LResult: HResult;
begin
_VarToLStr(S, V);
LResult := VarR8FromStr(S, $400, 0, LValue);
if LResult = VAR_OK then
Result := LValue
else if not TryStrToFloat(S, Result) then
VarResultCheck(LResult, varString, varDouble);
end;
问题从
LResult := VarR8FromStr(S, VAR_LOCALE_USER_DEFAULT, 0, Result);
开始,其中返回类型不匹配,并且流程向下分支到 TryStrToFloat(S, LValue)
,不知何故失败。很难想象为什么 TryStrToFloat('', very-small-number)
会失败,但是这段代码:
function TryStrToFloat(const S: string; out Value: Extended): Boolean;
begin
Result := TextToFloat(PChar(S), Value, fvExtended);
end;
表明
Try...
可能需要一个 Unicode 字符串,但到目前为止的所有处理都是通过 WideString
完成的,这就是转换通过以下方式完成的原因:
procedure _UStrFromWStr(var Dest: UnicodeString; const Source: WideString);
asm
{ -> EAX pointer to dest }
{ EDX pointer to WideString data }
XOR ECX,ECX
TEST EDX,EDX
JZ @@1 // nil source => zero length
MOV ECX,[EDX-4]
SHR ECX,1 // length in WideString is byte count
@@1: JMP _UStrFromPWCharLen
end;
还有一些混乱。我不明白这部分,但要么:
WideString
''
无法转换为 UnicodeString
,或very_small_number
不适合作为默认值。所以 - 如果我可以纠正这些
Variant
处理程序中的某些内容并将此更正的 Variants.pas
文件添加到我的项目中,那么我可以使用旧的 TdxDBGrid
一段时间。
那么 - 是否有人有类似的迁移问题的经验,正是这种类型的
Variant
处理、Variant
转换代码,并且他们知道并且可以建议对 Variant
处理/转换程序进行或多或少的安全修正?
您可以更改 Delphi 将变量字符串转换为双精度型的方式。因此,您可以告诉 Delphi 将空字符串转换为值为 0.0 的双精度值。您可能会因此隐藏其他错误而不是修复它们。所以要小心。
uses VarUtils;
{$IF compilerversion >= 24}
function MyVarR8FromStr(const strIn: PWideChar; LCID: Integer; dwFlags: Integer;
out dblOut: Double): HRESULT; stdcall;
const
CResult: array [False..True] of HRESULT = (VAR_TYPEMISMATCH, VAR_OK);
begin
if StrLen(strIn) = 0 then
begin
Result := VAR_OK;
dblOut := 0.0;
end
else
Result := CResult[TryStrToFloat(strIn, dblOut)];
end;
{$ELSE}
function MyVarR8FromStr(const strIn: WideString; LCID: Integer; dwFlags: Longint;
out dblOut: Double): HRESULT; stdcall;
const
CResult: array [False..True] of HRESULT = (VAR_TYPEMISMATCH, VAR_OK);
begin
if strIn = '' then
begin
Result := VAR_OK;
dblOut := 0.0;
end
else
Result := CResult[TryStrToFloat(strIn, dblOut)];
end;
{$IFEND}
initialization
VarUtils.VarR8FromStr := MyVarR8FromStr;
end.