0
votes

I have a DLL, written in XE2 that takes a PChar as a parameter (therefore being a unicode string). I was hoping to write an application in Delphi 2006 that calls this DLL. Is this possible, how do I pass in the PChar parameter? If I was doing it in Delphi XE2 I would simply do:

tmpString := 'hello';
DLL_Call(PChar(tmpString));

I have tried defining my tmpString as a WideString in Delphi 2006, but I believe a WideString and an XE2 Unicode string differ considerably?

Is there a way I can pass the string correctly to the DLL? I am in control of the DLL source code so I could obviously change the function definition to PAnsiChar but I'd prefer not to do this, I was hoping for a solution from the Delphi 2006 side if possible.

3
If you're working in a mixed XE/2006 environment avoid mentally fixing on type names that change (such as PChar and Char). Instead in your documentation and APIs that have to work between both places, use the unambiguous terms PAnsiChar and PWideChar, or AnsiChar and WideChar, in your DLL-export/import APIs. Once you do, you'll find your confusion vanishes. This is not a technical point I'm making, it's a semantic "developer-mind" point that really helped me. Secondly, I always use PXxxChar buffers and their lengths, rather than var-string so I don't have to use the borland shared mem dllWarren P

3 Answers

3
votes

You need to declare the function as receiving a PWideChar. And then use WideString to hold the payload.

function DLL_Call(S: PWideChar); stdcall; external 'mylib.dll';

......
var
  tmpString: WideString;
......
tmpString := 'hello';
DLL_Call(PWideChar(tmpString));

Remember that PChar is an alias. In pre-Unicode Delphi it is an alias to PAnsiChar. In Unicode Delphi it is an alias to PWideChar. Pre-Unicode Delphi is perfectly capable of calling any Unicode APIs, but must use PWideChar explicitly.

2
votes

I have tried defining my tmpString as a WideString in Delphi 2006, but I believe a WideString and an XE2 Unicode string differ considerably?

They do. However, they can both be converted from/to a C-style #0-terminated array of WideChar, in other words PWideChar. The only potential problem is that you cannot pass in strings that contain #0 other than as a terminator.

Your objection would be valid if you attempted to call a function accepting a UnicodeString with a WideString argument, but that's not what you're doing. So the solution you already found is the right one.

0
votes

It really depends on how the DLL uses the PWideChar that is passed to it. As long as the DLL does not make any assumptions about how the memory is allocated, it only reads from the memory or writes into the memory, then a WideString will work just fine. Widestring and UnicodeString are managed differently by the RTL, but they both contain UTF-16 encoded payloads, so they are content-compatible with each other. Both also contain a #0 character at the end of their payloads, which is important since the DLL only accepts a PChar pointer, so both string types are treated as null-terminated by the DLL when casted to PChar. To avoid that dependancy, you should update the DLL to accept the string length as a parameter as well, eg:

D2006:

function DLL_Call(S: PWideChar; L: Integer); stdcall; external 'mylib.dll'; 

var 
  tmpString: WideString; 

tmpString := 'hello'; 
DLL_Call(PWideChar(tmpString), Length(tmpString)); 

XE2:

function DLL_Call(S: PChar; L: Integer); stdcall; external 'mylib.dll'; 

var 
  tmpString: String; 

tmpString := 'hello'; 
DLL_Call(PChar(tmpString), Length(tmpString));