4

I have a Dll function with this signature:

UInt32 Authenticate(uint8 *Key);

I'm doing this on Delphi:

function Authenticate(Key:string) : UInt32; external 'mylib.dll' name 'Authenticate';

But always, the function return 10 (error code) and the application brakes :\

There is a way to do this right?

UPDATE: thanks guys! you're the best!

avra
  • 3,690
  • 19
  • 19
João Mello
  • 153
  • 2
  • 12
  • of course uint8 is not equivalent to a string... what is supposed you have to pass as a key to the function, just a pointer to byte? – jachguate Aug 03 '12 at 01:02
  • @jachguate uint8* is equivalent to PAnsiChar though, in this case – David Heffernan Aug 03 '12 at 07:23
  • @David, equivalent is ambiguous in this case XD. IMHO uint8 is only equivalent to a PByte. the function expecting a PAnsiChar trough a uint8 pointer is not matter of equivalence but of preference in the c side. One that I don't clearly agree with. – jachguate Aug 03 '12 at 14:54

3 Answers3

7

There are some problems with your code.

1) uint8 is the equivilent of Byte in Delphi, not String.

2) the C code is using the compiler's default calling convention, which is usually __cdecl. Delphi's default calling convention, on the other hand, is register instead. They are not compatible with each other. If you mismatch the calling convention, the stack and CPU registers will not be managed correctly during the function call at runtime.

A literal translation of the C code would be this instead:

function Authenticate(Key: PByte) : UInt32; cdecl; external 'mylib.dll';

However, assuming the function is actually expecting a null-terminated string then do this instead:

// the function is expecting a pointer to 8-bit data,
// so DO NOT use `PChar`, which is 16-bit in Delphi 2009+...
function Authenticate(Key: PAnsiChar) : UInt32; cdecl; external 'mylib.dll';

I would stick with the first declaration, as it matches the original C code. Even if the function is expecting a null-terminated string as input, you can still pass it in using PByte via a type-cast:

var
  S: AnsiString;
begin
  Authenticate(PByte(PAnsiChar(S)));
end;

Or, if the function allows NULL input for empty strings:

var
  S: AnsiString;
begin
  Authenticate(PByte(Pointer(S)));
end;
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • Definitely a good start. It's worth noting that Delphi used 8-bit ASCII for versions lower than Delphi 2008, in which case PChar would be preferred. Here's an excellent link on Delphi string handling and compatibility with Windows: http://delphi.about.com/od/beginners/l/aa071800a.htm. – paulsm4 Aug 03 '12 at 02:34
  • 5
    `PAnsiChar` is still preferred over `PChar`, even in pre-2009 versions of Delphi. It makes the code more explicit that it is expecting 8-bit character data, and you don't have to remember to change it from `PChar` to `PAnsiChar` (in order to maintain compatibility with the C code) if the project is upgraded to a 2009+ version of Delphi later on. – Remy Lebeau Aug 03 '12 at 02:49
2

I would add nothing to the great Remy's answer, but I would like to give a list of the tools that can help in conversion of C DLL headers to Pascal (in no special order):

Beware that these converters can only convert 60-80% of the code, so manual work follows.

The biggest time saver tip I can give is to try to find Visual Basic header translation if it exists for your DLL, and use Marco Cantu's VB converter at http://www.marcocantu.com/tools/vb2delphi.htm. This will probably give you almost 100% automatic conversion (if you are converting just DLL headers, of course). There is also a commercial VBTO converter but trial demo is quite enough for conversion of VB DLL headers to Pascal. Download it here: http://www.vbto.net

Other tips for conversion from C--/C++:

Slightly off topic, but I thought this might be useful to someone...

avra
  • 3,690
  • 19
  • 19
0

For starters, change "string" to "pchar".

There might be other problems besides that.

paulsm4
  • 114,292
  • 17
  • 138
  • 190
  • Use `PAnsiChar` instead if using Delphi 2009+. – Remy Lebeau Aug 03 '12 at 01:12
  • `PByteArray` would be more exact variable type. – Jay Aug 03 '12 at 01:37
  • 2
    This isn't an answer. There are many more problems, and `PChar` is wrong anyway, as `PChar` isn't a replacement for `pointer to 8-byte unsigned integer` (neither is `string`, of course). It should at best be a comment to the original question; it's certainly not an answer. – Ken White Aug 03 '12 at 01:42
  • 1
    @Ken - uint8 is 8 bits, not bytes, i.e. Byte. See http://msdn.microsoft.com/en-us/library/cc230388%28v=prot.10%29.aspx – Gerry Coll Aug 03 '12 at 06:10
  • @Gerry: Of course it is. Typo on my part, not reading well enough what I was writing. Thanks for the correction - don't need the link, but I appreciate the effort to provide it. Thanks again. :-) – Ken White Aug 03 '12 at 10:56