DLL 调用约定错误

Posted

技术标签:

【中文标题】DLL 调用约定错误【英文标题】:Calling convention error with DLL 【发布时间】:2012-01-22 15:36:01 【问题描述】:

我正在使用 MinGW、32 位模式为我有源代码的应用程序 (PCSX) 构建 DLL。我正在遵循另一个模块来源的指南。

产生的错误是:

运行时检查失败 #0 - ESP 的值未在函数调用中正确保存。这通常是用一个调用约定声明的函数和一个用不同调用约定声明的函数指针调用的结果。

PSEgetLibName 调用正常,并返回正确的结果。 PADinit 抛出上述错误。

// sucess, everything configured, and went OK.
#define PSE_PAD_ERR_SUCCESS         0

main.h

long PADinit(long flags);

main.c

long PADinit(long flags) 
    return PSE_PAD_ERR_SUCCESS;

char *PSEgetLibName(void) 
    return _("PSX-U");

生成文件:

# Build for Windows under MinGW
#MINGWDBG= -DDEBUG -O0
MINGWDBG= -DNDEBUG -O2
#MINGWOPT= -W -Wall -mthreads -Wl,--subsystem,console $(MINGWDBG) -DHAVE_STDINT
MINGWOPT= -W -Wall -mthreads -Wl,--subsystem,windows $(MINGWDBG)
mingw:
    windres win32\res.rc win32\res.o
    gcc $(MINGWOPT) mongoose.c main.c -lws2_32 \
        -shared -Wl,--out-implib=$(PROG).lib -o $(PROG).dll
    gcc $(MINGWOPT) mongoose.c main.c win32\res.o -lws2_32 -ladvapi32 \
        -o $(PROG).exe

我尝试使用__stdcall__cdecl 声明函数,因为它似乎对这个错误很重要,但它不会改变结果。

编辑: 代码调用:

plugins.h

typedef long (CALLBACK* PADinit)(long);
...
extern PADinit             PAD1_init;

plugins.c

    ret = PAD1_init(1);

此处的完整源代码(适用于 PCSX): http://pcsxr.codeplex.com/SourceControl/list/changesets

【问题讨论】:

调用该函数的代码是什么? 添加了调用代码,虽然没什么花哨的。完整的源代码也可用。 【参考方案1】:

您应该坚持使用CALLBACK 宏,因为它在插件头文件和您引用的源代码中的其他插件中完成。

它使用 mingw/GCC 4.5 扩展为 __attribute__((__stdcall__))。把它放在头文件和实现文件中。

long CALLBACK PADinit(long flags);
long CALLBACK PADinit(long flags) 
    return PSE_PAD_ERR_SUCCESS;

您应该对所有的回调函数进行这样的注释,无论它们是否正常工作。

【讨论】:

在returntype之前还是之后放置重要吗?我尝试了与 dllexport、stdcall、extern 的任何组合,但我仍然迷路了。 没关系,你也可以把它放在函数参数列表之后。确保没有 undefing CALLBACK(或将其定义为空的东西)。【参考方案2】:

发现mingw需要给链接器传一个参数(-Wl,--add-stdcall-alias),使用__stdcall终于解决了!

http://www.mingw.org/wiki/Visual_Basic_DLL

【讨论】:

以上是关于DLL 调用约定错误的主要内容,如果未能解决你的问题,请参考以下文章

DLL-动态链接库(导入导出符/调用约定)

使用指针调用 C++ DLL 函数

如何检查检查PInvoke签名的调用约定和参数与非托管的目标签名是不是匹配?

Outputpin 中的调用约定冲突

python引用c的dll

C++ DLL 返回从 Python 调用的指针