将一个ISO C++类暴露给VB6应用程序

9
我已经开发了一个C ++类来访问USB上的软件保护加密狗。该C ++类是在Linux下使用g ++开发的,但我可以在Windows下使用MinGW成功编译它。我有一个科学应用程序,它是使用VB6(Visual Basic 6)构建的。
问题是如何将我的C ++类暴露给VB6应用程序?有哪些可能的方法?我需要使用COM吗?(好吧,“无微软”的解决方案更可取:)
非常感谢您的帮助!
更新1。阅读您的评论后,我意识到需要实现C ++类的COM包装器。周围有没有好的最近的例子?我能否使用MinGW(避免MSVC)实现COM包装器?
更新2。最终,我决定为这个问题提供悬赏。以下是我想更好地理解的事情:
1.我意识到需要为我的C ++类实现COM包装器。有人可以为像这样的类提供工作示例吗?
class ValueMapper
{
public:
    ValueMapper( ) { }

    ValueMapper( double fmin, double fmax, int ilength ) {
        SetMapping( fmin, fmax, ilength );
    }

    inline double GetMin() { return min; }
    inline double GetMax() { return max; }
    inline int GetLength() { return length; }

    virtual inline void SetMapping( double fmin, double fmax, int ilength )
    {
        min = fmin;
        max = fmax;
        length = ilength;
    }

    virtual inline int MapValue( double value ) {
        double factor = length / (max - min);
        return (int)RoundTo( (value-min) * factor );
    }

    static double RoundTo( double value, double eps = 1 ) {
        return floor(value/eps + 0.5) * eps;
    }

protected:
    double  min;
    double  max;
    int     length;
};

2. 如何在VB6中使用生成的COM包装器?我需要注册一个COM服务器吗?可以不注册使用吗?

3. 可选。是否可以使用MinGW实现COM包装器?


1
可能存在许多重复:http://stackoverflow.com/search?q=vb6+call+c%2B%2B - fazo
4
用于 Visual Basic 的 DLL 开发注意事项 - Cody Gray
1
你为什么要避免使用COM呢?VB 6已经完全深入到COM开发中。很难想象你试图使用“无Microsoft”解决方案所能实现的目标。如果你想要那样做,你就不会编写VB 6应用程序或在Windows上运行它。 - Cody Gray
@Cody Gray,感谢您提供的链接到笔记!它真的值得一读。嗯,看起来我需要使用COM。是否有最近的COM包装器到ISO C++类的示例? - ezpresso
你不一定要使用COM。还有其他的方法可以做到这一点,但是通过COM来实现实际上更简单。这有点讽刺,因为历史上关于COM并没有什么“简单”的东西,但VB 6就是基于它构建的,一旦你克服了COM开发的最初障碍,它确实大大简化了像这样的互操作场景。我无法给你关于MinGW的任何建议;我不太喜欢它,也从未真正将其用于严肃的Windows开发。 - Cody Gray
关于第二点:vb6 .exe(s)在运行时会默默地注册所有缺失和可访问的(同一目录或其他位置)COM组件。 - Saic Siquot
2个回答

8
为了从Visual Basic中访问COM C++类,您需要在称为IDL的元语言中指定其接口。它将用于生成类型库,该类型库将由Visual Basic读取,并且将实现C ++中的类骨架,例如委托调用到ValueMapper对象。这是通过名为midl.exe的工具完成的。它随Windows Platform SDK或任何VC ++环境一起提供。如果您没有拥有其中之一,则可以免费下载它以及VC ++ 10 Express Edition。
您对象的IDL文件可能如下所示:
import "oaidl.idl"; 
[
 uuid(C6907FD4-9F56-499A-A784-6168AB3352D6),
 version(1.0),
 local,
 oleautomation
]
interface IValueMapper : IDispatch
{
  [id(1), propget] double Min();
  [id(2),propget] double Max();
  [id(3),propget] int Length();
  [id(4)] void SetMapping( [in] double fmin, [in] double fmax, [in] int ilength );
  [id(5)] int MapValue([in] double value);
  [id(6)] double RoundTo( [in] double value,[in,defaultvalue(1)] double eps );
};

[
  uuid(1C110E43-A56F-41A2-8052-EF85FF96082F),
  version(1.0),
  helpstring("Value Mapper Library"),
] library ValueMapperLib
{
  importlib("stdole32.tlb");
  interface IValueMapper;
  [
  uuid(D1A2F830-994E-4495-A9C3-1440155578A9),
  helpstring("Value Mapper Component Class")
  ] 
  coclass ValueMapperClassObject
  {
    [default] interface IValueMapper;
  }; //end coclass def
};

现在,您可以通过从IValueMapper派生一个类并使用ValueMapper成员实现其功能来提供所需的功能。不幸的是,您还需要提供一些样板代码来实现类对象、IUnknown和IDispatch接口以及DLL注册代码。您可以在互联网上找到相关的代码片段,例如:http://www.dcl.hpi.uni-potsdam.de/LV/Components04/VL5/MSDN/DrGUI-on-COM.html http://www.codeproject.com/KB/COM/simplecomserver.aspx
此外,我已经组装了一个VC++ 10完整项目,实现了这个接口,如果您想看一下,请告诉我。

谢谢你的回答!有没有办法从C++类头文件生成IDL文件?我是否总是需要提供.tlb文件才能在VB6项目中使用生成的COM对象DLL? - ezpresso
由于IDL包含比类头文件更多的信息,例如标记输入和输出参数,因此通常无法从标准类头文件中生成它。VB需要.tlb库来了解类接口,但它是由midl编译器自动生成并由VB读取的。因此您不需要担心它。 - jszpilewski
是的,为了方便起见,您可以使用VC++项目中的资源文件(.rc)将.tlb库放置在dll内,并同时注册两者。请查看我发布的第二个链接,其中包含一个示例项目,其中包含一些可重复使用的通用代码。 - jszpilewski
对于编辑IDL,我建议使用任何类似于免费VC ++ 10 Express Edition的Visual C++编辑器,您可以将IDL添加到项目中,并且它将被识别并自动编译。因此,无需手动触及midl.exe。也许VB也会识别它。我知道的一个独立的编辑器是Crimson Editor,但大多数编辑器也应该可以胜任。 - jszpilewski
是的,这就是Visual Basic运行时内部用于调用对象的接口。您可以使用使用默认Windows处理程序的示例中的样板实现。 - jszpilewski
显示剩余5条评论

5

我知道有两种可能的方法:

1)编写COM包装器,直接从VB6访问它。

2)将您的类制作为C接口(通过“展平”),并在普通DLL中公开它。

前一种方法更常见,但听起来您可能更喜欢后者。


谢谢你的回答。我感觉写一个COM封装会更不痛苦一些? - ezpresso
4
这取决于你更加熟悉哪种方式。实际上,如果你正在使用MingW,编写COM组件可能并不容易。 - Nemanja Trifunovic

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接