3

I need to wrap some legacy code in Delphi 7 for use within Delphi XE2. My question seems simple, but I tried ALL the examples I could find and they all fail. Basically, I need to be able to pass strings between D7 and DXE2, and as far as I can figure out, the safest approach is to use pchar (since I do not want to ship the borlandmm dll). So DLL written in D7, to be called by Delphi XE2

My interface needs to be

IN My DLL:

function d7zipFile(pFatFile,pThinFile : PChar) : integer; stdCall;
function d7unzipfile(pThinFile,pFatFile : PChar) : integer; stdCall;

I need to pass BACK the pFatFile name in the unzipfile function.

In My calling code:

function d7zipFile(pFatFile,pThinFile : PChar) : integer; external 'd7b64zip.dll';

function d7unzipfile(pThinFile,pFatFile : PChar) : integer; external 'd7b64zip.dll';

Could someone please assist with the best way to implement these?

Obviously I am not looking for the actual zip/unzip code - I have that working fine within D7. I want to know how to declare and work with the string / pchar params, since the various types I tried (PWideChar, WideString, ShortString etc) all give errors.

So I would be happy to simply be able to do a showMessage in the d7zipFile function for both filenames. And then be able to do a showMessage in delphiXE2 on the pFatFile variable, which means the strings went both ways OK?

Jens Mühlenhoff
  • 14,565
  • 6
  • 56
  • 113
Heinz
  • 39
  • 2
  • 6

1 Answers1

7

By far the easiest way to do this is to use WideString. This is the Delphi wrapper around the COM BSTR type. Dynamic allocation of the string payload is done using the shared COM allocator. Since the Delphi RTL manages that, it is transparent to you.

In the Delphi 7 code you declare your functions like this:

function d7zipFile(const FatFile, ThinFile: WideString): integer; stdcall;
function d7unzipfile(const ThinFile: WideString; var FatFile: WideString): 
    integer; stdcall;

In your calling code you declare the functions like this:

function d7zipFile(const FatFile, ThinFile: WideString): integer; stdcall; 
    external 'd7b64zip.dll';
function d7unzipfile(const ThinFile: WideString; var FatFile: WideString): 
    integer; stdcall; external 'd7b64zip.dll';

The alternative to this approach is to use PAnsiChar or PWideChar. Note that you cannot use PChar because that alias refers to different types depending on which version of Delphi you use. In Delphi 7 PChar is an alias for PAnsiChar, and in XE2 it is an alias for PWideChar.

The big downside of using PAnsiChar, say, is that the caller needs to allocate the string which is returned from the DLL. But typically the caller does not know how large that string needs to be. There are a variety of solutions to the problem but the neatest approach is always to use a shared allocator. You state that you do not want to rely on borlandmm.dll and so the next most obvious common allocator is the COM allocator. And that's why WideString is attractive.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • Out of curiosity: Does the WideString approach work with other programming languages? – Jens Mühlenhoff Jul 24 '12 at 08:58
  • 2
    @JensMühlenhoff Mostly yes it does. It's just a COM BSTR. But there is a trap if you try to use a `WideString` as a function return value because Delphi's semantics for return values are not compatible with the ABI used by many other common Windows implementations of languages like C, C++, C# etc. See http://stackoverflow.com/questions/9349530/why-can-a-widestring-not-be-used-as-a-function-return-value-for-interop – David Heffernan Jul 24 '12 at 09:02
  • +1 Since WideString is a good candidate for easy string process, managing the Unicode content even on older Delphi revision. You may emphasize about the `var` parameter description for `FatFile`, which is the main solution about OP's problems: pass *back* a string content. – Arnaud Bouchez Jul 24 '12 at 16:02