将cdecl函数调用从C转换为Pascal,该函数调用使用带变量参数列表的回调



我正在将视频编码器DLL的C头文件转换为Delphi Pascal。

我在以下功能中遇到了一些访问违规问题,需要帮助解决:

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);

注:MC_EXPORT_API=cdecl

get_rc声明如下:

// 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;
}

此函数返回指向另一个具有"变量参数"列表的函数的指针。其中一个声明如下:

void error_printf(const char * fmt, ...)
{
  char lst[256];
  va_list marker;
  va_start(marker,fmt);
  vsprintf(lst,fmt,marker);
  va_end(marker);
  printf("%sn", lst);
}

我已经将函数调用和get_rc翻译成了Delphi Pascal代码:

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;

不幸的是,我不知道如何实现上面显示的C风格方法error_printf。有人能帮我指明正确的方向吗?我也很好奇我是否正确地实现了其他函数,因为当我尝试调用h264OutVideoNew()函数时,会遇到访问冲突。

PS!我没有在这篇文章中包括压缩的记录Th264_v_settings/P_h264_v_settings,因为这很长,并不是真正的问题。

类型为char*的C参数是指向以null结尾的8位字符数组的指针。在Delphi中,等效类型为PAnsiChar。您不能使用string,因为它是一个托管的Delphi类型,在C.中没有等效的类型

此外,错误函数原型具有void返回值。您正在返回一个指针,这是一个错误。

您面临的更大的问题是,您无法容易地实现一个C风格的函数,该函数在Delphi中接收可变数量的参数。您可以声明和调用这样的函数,但不能实现。这意味着这样一个带有可变参数的函数必须是一个外部函数。

现在,您可以编写自己的汇编程序来填充变量参数。然而,这不是我要走的路线。我会用C编写这个函数,然后将其编译成一个.obj文件,该文件可以用$LINK链接到Delphi程序中。

如果你实际上不需要读取变量参数,你可以这样忽略它们:

TErrorMessageHandler = procedure(Name: PAnsiChar); cdecl;

注意,我做了以下更改:

  1. 将类型名称更改为以标准T为前缀
  2. 已更正Name参数的类型
  3. 从函数更改为过程以匹配C声明
  4. 删除了我们无法在Delphi中实现的varargs,因此忽略了额外的参数

然后你导入的函数会是这样的:

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;

然后你可以实现这样的错误回调函数:

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

最新更新