【问题标题】:Passing a VB6 boolean variable to an stdcall function in C++ DLL将 VB6 布尔变量传递给 C++ DLL 中的 stdcall 函数
【发布时间】:2015-01-06 03:54:37
【问题描述】:

我正在寻找将 VB6 布尔变量传递给函数(用 C++ 编写,stdcall)的最安全的方法。

C++ 函数将使用此 VB6 变量设置结构的“bool”变量。

我曾尝试在 C++ 中这样声明它:

extern "C" __declspec(dllexport) int SetParameter( BOOL bErrorView) 
{

    DLL_sSettings nSet;
    nSet.bErrorView =(bErrorView != FALSE);

    int ret = stSetParameter(sizeof(DLL_sSettings), nSet);
    return (ret);
}

stSetParameter 声明为

extern "C" int ST_COMDLL_API stSetParameter(int DataLen, DLL_sSettings Settings);

DLL_sSetting 声明为

typedef struct
{
    bool bErrorView;            // true:    Show 
                                // false:   Don't show
    (...)
} DLL_sSettings;

但是,我无法让它工作。

我在 VB6 中使用

调用它
Private Declare Function SetParameter Lib "MyDLL.dll" Alias "_SetParameter@4" (ByVal bErrorView As Boolean) As Long

但它没有按预期工作,我猜 VB6 布尔值在某处丢失或转换不正确。

我目前正在使用 VB6 Boolean、C++ BOOL 和 C++ bool。 我知道这不太好,但我没有看到任何其他方式。

有人发现我的代码有问题吗?

【问题讨论】:

  • 看起来STDCALL函数和VB6使用的是两个不同的函数。也使SetParameter stdcall。
  • @BenVoigt 我的 C++ DLL 通过其属性设置为调用约定 __stdcall (/Gz)。我应该写“extern“C”int SetParameter”吗?你能给我准确的拼写吗?我应该保留“extern C”吗?
  • extern "C" __declspec(dllexport) int __stdcall SetParameter(BOOL bErrorView) 应该没问题。在使用/Gz 时,不需要指定__stdcall,但它不会造成任何伤害,所以我会明确说明。
  • @BenVoigt 啊,是的……我快到了。传递一个 VB6 Boolean True 变量已经给出了正确的结果(虽然在我按照你的建议更改声明之前它实际上并没有做任何事情),但是传递一个 False 不会做任何事情。这就是为什么我想知道 (bErrorView != FALSE);真的是对的。
  • 尝试将 VB6 参数更改为 ByVal Long。如果 VB6 只存储一个字节,而 C++ 读取四个字节,那么即使第一个字节为零,其他字节中的垃圾也会使整体值为!= FALSE

标签: c++ com vb6 stdcall


【解决方案1】:

BOOLint 的类型定义。

它在windef.h中声明如下:

typedef int                 BOOL;

#ifndef FALSE
#define FALSE               0
#endif

#ifndef TRUE
#define TRUE                1
#endif

bool是C++类型,如果用extern "C"声明函数,则不能在函数原型中使用。

所以 VB 应该将 BOOL 视为 Long(32 位整数),而不是 Boolean。 0 表示假,否则(通常为 1)为真。

【讨论】:

  • 结构很好,VB6 没有触及它。唯一关心的是 C++ 和 VB 中的函数签名之间的匹配。
  • 好的,我把最后一行去掉了,基本的答案是在界面中使用int,并检查是否为0。
  • VB6 使用 -1 表示 True,但因为 C++ 代码使用 != FALSE,它应该接受 1-1 以及任何非零值。 VB 应该使用Long(32 位)作为 WinAPI BOOL
  • 它是整数,在 VB 中,条件中只允许布尔值,而 AFAIK,它不允许像 if(1) then... 这样的东西,无论如何应该检查 if (var=0)/(var!=0) 而不是 if (var=false/true)。在 VB 中你是对的。
  • 你真的把 VB6 和 C++ 和最后一条评论混为一谈了
【解决方案2】:

默认情况下,VB6 使用 StdCall 调用约定(如果您使用描述导入的 module 部分而不是使用 Declare Function 创建类型库,则支持 cdecl 约定)。 C++ 支持大量调用约定:stdcall、fastcall、cdecl、thiscall。

需要注意的是,在另一个库中使用 stdcall 调用函数不足以将您的函数更改为 stdcall。您可以使用命令行切换到编译器,但最可靠的方法是在源代码中包含 __stdcall 关键字。它被应用于函数的名称,如下所示:

int __stdcall functionname(int args);

由于您还希望导出这些函数以供 VB6 查找,因此您希望 extern "C" 减少名称修改,并希望 __declspec(dllexport) 将它们放在导出表中。

使用宏一次完成以上所有操作是很常见的。看起来您正在包装的库使用ST_COMDLL_API 执行此操作。在库内部,它将扩展到 __declspec(dllexport) __stdcall。对于消费者,它将改用dllimport

任何时候您定义一个 API 以在不同的编译器(甚至不同的语言)中使用时,最好非常明确地说明调用约定和结构打包 (#pragma pack)。否则,您将受到项目文件和其他头文件中指定的选项的支配。即使您对编译器使用的默认值感到满意,您的公共头文件也应该是明确的,因为最终有人会尝试在同一个程序中使用两个库,而另一个库可能会要求更改编译选项。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-09-04
    • 2015-12-26
    • 2015-08-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多