1

I'm trying to migrate from Delphi 2007 to Embarcadero RAD Studio XE. I'm getting tons of warnings. They all look like this: I have a procedure where I declare a "String":

procedure SendMail( ADestinataire,ASubject : String);

And I'm trying to call Windows API like:

  Res := MAPIResolveName(Session, Application.Handle,
    PAnsiChar(ADestinataire), MAPI_LOGON_UI, 0, PRecip);

So the warnings are:

W1044: Transtyping string into PAnsiChar suspect.

What am I doing wrong / how should I correct this (350 warnings...)?

Thank you very much

Johan
  • 74,508
  • 24
  • 191
  • 319
Olivier Pons
  • 15,363
  • 26
  • 117
  • 213

4 Answers4

8

MAPIResolveName uses LPSTR parameter, which is PAnsiChar in Delphi. Simple MAPI does not support UTF16 strings (though it can be used with UTF8 strings), so if you adhere to simple MAPI you should use AnsiStrings, for example

procedure SendMail( ADestinataire,ASubject : AnsiString);

or better you can use

procedure SendMail( ADestinataire,ASubject : String);

and explicitly convert string parameters to AnsiStrings prior to calling MAPIResolveName


Update The whole Simple MAPI is now deprecated; Simple MAPI can be used with UTF8 strings, but it requires some changes in code and registry.

So if the question is about quick porting old ANSI Simple MAPI to Unicode Delphi, the best is to adhere to AnsiStrings.

A more solid approach is to abandon Simple MAPI completely and use Extended MAPI instead.

kludg
  • 27,213
  • 5
  • 67
  • 118
  • 1
    @Olivier Pons: If it supports UTF8 strings, it would be better to use the UTF8 specialisation of `AnsiString` - which is conveniently named `UTF8String`. That way it's a lossless conversion (Unicode to ANSI is lossy.) – David Jun 03 '11 at 00:04
  • Thank you very much for your nice answer. It wasn't specifically about Simple MAPI (unfortunately I don't have the time to rewrite it), but it was in general, when accessing Windows API and all the stuff around. If I get it right, I may have to convert String parameters to AnsiStrings instead of simple things like PChar(MyStringParam). – Olivier Pons Jun 04 '11 at 13:20
  • @Olivier - No, my answer is not about Windows API in general. Most Windows API functins have unicode (UTF16) variants, and you should follow the first part of Andreas Rejbrand answer while upgrading to Unicode Delphi. Simple MAPI is an exception from the rule - it does not have unicode (UTF16) variant, so you should adhere to ANSI strings. – kludg Jun 04 '11 at 14:48
2

Just write

Res := MAPIResolveName(Session, Application.Handle,
  PChar(ADestinataire), MAPI_LOGON_UI, 0, PRecip);

If you have a string, that is, a Unicode string, that is, a pointer to a sequence of Unicode characters, you shouldn't cast it to PAnsiChar. PAnsiChar is a pointer to a sequence of non-Unicode characters. Indeed, a cast to a PSomethingChar type simply tells the compiler to interpret the thing inside the cast as a pointer of the specified type. It doesn't do any conversion. So, basically, right now you lie to the compiler: You have a Unicode string and instructs the compiler to interpret it as an ANSI (non-Unicode) string. That's bad.

Instead, you should cast it to PWideChar, a pointer to a sequence of Unicode characters. In Delphi 2009+, PChar is equivalent to PWideChar.

Of course, if you send a pointer to a sequence of Unicode characters to the function, then the function had better expect Unicode characters, but I am not sure if this is the case of the MAPIResolveName function. I suspect that it actually requires ANSI (that is, non-Unicode) characters. If this is the case, you need to convert the Unicode string to an ANSI (non-Unicode) string. This is easy, just write AnsiString(ADestinataire). Then you cast to a ANSI (non-Unicode) PAnsiChar:

Res := MAPIResolveName(Session, Application.Handle,
  PANsiChar(AnsiString(ADestinataire)), MAPI_LOGON_UI, 0, PRecip);
Andreas Rejbrand
  • 105,602
  • 8
  • 282
  • 384
1

Starting with Delphi 2009, the string data type is now implemented as a Unicode string. Previous versions implemented the string data type as an Ansi string (i.e. one byte per character).

This had significant implications when we ported our apps from 2007 to XE, and these article were very helpful:

Delphi in a Unicode World (first of three parts)

Delphi and Unicode

Delphi Unicode Migration for Mere Mortals

bvanderw
  • 1,065
  • 2
  • 12
  • 20
0

To step back a moment:

When using    use the cast
============  ================
String        PChar
AnsiString    PAnsiChar
WideString    PWideChar

String used to be an alias for AnsiString, which means it happened to work if you used PAnsiChar (even though you should have used PChar).

Now string is an alias for UnicodeString, which means using PAnsiChar (which was always wrong) is now really wrong.

Knowing this you can solve the question:

ADestinataire: String
PAnsiChar(ADestinataire)
Ian Boyd
  • 246,734
  • 253
  • 869
  • 1,219