c++ - 对象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 端是fun
如何声明的。_fun
但是,我们可以看到一个错误。回调的调用约定不匹配。C++ 代码将回调定义为__cdecl
. 您需要cdecl
在 Delphi 端使用来匹配,而不是stdcall
.
同样,我希望您的 Delphi 代码对_fun
. 同样应该是cdecl
,但错误消息表明您的声明实际上是register
.
总之,对您的 Delphi 代码进行以下更改:
- 将回调函数类型声明为
cdecl
. - 将实现回调的函数声明为
cdecl
. fun
声明as的导入cdecl
。
查看您的编辑,您对返回值的错误检查LoadLibrary
是错误的。错误由返回值为零表示。将相等与零进行比较以测试是否失败。
调用时您也无法检查错误GetProcAddress
。您需要处理nil
返回的情况。同样,这可能会导致您编写的代码出现运行时错误。
您编辑中的代码表明我所有的猜测都是正确的。解决方案在上面的要点中有详细说明。
推荐阅读
- azure-active-directory - 我可以使用 Graph API 代表来宾用户创建 Microsoft Teams 在线会议吗?
- python-3.x - Selenium 滚动元素,页面内
- magento-1.9 - 更改状态取决于吨子产品 magento 1.9
- python - 如何从 Python 脚本中获取返回类型
- c++ - 比较二进制数输入的字符时,在抛出 'std::out_of_range 的实例后调用终止
- python - django 按列计算行数
- javascript - Dexie 在保存到 indexeddb 时可以尊重 js 类 getter/setter 吗?
- html - 如何修复文本
- mysql - 导入时仅从 MYSQL 转储文件中导入最新更改
- python - 如何在 google colab 中读取 .arff 文件?