views:

553

answers:

3

Hi all.

I have a function in C++ that I call with its memory address with typedef, and I want to do the same thing in Delphi.

typedef void (*function_t)(char *format, ...);

function_t Function;

Function = (function_t)0x00477123;

And then, I call it with: Function("string", etc);

I tried to do this in Delphi, but got no results.

Is there any way to do this without using "asm" in Delphi?

If so, please give me a example code.

Thanks.

+1  A: 

Yes, Delphi supports function pointers. Declare it like this:

type MyProcType = procedure(value: string);

Then declare a variable of type MyProcType and assign the address of your procedure to it, and you can call it the same way you would in C.

If you want a pointer to a method of an object instead of a standalone procedure or function, add "of object" to the end of the function pointer declaration.

Mason Wheeler
Thank you all, it worked.But, there's a bug:The function I'm trying to call, is similar to "printf".In C++, when I call my function, with the string parameter as "string", it prints "string" in the console, but with Delphi, it prints "xÿ↕", I tried to change String to PChar, and so on, but no one worked. What can I do to print "string" correctly?
Flávio Toribio
@Edward - apart from using the right parameter type you may also need to specify a calling convention. If you don't specify anything, Delphi will assume you want to use the "register" fastcall convention.
PhiS
Try with PAnsiChar and check calling conversions.
pani
PhiS, thank you to explain me of calling conventions. When a tried all calling conventions, none worked, but then, I saw pani's comment, and it worked perfectly, so thank you too pani!
Flávio Toribio
+2  A: 
program Project1;

type
  TFoo = procedure(S: String);

var
  F: TFoo;
begin
  F := TFoo($00477123);
  F('string');
end.

Of course, if you just run the above you'll get a runtime error 216 at address $00477123.

Frank Shearar
This doesn't address calling convention or the variable number of arguments, so won't work correctly for his example.
David M
David you're quite right. I wanted to illustrate function pointers, and hadn't noticed the varargs bit.
Frank Shearar
+16  A: 

An idiomatic translation for this:

typedef void (*function_t)(char *format, ...);
function_t Function;
Function = (function_t)0x00477123;

Is this:

type
  TFunction = procedure(Format: PAnsiChar) cdecl varargs;
var
  Function: TFunction;
// ...
  Function := TFunction($00477123);

The 'cdecl varargs' is required to get the C calling convention (where the caller pops the stack) and the variadic argument support (which is only supported with the C calling convention). Varargs is only supported as a means for calling C; there is no built-in support in Delphi for implementing variadic parameter lists in the C style. Instead, there is a different mechanism, used by the Format procedure and friends:

function Format(const Fmt: string; const Args: array of const): string;

But you can find out more about that elsewhere.

Barry Kelly
Oh, good point! I missed the ... in there.
Mason Wheeler
Too bad one can only up-vote once!
François
+1 for posting the real solution (getting the parameter types, cdecl and varargs right is more important than some people think).
Jeroen Pluimers