Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delphi PChar to C++ const char*

Tags:

c++

dll

delphi

I am trying to use a C++ dll from a native program. I am following the virtual method scenario as explained here

Lets say my C++ function signature is of the form

int Setup(const char* szIp, const char* szPort);

And the corresponding delphi signature is

function Setup(ip, port: PChar):Integer: virtual; cdecl; abstract;

And somewhere from the delphi program i can call

pObj.Setup('192.168.1.100', '97777');

The control comes into the dll, but szIp and szPort formal parameters only receives the first character of the ip and port that I had passed from the delphi program.

I understand that it has to do with null terminating the string properly in delphi. So i had tried the following too.

var
  pzIp, pzPort: PChar;
  szIp, szPort: string; 

begin
   szIp   := '192.168.1.2';
   szPort := '9777';
   //initilize memory for pchar vars
   GetMem(pzIp, Length(szIp)+1);
   GetMem(pzPort, Length(szPort)+1);
   //null terminate the strings
   pzIp[Length(szIp)+1] := #0;
   pzPort[Length(szPort)+1] := #0;
   //copy strings to pchar
   StrPCopy(pzIp, szIp);
   StrPCopy(pzPort, szPort);
end.

This a'int working either. When i Writeln pzIp and pzPort I get strange results.

Forgot to tell, all member functions from the C++ dll are compiled with __stdcall and exported properly

like image 972
rptony Avatar asked Sep 09 '09 10:09

rptony


3 Answers

In Delphi 2010 (and Delphi 2009) the "char" type is actually a WIDEChar - that is, 16 bits wide. So when you call your C++ function, if that is expecting CHAR to be 8 bits wide (so called "ANSI", rather than UNICODE), then it is going to misinterpret the input parameter.

e.g. if you pass the string 'ABC'#0 (I'm showing the null terminator explicitly but this is just an implicit part of a string in Delphi and does not need to be added specifically) this passes a pointer to an 8 byte sequence, NOT 4 bytes!

But because the 3 characters in your string have only 8-bit code-point values (in Unicode terms, this means that what the C++ code "sees" is a string that looks like:

  'A'#0'B'#0'C'#0#0#0

Which would explain why your C++ code seems only to be getting the first character of the string - it is seeing the #0 in the 2nd byte of that first character and assuming that it is the null terminator for the entire string.

You either need to modify your C++ code to correctly receive pointers to WideChar strings, OR modify the function signature in Delphi and convert your strings to ANSIString in the Delphi code before passing those to the C++ function:

Revised function signature:

  function Setup(ip, port: PANSIChar):Integer: virtual; stdcall; abstract;

and the corresponding "Long hand" showing conversion of strings to ANSIString before calling the function - the compiler may take care of this for you but you might find it helpful to make it clear in your code rather than relying on "compiler magic":

  var
    sIPAddress: ANSIString;
    sPort: ANSIString;
  begin   
    sIPAddress := '192.168.1.100';
    sPort      := '97777';

    pObj.Setup(sIPAddress, sPort);

    // etc... 
like image 119
Deltics Avatar answered Nov 14 '22 05:11

Deltics


Is char the same size in both compilers? If you are using D2009/D2010, char is now 16-bits.

like image 45
IanH Avatar answered Nov 14 '22 06:11

IanH


If I understand correctly your function prototype should be stdcall as well.

function Setup(ip, port: PChar):Integer: virtual; stdcall; abstract;

ps. Delphi strings are already null-terminated.

like image 32
utku_karatas Avatar answered Nov 14 '22 05:11

utku_karatas