3

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

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

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

谢谢,

编辑:

这里有一些额外的信息可以帮助我澄清我的情况。

有一个third_party.exe需要访问skeleton.dll. 源代码skeleton.dll包含下面的头文件,使用__cdecl编译。

#ifdef _EXPORTING
  #define DECLSPEC    __declspec(dllexport)
#else
   #define DECLSPEC    __declspec(dllimport)
#endif

#ifdef __cplusplus
   extern "C" {  
#endif

DECLSPEC int ICD_Create(char* id);
...
...
...

理想情况下,我会使用框架源代码来开发我的 DLL;不幸的是,将我当前的 VB6 遗留代码移植到 C++ 中太耗时了。鉴于此,我不得不按照本指南破解我的 VB6 代码(这是一种变通方法,但它允许我使用 ActiveX DLL 作为标准 C DLL)。

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

架构看起来像:

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)

legacy DLL 生成 dll、lib 和 def 文件;没有头文件。

4

2 回答 2

4

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

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

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


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

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

旧版 DLL 使用__stdcall. 应用程序使用__cdecl.

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

但是,我发现问题和评论很难理解。也许我还没有完全理解。随时添加更多信息以在对问题的编辑中进行澄清。


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

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

我认为你最好的做法是专注于让这些原型翻译正确。也许您可以考虑在单独的独立测试项目的上下文中这样做,以避免整个应用程序的复杂性。

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

于 2011-08-02T19:10:21.283 回答
2

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

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

于 2011-08-02T17:31:06.400 回答