什么vb6类型与std :: vector兼容ABI?

时间:2012-06-27 08:21:33

标签: c++ dll vb6 stdvector

我一直在用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中定义了“Object struct”

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的向量来添加对象 - 我使用指针以尽可能少地使用内存 - 对不起我的英语,根本不是我的母语。
- 感谢您阅读并试图帮助我。

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

编辑之二:

@Rook:我觉得我可以通过使用新的结构来实现这一目标     struct ObjectArrayPointer
    {
        对象*指针;
        size_t计数器;
    }

然后以这种方式调用我的函数:

void __stdcall DLLFunction (ObjectArrayPointer*);

然后我就可以添加对象并编辑我的VB6应用程序的size参数来查找这些新对象。那是你的意思吗?

3 个答案:

答案 0 :(得分:5)

您不应该尝试从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&amp; OE。警告实施者!)

答案 1 :(得分:1)

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

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

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

  1. C ++ int在VB6中是Long
  2. 此外,Id字符串将不兼容。 VB6将有一个指向unicode BString的指针(除非你使它固定长度),因为C ++将有一个带有ANSI字符数组的std :: string。如果传递对象数组(而不是指针)
  3. ,VB6可以编组

答案 2 :(得分:1)

VB6 ABI是COM Automation ABI。

因此,如果你需要一个兼容VB6 ABI的arry,你应该使用SAFEARRAY。我建议你也应该使用Compiler COM Support类:

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

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

您可能还想看看这些:

SAFEARRAY的替代品

SAFEARRAY的替代方法是提供COM Collection对象。这只是一个带有Dispinterface或Dual接口的COM对象,其方法为CountItem。项应该有dispid = 0作为默认方法。您可能还希望_NewEnum提供DISPID_NEWENUM以支持For Each语法。