如何将.NET COM dll中的结构或类返回给消耗的VB6应用程序?

时间:2017-06-23 20:20:44

标签: c# .net dll com vb6

这似乎很容易在这里找到,但如果之前有人问过,我就不知道在哪里。

基本上,我是一名.NET开发人员,我不得不使用VB6一分钟,并学习制作COM DLL。我正在使用C#工作,我正在尝试使用该语言创建一个COM DLL,以便将自定义类/结构返回到某些VB6代码,尽管答案here很容易在返回{时使用{来自COM方法的{1}}或string,我无法使用实际对象。

示例代码:

C#

int

VB6

using System;
using System.Runtime.InteropServices;

namespace One.Two.Three
{
    [Guid("<some GUID>"), ClassInterface(ClassInterfaceType.None)]
    public class SomeClass : ISomeClass
    {
        public string Test1 { get; set; } = "Tesuto Ichiban";
        public string Test2 { get; set; } = "Tesuto Niban";

        public SomeClass SomeFunction(ref string str1, ref string str2, ref string str3,
                ref bool someBool, string str4)
        {
            return new SomeClass();
        }
    }

    [Guid("<another GUID>")]
    public interface ISomeClass
    {
        SomeClass SomeFunction(ref string str1, ref string str2, ref string str3, ref bool
                someBool, string str4);
    }

    public class Test
    {
        public string Test1 { get; set; } = "Tesuto Ichiban";
        public string Test2 { get; set; } = "Tesuto Niban";
    }
}

当返回值为 MsgBox ("start") Dim result As Object Dim someObj Set someObj = CreateObject("One.Two.Three.SomeClass") result = CallByName(someObj, "SomeFunction", VbMethod, "1", "2", "3", True, "4") MsgBox (result) 'MsgBox (result.toString()) 'MsgBox (result.Test1) 'MsgBox (result.Test2) MsgBox ("end") string时(以及int被声明为result时),此方法效果很好,此时值可以被传递到String并向用户显示就好了。但是,如果返回 MsgBox SomeClass,那么任何将Test传递给result.[toString()/Test1/Test2]的尝试都会产生消息&#34;开始&#34;和&#34;结束&#34;仍然正在向用户显示,但两者之间根本没有任何显示(甚至不是空白消息)。

值得注意的是,通过返回MsgBox的实例并将Test声明为result,对String的调用将显示&#34; One.Two .Three.Test&#34; - 这表明那里发生了一些事情。

所以......问题是:

还需要做些什么来使VB6应用程序能够公平地访问此对象?

特别是,我需要返回一个数组,MsgBox (result)或某些对象,每个对象都有几个成员。再一次,这似乎是相对容易在Google或SO上找到的东西,但它似乎被其他搜索结果所掩盖。

P.S。 dll的.NET Framework是4.5。 (我在4.0文件夹中使用了RegAsm,而不是链接答案中特别提到的2.0)。如果需要降低到4.0,我可能会,但可能无法将其一直降到2.0。

1 个答案:

答案 0 :(得分:3)

不仅有一种方法可以使这项工作,但这里有一个简单的方法,与您的工作方式相匹配:

C#代码可以非常简单,您不需要明确声明接口,不需要在任何地方使用Dim result As Object Dim someObj Set someObj = CreateObject("One.Two.Three.SomeClass") ' note the "Set" keyword, it's mandatory for COM objects... Set result = CallByName(someObj, "SomeFunction", VbMethod, "hello world") MsgBox result.Text 关键字等,但是您需要在您的类中添加// progid is now optional because we won't need CreateObject anymore [ProgId("One.Two.Three.SomeClass")] [ComVisible(true)] [ClassInterface(ClassInterfaceType.AutoDual)] public class SomeClass1 { public SomeClass2 SomeFunction(string text) { return new SomeClass2 { Text = text }; } } [ComVisible(true)] [ClassInterface(ClassInterfaceType.AutoDual)] public class SomeClass2 { public string Text { get; set; } } 属性(字符串,整数等等是隐含的ComVisible):

ClassInterfaceType.AutoDual

VB / VBA代码:

Dim c1 As New SomeClass1
Set c2 = c1.SomeFunction("hello world")
MsgBox c2.Text

但是,如果你想从VB / VBA获得Intellisense,你也可以声明这样的类:

ClassInterfaceType.AutoDual

我刚刚添加List<T>,现在我可以引用TLB(我使用regasm / tlb创建),并在VB / VBA中使用此代码:

theValue

thValue不推荐&#34;&#34;因为如果你走这条路线,你必须确保COM客户端(这里是VB / VBA)和COM服务器(这里是C#)之间的二进制文件是100%同步的,否则你可能会遇到很难的VB / VBA崩溃。然而,它是一种妥协,智能感知是一种伟大的生产力工具恕我直言。

关于返回thValue的最后一句话,你会遇到麻烦。如果你面对它,请问另一个问题: - )