Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why might SetString intrinsic cause an "Incompatible types" error on PChar argument?

Please excuse the silly question, but I'm confused. Consider the following method (sorry for noisy comments, this is a real code under development):

function HLanguages.GetISO639LangName(Index: Integer): string;
const
  MaxIso639LangName = 9;  { see msdn.microsoft.com/en-us/library/windows/desktop/dd373848 }
var
  LCData: array[0..MaxIso639LangName-1] of Char;
  Length: Integer;
begin
  { TODO : GetLocaleStr sucks, write proper implementation }
  //Result := GetLocaleStr(LocaleID[Index], LOCALE_SISO639LANGNAME, '??');
  Length := GetLocaleInfo(LocaleID[Index], LOCALE_SISO639LANGNAME, @LCData, System.Length(LCData));
  Win32Check(Length <> 0);
  SetString(Result, @LCData, Length); // "E2008 Incompatible types" here, but why?
end;

If I remove the reference operator then implicit cast from $X+ comes to the rescue and method compiles. Why compiler refuses this code with reference operator is beyond my understanding.

This is Delphi XE2 and this behaviour might be specific to it.


And if I add a test-case dummy with equivalent prototype as intrinsic one within the scope of HLanguages.GetISO639LangName this error will magically go away:

procedure SetString(var s: string; buffer: PChar; len: Integer);
begin
  { test case dummy }
end;
like image 618
OnTheFly Avatar asked Dec 16 '22 16:12

OnTheFly


1 Answers

You have to explicitly convert it to PChar:

SetString(result,PChar(@LCData),Length); 

As you stated, SetString() is very demanding about the 2nd parameter type. It must be either a PChar either a PWideChar either a PAnsiChar, depending on the string type itself.

I suspect this is due to the fact that SetString() is defined as overloaded with either a string, a WideString, or an AnsiString as 1st parameter. So in order to validate the right signature, it needs to have exact match of all parameters types:

SetString(var s: string; buf: PChar; len: integer); overload;
SetString(var s: AnsiString; buf: PAnsiChar; len: integer); overload;
SetString(var s: WideString; buf: PWideChar; len: integer); overload;

Of course, all those are "intrinsics", so you won't find such definition in system.pas, but directly some procedure like _LStrFromPCharLen() _UStrFromPCharLen() _WStrFromPWCharLen() or such.

This behavior is the same since early versions of Delphi, and is not a regression in XE2.

like image 168
Arnaud Bouchez Avatar answered Jun 02 '23 16:06

Arnaud Bouchez