【问题标题】:What vb6 type is ABI-compatible with std::vector?什么 vb6 类型与 std::vector ABI 兼容?
【发布时间】:2012-06-27 08:21:33
【问题描述】:

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

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

编辑之二:

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

然后这样调用我的函数:

void __stdcall DLLFunction (ObjectArrayPointer*);

然后我可以添加对象并为我的 VB6 应用程序编辑大小参数以找到这些新对象。你是这个意思吗?

【问题讨论】:

  • 您可能会发现 VB6 结构中的 Integer 类型需要为 Long。 Integer 在 VB6 中只有 16 位。

标签: c++ dll vb6 stdvector


【解决方案1】:

无论如何,您都不应该尝试从 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。Caveat Implementor!)

【讨论】:

  • 感谢您的回复,但正如我上面所说,我需要找到一种将元素添加到输入的方法,这就是为什么我要搜索其他输入类型而不是简单数组。
  • 我刚刚编辑了我的问题以确保我理解你的意思。
  • @Illmess:从您的编辑中:是的,您可以只使用一个简单的结构,包括长度,但是您依赖于客户端代码,而不是完全错误。通过以我所做的方式包装std::vector,您无需信任 VB 端即可获得正确的长度。您只需要担心内存释放。您还可以在 DLL 的代码中使用 std::vector 的所有良好功能,这可以使您需要执行的其他任务更轻松、更安全。但是,这取决于您。
【解决方案2】:

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

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

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

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

【讨论】:

  • 更糟糕的是,std::string 是一个字符数组,即 ANSI 字符串,而 BString 是 Unicode。
【解决方案3】:

VB6 ABI 是 COM 自动化 ABI。

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

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

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

您可能还想看看这些:

SAFEARRAY 的替代品

SAFEARRAY 的替代方法是提供一个 COM 集合对象。这只是一个带有 Dispinterface 或 Dual 接口的 COM 对象,方法是 Count 和 Item。项目应该有 dispid=0 作为默认方法。您可能还想提供 _NewEnum 和 DISPID_NEWENUM 以支持 For Each 语法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-25
    • 2021-11-26
    • 1970-01-01
    相关资源
    最近更新 更多