我可以将__cdecl导出调用与DLL中的__stdcall导入调用混合使用吗?

时间:2011-08-02 17:18:00

标签: c++ c calling-convention

我正在为第三方应用程序编写模块;应用程序uses __cdecl调用约定。

与此同时,我有一个uses __stdcall调用约定的遗留DLL。

我可以创建一端exports __cdecl功能的包装器,而另一端imports __stdcall功能吗?我还有哪些其他选择?

谢谢,

编辑:

以下是我的帮助澄清我的情况的一些额外信息。

third_party.exe需要skeleton.dll才能访问#ifdef _EXPORTING #define DECLSPEC __declspec(dllexport) #else #define DECLSPEC __declspec(dllimport) #endif #ifdef __cplusplus extern "C" { #endif DECLSPEC int ICD_Create(char* id); ... ... ... 。源代码skeleton.dll包含下面的头文件,并使用__cdecl进行编译。

Application: ThirdParty.exe (out of your control: Uses __cdecl) 
     |
     |
Plugin module: Skeleton.dll (your code)
     |
     |
Legacy DLL: ModifiedVB6.dll (out of your control: Seem to work with __stdcall)

理想情况下,我会使用骨架源代码来开发我的DLL;遗憾的是,将当前的VB6遗留代码移植到C ++中太费时间了。鉴于此,我不得不通过跟随this guideline破解我的VB6代码(这是一个解决方法,但它允许我使用ActiveX DLL作为标准C DLL)。

我对修改后的VB6调用约定没有100%的信心,也不知道如何修改它。练习使用__stdcall,似乎与我开发的测试应用程序一起正常工作。但是,当我使用第三方应用程序测试它时,它会正确调用某些函数,但在其他函数中它会崩溃。

架构如下:

{{1}}

旧版DLL生成dll,lib和def文件;没有头文件。

2 个答案:

答案 0 :(得分:4)

DLL通常会附带一个头文件(.h)和一个处理调用约定,导出函数原型等的相关导入库(.lib)。

只需包含头文件,链接到导入库,您就可以直接调用这些函数。

该头文件将指定函数使用__stdcall调用约定。你肯定不会,也不应该写一个单独的包装DLL。这将增加一个完全无偿的复杂层。


重新阅读您的问题和评论后,我相信您拥有以下架构:

Application (out of your control)
     |
     |
Plugin module (your code)
     |
     |
Legacy DLL (out of your control)

旧版DLL使用__stdcall导出其功能。应用程序使用__cdecl从插件导入函数。

如果该概要正确,那么您当然必须使用__stdcall从旧版DLL导入并使用__cdecl导出到应用程序。由于界面的这些部分不在您的控制范围之内,因此您无法选择。

然而,我发现问题和评论很难遵循。也许我还没有完全理解。请随意添加更多信息,以便在编辑问题时进行澄清。


更新后,我怀疑你的问题都与如何将VB6遗留DLL与C ++ DLL接口有关。由于您没有VB6 DLL的头文件(.h),因此您可能正在编写自己的翻译。

如果我没记错的话,VB6只支持你当前正在使用的__stdcall。因此,您的问题最有可能是由于导出的VB函数错误地转换为C ++原型。

我认为您最好的行动方案是专注于使这些原型翻译正确无误。也许您可以考虑在单独的独立测试项目的上下文中执行此操作,以避免整个应用程序的复杂性。

如果您需要Stack Overflow的进一步帮助,我认为您需要提供VB6函数声明和您尝试过的翻译,但我认为这将成为新问题的主题。

答案 1 :(得分:2)

__declspec(dllexport)只需要告诉编译器从DLL导出标识符。这与您定义(可能)导出的函数的调用约定或您导入的函数的调用约定无关。这应该单独指定,__stdcall很好(但请注意,vararg函数必须是__cdecl,因为调用者必须清理堆栈。)

是的,您可以使用另一个导入它的DLL包装您的DLL并导出具有__cdecl调用约定的函数,但它可能会混淆DLL的用户。我不会这样做,但它是可能的。