首页 > 解决方案 > 对象pascal上的C回调函数崩溃

问题描述

我正在创建一个如下所示的 C dll。

#ifdef TEST_EXPORTS
#define TEST_API __declspec(dllexport)
#else
#define TEST_API __declspec(dllimport)
#endif

#ifdef __cplusplus
extern "C" {
#endif
    /* fun accept an argument status_callback which is a function pointer*/
    TEST_API void fun(void(*status_callback)(int));
#ifdef __cplusplus
}
#endif

和 fun 实现为:

void fun(void(*status_callback)(int)) {
   status_callback(0);
}

当使用下面的 delphi xe 在对象 pascal 上使用这个 dll 时,我在回调函数的地址出现访问冲突而崩溃

type
 TStatusCallBack = procedure( Value: Integer ); stdcall;
 T_fun = procedure(cb : TStatusCallback );

procedure BCallBack( Value: Integer ); stdcall;
begin
   BStatus := value;
end;

begin
 _fun(BCallBack);
end;

实例化代码:

DLLHandle := LoadLibrary( ‘mylib.dll’ );
if (DLLHandle > HDLL_ERROR) then
begin
  _fun := T_fun(GetProcAddress( DLLHandle, 'fun');
end;

问题是什么?既然我是 C 的菜鸟,有什么意见吗??

标签: c++delphi

解决方案


我们缺少重要的细节。我们看不到 C++ 端的实现,也看不到你在 Delphi 端是fun如何声明的。_fun

但是,我们可以看到一个错误。回调的调用约定不匹配。C++ 代码将回调定义为__cdecl. 您需要cdecl在 Delphi 端使用来匹配,而不是stdcall.

同样,我希望您的 Delphi 代码对_fun. 同样应该是cdecl,但错误消息表明您的声明实际上是register.

总之,对您的 Delphi 代码进行以下更改:

  • 将回调函数类型声明为cdecl.
  • 将实现回调的函数声明为cdecl.
  • fun声明as的导入cdecl

查看您的编辑,您对返回值的错误检查LoadLibrary是错误的。错误由返回值为零表示。将相等与零进行比较以测试是否失败。

调用时您也无法检查错误GetProcAddress。您需要处理nil返回的情况。同样,这可能会导致您编写的代码出现运行时错误。

您编辑中的代码表明我所有的猜测都是正确的。解决方案在上面的要点中有详细说明。


推荐阅读