Delphi 2007->10.1 柏林港:解决 E2251 对 StrLen 的模糊过载调用

Delphi 2007->10.1 Berlin Port: Solving E2251 Ambiguious overloaded call to StrLen

背景:将我的代码移植到 Delphi 10.1 Berlin 并使用第三方库。有些不再可用,所以我会尝试修复代码...

以下代码(将参数从一个程序实例传递到另一个程序实例)引发了 E2251 对 StrLen 的不明确过载调用。我明白为什么,我只是不知道最好的解决方法。

type
  PInstInfo = ^TInstInfo;
  TInstInfo = packed record
    FirstInstanceWnd:HWND;
    ParamCount:Integer;
    Params:Array[0..MAX_PARAMS-1, 0..MAX_PARAM_SIZE] of Char;
  end;

// Memory is filled with:
 lpInfo^.ParamCount:=ParamCount;
 if lpInfo^.ParamCount>MAX_PARAMS then
  lpInfo^.ParamCount:=MAX_PARAMS;
 for i:=0 to lpInfo^.ParamCount-1 do
 begin
  tempStr:=ParamStr(i+1);
  if length(tempStr)>MAX_PARAM_SIZE then
   setLength(tempStr,MAX_PARAM_SIZE);
  StrCopy(@(lpInfo^.Params[i,0]),PChar(tempStr));
 end;
 // and notify the first instance
 PostMessage(lpInfo^.FirstInstanceWnd, MSG_2ND_INSTANCE, 0, 0);



// And read using:
   if lpInfo <> nil then
   try
    // get Parameters
    params:=TStringList.Create;
    try
     for i:=0 to lpInfo^.ParamCount-1 do
     begin
      SetString(tempStr,
       PChar(@(lpInfo^.Params[i,0])),
       StrLen(@(lpInfo^.Params[i,0])));  <--- E2251 Ambiguious overloaded call to StrLen
      params.Add(tempStr);
     end;
     InstanceStarted(params);
    finally
     params.Free;
    end;

谢谢

默认情况下,@ 地址运算符生成一个无类型指针。 StrLen() 有两个重载版本,一个使用 PAnsiChar,一个使用 PWideChar。无类型指针可以传递给两个重载,因此会产生歧义。 PWideChar 重载在 Delphi 2007 中不存在,这就是之前编译代码的原因。

要修复代码,您必须:

  1. 使用 {$TYPEDADDRESS ON}{$T+} 编译器指令启用 Type-checked pointers 因此使用 [=14= 获取 Char 变量的地址] 运算符将生成类型化 PChar 指针而不是非类型化指针。

    {$TYPEDADDRESS ON}
    SetString(tempStr,
      @(lpInfo^.Params[i,0]),
      StrLen(@(lpInfo^.Params[i,0])));
    
  2. 使用与 SetString() 的第二个参数相同的类型转换:

    SetString(tempStr,
      PChar(@(lpInfo^.Params[i,0])),
      StrLen(PChar(@(lpInfo^.Params[i,0]))));
    
  3. 摆脱对 SetString()StrLen() 的调用,因为可以将空终止字符指针直接分配给 String 变量:

    tempStr := PChar(@(lpInfo^.Params[i,0]));
    

    {$TYPEDADDRESS ON}
    tempStr := @(lpInfo^.Params[i,0]);
    

尽管如此,请注意 Char 数据类型在 D2009 中从 Ansi 更改为 Unicode,因此此代码仅在将参数发送到应用程序的 Unicode 版本时有效,而不是 Ansi 版本.如果您需要继续支持您的应用程序的旧版本,您应该定义一个不同的 window 消息来传递 Unicode 参数,然后让您的 Unicode 应用程序支持两种消息的接收,并分析目标 HWND 以决定使用哪条消息发送。