Converting a cdecl function call from C to Pascal that uses callback with variable argument lists

c, delphi, header-files, pascal

Solution

A C parameter of type `char*` is a pointer to a null-terminated array of 8 bit characters. In Delphi the equivalent type is `PAnsiChar`. You cannot use `string` since that is a managed Delphi type that has no equivalent in C.

In addition, the error function prototype has void return value. You are returning a pointer and that's an error.

The bigger problem that you have is that you cannot readily implement a C style function that receives a variable number of arguments in Delphi. You can declare and call such a function, but you cannot implement one. This means that such a function, with variable arguments, has to be an external function.

Now, you could write your own assembler routine to full off the variable arguments. However, that's not the route I would take. I would write the function in C and then compile it to a .obj file that can be linked into your Delphi program with `$LINK`.

If you don't actually need to read off the variable arguments, you can ignore them like this:

TErrorMessageHandler = procedure(Name: PAnsiChar); cdecl;

Note that I have made the following changes:

- Change the type name to be prefixed with `T` which is standard.

- Corrected the type of the `Name` parameter.

- Changed from function to procedure to match the C declaration.

- Removed the `varargs` which we cannot implement in Delphi and thus ignore the additional parameters.

Then your imported function would look like this:

function h264OutVideoNew(
  get_rc: TErrorMessageHandler;
  settings: Ph264_v_settings;
  options: int32;
  CPU: int32;
  frame0: int32;
  nFrames: int32
): Pointer; cdecl; external 'mc_enc_avc.dll' index 4;

And then you can implement the error callback function like this:

procedure error_printf(Name: PAnsiChar); cdecl;
begin
  // do stuff here
end;

Problem

I am converting a C header file for a video encoder DLL to Delphi Pascal. I've run into some issues with access violations with the following function and need help resolving this: ``` h264venc_tt * MC_EXPORT_API h264OutVideoNew( void * (MC_EXPORT_API * get_rc)(const char* name), const struct h264_v_settings * set, int32_t options, int32_t CPU, int32_t frame0, int32_t nframes); ``` Note: MC_EXPORT_API = cdecl The get_rc is declared as follows: ``` // resource functions dispatcher void * MC_EXPORT_API get_rc(const char* name) { if (!strcmp(name, "err_printf")) return (void*) error_printf; else if (!strcmp(name, "prg_printf")) return (void*) progress_printf; else if (!strcmp(name, "wrn_printf")) return (void*) warn_printf; else if (!strcmp(name, "inf_printf")) return (void*) info_printf; return NULL; } ``` This function returns a pointer to another function that has a Variable Argument list. One of these is declared as this: ``` void error_printf(const char * fmt, ...) { char lst[256]; va_list marker; va_start(marker,fmt); vsprintf(lst,fmt,marker); va_end(marker); printf("%s\n", lst); } ``` I've translated this the function call and the get_rc to this Delphi Pascal code: ``` PErrorMessageHandler = function (const Name: String): Pointer; cdecl varargs; function h264OutVideoNew( get_rc: PErrorMessageHandler; settings: Ph264_v_settings; options: int32; CPU: int32; frame0: int32; nFrames: int32 ): Pointer; cdecl; external 'mc_enc_avc.dll' index 4; ``` Unfortunately, I have no idea how to implement the C-style method error_printf shown above. Can anyone help to point me in the right direction? I am also curious if I have implemented the other functions correctly as I am getting access violations when I try to call the `h264OutVideoNew()` function. PS! I've not included the packed record `Th264_v_settings`/`P_h264_v_settings` in this post as this is very long and not really the problem.

Original source