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 的任何组合,但我仍然迷路了。 没关系,你也可以把它放在函数参数列表之后。确保没有undef
ing CALLBACK(或将其定义为空的东西)。【参考方案2】:
发现mingw需要给链接器传一个参数(-Wl,--add-stdcall-alias),使用__stdcall终于解决了!
http://www.mingw.org/wiki/Visual_Basic_DLL
【讨论】:
以上是关于DLL 调用约定错误的主要内容,如果未能解决你的问题,请参考以下文章