views:

12733

answers:

6

I'm converting my applications to Delphi 2009 and faced an intriguing issue with some calls that need to convert a string (wide) to AnsiString.

Here's an example to demonstrate the issue I'm having:

var
  s: PAnsiChar;

...

s := PAnsiChar(Application.ExeName);

With Delphi 2007 and previous versions, s := PChar(Application.ExeName) would return the application exe path.

with Delphi 2009, s := PAnsiChar(Application.ExeName) returns only 'E'.

My guess is that's because I'm converting a unicode string to an ansi string but how can I convert it so that a PAnsiChar gets the full string?

+6  A: 

I have no Delphi 2009 here so I can't check it. But maybe you have to try:

s := PAnsiChar(AnsiString(Application.ExeName));

As gabr already pointed, this is not a very good practice and you will only use it if you are 100% sure, the string only contains characters that have a direct mapping to the ansi range.

That's why you should get a warning because you are converting Unicode to Ansi.

Gamecat
You shouldn't because it is an explicit conversion.And, yes, it should work.
gabr
I know, but the conversion to PAnsiChar is also a bit questionable.
Gamecat
It does work at the cost of the explicit conversion. Is there any other alternative? The conversion to PAnsiChar is explained on my reply below.
smartins
The problem is that you always have the chance of information loss. It is possibly better to change the PAnsiChar for a string.
Gamecat
A: 

Does this help you WideCharToMultiByte ?

Jamie
WideCharToMultiByte is used internally in some casts of Delphi
DR
+1  A: 

Gamecat explicit conversion works. I'm explaining the problem in more detail below so that perhaps someone can point to a better solution.

I'm using the following function to retrieve the application compilation date:

function LinkerTimeStamp(const FileName: string): TDateTime;
var
  LI: TLoadedImage;
begin
  {$IFDEF UNICODE}
  Win32Check(MapAndLoad(PAnsiChar(AnsiString(FileName)), nil, @LI, False, True));
  {$ELSE}
  Win32Check(MapAndLoad(PChar(FileName), nil, @LI, False, True));
  {$ENDIF}
  Result := LI.FileHeader.FileHeader.TimeDateStamp / SecsPerDay + UnixDateDelta;
  UnMapAndLoad(@LI);
end;

MapAndLoad requires a PAnsiChar for the ImageName Parameter so I need to convert the unicode string. Is there any other alternative as to explicitly convert to AnsiString first?

smartins
Is there no Unicode version of MapAndLoad?
Gamecat
No, I don't think there is a Unicode version. CodeGear Imagehlp unit declares MapAndLoad as a LPSTR which maps to PAnsiChar. And no mention on msdn about an Unicode version.
smartins
You should probably add a comment what you changed for Unicode compatibility, and remove the IFDEF altogether - PAnsiChar and AnsiString are available at least in Delphi 4 already, and the typecasts do not hurt in Ansi programs. The simpler the code the better IMHO.
mghie
A: 

I had the exact same problem. The PAnsiChar only points to the first character. I wrote the following function to handle the old functionality.

// This function converts a string to a PAnsiChar
// If the output is not the same, an exception is raised
// Author: [email protected]

function StringToPAnsiChar(stringVar : string) : PAnsiChar;
Var
  AnsString : AnsiString;
  InternalError : Boolean;
begin
  InternalError := false;
  Result := '';
  try
    if stringVar <> '' Then
    begin
       AnsString := AnsiString(StringVar);
       Result := PAnsiChar(PAnsiString(AnsString));
    end;
  Except
    InternalError := true;
  end;
  if InternalError or (String(Result) <> stringVar) then
  begin
    Raise Exception.Create('Conversion from string to PAnsiChar failed!');
  end;
end;

I hope this can help you...

Regards,

Nogabel

A: 

I think You are a bit off. Every Win32 API function has a unicode counterpart, if it is expecting a string. Try MapAndLoadW instead of MapAndLoad...

There's no MapAndLoadW. It was the first thing I looked at. Not all Win32 APIs have unicode counterparts, most do but some like this one do not.
smartins
+1  A: 

instead of using type String, use RawByteString

s: RawByteString;

s = loadsomeregularstring(usually a string type);

PAnsiChar(s) <<< all fine.

Meka