哪种 vb6 类型与 std::vector 兼容 BIB

What vb6 type is ABI-compatible with std::vector?

本文关键字:vector BIB 兼容 std vb6 类型 哪种      更新时间:2023-10-16

我一直在用C++编写一个DLL,现在我必须从VB6应用程序调用这个DLL。

下面是此 DLL 中的代码示例:

#include <vector>
#include <string>
using namespace std;    
void __stdcall DLLFunction (vector<Object>*)
{
 // performs a few operations on the Objects contained in the vector.
}
struct Object
{
    long CoordX;
    long CoordY;
    long Width;
    long Height;
    LPSTR Id;
};

我还在 VB6 中定义了"对象结构"

Private Type Object
    CoordX As Integer 
    CoordY As Integer 
    Width As Integer
    Height As Integer
    Id As String 
End Type

问题是我不知道什么 vb6 类型可以代表 std::vector 以调用 DLL 的函数。

笔记:
- 我使用 DLL 的向量来添加对象。
- 我使用指针是为了使用尽可能少的内存。
- 对不起我的英语,它根本不是我的母语。
- 感谢您的阅读并试图帮助我。

编辑:
- 我修复了键入问题(Id 肯定由 NullChar 结束,所以 LPSTR 应该可以解决问题)。- 我读了你们的答案,我要感谢你们俩,你们的答案彼此接近,一个主要问题仍然存在。我的 DLL 肯定需要将元素添加到容器中。因此,我想知道如何做到这一点。也许我可以向我的函数添加一个返回类型,然后使函数能够返回它创建的项目(而不是直接将其放入容器中),以便 vb6 应用程序获取这些项目并能够处理它们,但我无法弄清楚如何做到这一点

编辑之二 :

@Rook :我觉得我可以通过使用新的结构来实现这一点。
struct ObjectArrayPointer

{ 对象* 指针;
size_t计数器;
}

然后这样调用我的函数:

void __stdcall DLLFunction (ObjectArrayPointer*);

然后,我将能够添加对象并编辑 VB6 应用程序的大小参数以查找这些新对象。这是你的意思吗?

无论如何,

您都不应该尝试从 DLL 导出模板容器。当面对较新的编译器和库时,它们可能会中断(例如,在 C++03 下构建的库将无法很好地与使用 C++11 构建的代码配合使用)。

最不痛苦的事情是接受指向缓冲区的指针和长度参数,

void __stdcall DLLFunction (Object* buffer, size_t nObjects);

如果容器的大小在执行过程中不会改变。这个接口非常简单,并且可以通过任何理解 C 调用约定的语言(例如,几乎每一个)轻松访问。

你已经放弃了std::vector的大部分使用,因为你已经把它专门化Object;你可以考虑一路走下去,创建你自己的ObjectCollection类,它在内部使用std::vector,但提供了一个非模板化的接口。这里有一个简单的例子:

// In your public API header file:
typedef struct object_collection_t *object_collection;
object_collection CreateObjectCollection();
void DestroyObjectCollect(object_collection collection);
void AddObjectToCollection(object_collection collection, Object* object);
// etc

页眉中不会以任何形式公开任何模板类型。这很好。

// And the corresponding code file:
struct object_collection_t
{
    std::vector<Object*> objects;
};
object_collection CreateObjectCollection() { return new object_collection_t; }
void DestroyObjectCollect(object_collection collection) { delete collection; }
void AddObjectToCollection(object_collection collection, Object* object)
{
    collection->objects.push_back(object);
}
// etc

所有的模板代码都被隐藏起来,给你留下了一个相当干净和简单的界面,它提供了一个不透明的指针类型,可以通过外部代码传递,但只能由你自己的查询和修改,等等。

编辑:顺便说一下,我在上面的代码中使用了Object*。使用普通的旧Object并避免与客户端代码的内存管理和指针操作相关的所有问题可能更安全,更麻烦。如果Object足够小且简单,则按值传递可能是更好的方法。

(注意:未检查可编译性或功能。E&OE。警告实施者!

你不能

这样做,因为它是一个C++类/模板。在内部,它是一个数组,但不能以可以从 VB6 创建的方式。

最好的办法是更改函数以接受指向具有 count 参数的数组的指针。

您还需要非常小心类型的结构。

  1. C++ int 在 VB6 中是 Long s。
  2. 此外,Id字符串将不兼容。VB6 将有一个指向 unicode BString 的指针(除非您将其固定长度),其中作为C++将具有 std::string,它是一个 ANSI 字符数组。 VB6 可能会封送它,如果你传递一个对象数组(而不是指针)

VB6 ABI 是 COM Automation ABI。

因此,如果您需要与VB6 ABI兼容的arry,则可能应该使用SAFEARRAY。我建议你也应该使用编译器COM支持类:

http://msdn.microsoft.com/en-US/library/5yb2sfxk(v=vs.80).aspx

这个问题似乎完全符合您的要求,使用 ATL 的 CComSafeArray 类:

  • 标准::矢量和_variant_t之间的转换

您可能还想查看以下内容:

  • https://stackoverflow.com/search?q=safearray+_variant_t

安全阵列的替代品

安全阵列的替代方法是提供 COM 集合对象。这只是一个具有 Dispinterface 或双接口的 COM 对象,具有方法 CountItem 。项目应具有 dispid=0 作为默认方法。您可能还希望为_NewEnum提供DISPID_NEWENUM以支持 For Each 语法。