Background: Porting my code to Delphi 10.1 Berlin and working through the third party libraries. Some are no longer available so I will try to fix the code...
The following code (passing params from one instance of a program to another) raises E2251 Ambiguious overloaded call to StrLen. I understand why, I just don't know the best way to resolve it.
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;
Thanks
By default, the @
address operator produces an untyped pointer. There are two overloaded versions of StrLen()
, one that takes a PAnsiChar
and one that takes a PWideChar
. An untyped pointer can be passed to both overloads, thus the ambiguity. The PWideChar
overload did not exist in Delphi 2007, which is why the code compiled before.
To fix the code, you will have to either:
use the {$TYPEDADDRESS ON}
or {$T+}
compiler directive to enable Type-checked pointers so taking the address of a Char
variable using the @
operator will produce a typed PChar
pointer instead of an untyped pointer.
{$TYPEDADDRESS ON}
SetString(tempStr,
@(lpInfo^.Params[i,0]),
StrLen(@(lpInfo^.Params[i,0])));
use the same type-cast you use in the 2nd parameter of SetString()
:
SetString(tempStr,
PChar(@(lpInfo^.Params[i,0])),
StrLen(PChar(@(lpInfo^.Params[i,0]))));
Get rid of the calls to SetString()
and StrLen()
, since a null-terminated character pointer can be assigned directly to a String
variable:
tempStr := PChar(@(lpInfo^.Params[i,0]));
{$TYPEDADDRESS ON}
tempStr := @(lpInfo^.Params[i,0]);
With that said, do be aware that the Char
data type changed from Ansi to Unicode in D2009, so this code will only work when sending the parameters to Unicode versions of your app, not to Ansi versions. If you need to continue supporting older versions of your app, you should define a different window message for passing Unicode parameters, and then have your Unicode app support both messages for receiving, and analyze the target HWND
to decide which message to use for sending.