如何在 VB6 中使 VB.NET DLL 可调用?

Posted

技术标签:

【中文标题】如何在 VB6 中使 VB.NET DLL 可调用?【英文标题】:How to make a VB.NET DLL callable in VB6? 【发布时间】:2021-12-27 18:56:00 【问题描述】:

我用VB.NET在VS2017中做了一个DLL:

Imports System.Runtime.InteropServices

<ComClass(ComClass1.ClassId, ComClass1.InterfaceId, ComClass1.EventsId)>
Public Class ComClass1

#Region "COM GUIDs"
    ' These  GUIDs provide the COM identity for this class 
    ' and its COM interfaces. If you change them, existing 
    ' clients will no longer be able to access the class.
    Public Const ClassId As String = "c67bcd70-54d0-4498-97be-a5f954790dec"
    Public Const InterfaceId As String = "7ef1a8ce-bcc1-464e-8dc3-fc164bdb7ea3"
    Public Const EventsId As String = "9939eabd-1102-4e34-9735-54664e3536bd"
#End Region

    ' A creatable COM class must have a Public Sub New() 
    ' with no parameters, otherwise, the class will not be 
    ' registered in the COM registry and cannot be created 
    ' via CreateObject.
    Public Sub New()
        MyBase.New()
    End Sub

    Public Xposition As Int32

    Public GoX As Int32

    Public Function MoveX() As Int32
        Dim target As Int32
        target = Convert.ToInt32(Rnd() * 1000)
        Xposition = target
        Return Xposition
    End Function

    Public Function ReadX() As Int32
        Dim target As Int32
        target = Convert.ToInt32(Rnd() * 1000 - GoX)
        Xposition = target
        Return Xposition
    End Function

End Class

我在开发 Widows 10 PC 上以管理员身份编译了 DLL。 我将 DLL 文件复制到运行 VB6 的 Windows XP 目标机器并得到运行时错误 453。

VB6 代码:

Private Declare Function GSCloseServer Lib "GSWDLL32.DLL" () As Long

Private Declare Function MoveX Lib "C:\Temp\VB_Applications\My_DLL_Test\MyNewDLL.dll" () As Integer


Private Sub btnMove_Click()

Call test

End Sub

Private Sub btnStop_Click()

   Dim Running As Integer

  ' Unload MyGraph
   Set Form1 = Nothing
   Running = GSCloseServer()
   
   If Running = 0 Then
     MsgBox "Close Server OK: " & Running, vbOKOnly
   Else
     MsgBox "Close Server Error " & Running, vbOKOnly
   End If

   Unload Me
   
End Sub

Private Sub test()

'txtbxReadBack.Text = ComClass1.Xposition

txtbxReadBack.Text = MoveX

End Sub

我以管理员身份运行 VS2017,因此 DLL 似乎已在开发 PC 上正确注册。

【问题讨论】:

你不需要那个构造函数。我知道文档说它是必需的,但是在 .Net 中,如果您没有为某个类型声明任何构造函数,它将为您生成无参数构造函数。 您在 VB.NET 中构建一个 COM 对象,因此您必须像 VB6 中的 COM 对象一样调用它,而不是像带导出的标准 dll 一样。 如何在VB6中将其称为com对象? 在vb6项目中,从Project-References中选择MyNewDLL接口。然后您可以定义和实例化 COM 对象,例如Dim oMyDLL = New namespace.ComClass1txtbxReadBack.Text = oMyDLL.MoveX,删除函数声明。在测试机器上,您的程序集需要注册(regasm.exe)。可能是在开发机器上编译程序集执行了程序集的注册。 快速说明(现在与您的问题无关),您已将 MoveX 声明为 .Net 端的 Int32 和 VB6 端的 Integer。 VB6 整数是 2 个字节,但 .Net Int32 是 4 个字节。您应该使用 VB6 Long 代替,它也是 4 个字节。 tlb 是通过注册 dll 创建的,包含 COM 接口定义。在 vb6 Project-References 中引用 tlb。 dll 的注册还添加了指向 tlb 和 dll 的注册表项(以及它们的路径);不要在不重新注册的情况下移动 dll。构建 dll 时,(在 VS2019 中)My Project-Compile 下有一个“Register for COM interop”复选框;选中该选项后,VS 在构建期间将注册 dll。但如果你没有引用那台电脑上的 dll(例如来自 vb6),你实际上不需要在那里注册它。 【参考方案1】:

这些是步骤。我将用一个类创建一个非常简单的“COMVisibleHelloWorld”类库

Imports System.Runtime.InteropServices

'Create a manual interface so we can use a fixed and known guid for the COM interface.
<Guid("3BBA8F8E-6B35-48E0-91D4-124DC6FCE7B9"), InterfaceType(ComInterfaceType.InterfaceIsDual)>
Public Interface IHelloWorld
    <DispId(1)> Function SayHello() As String

End Interface

<Guid("BCDCDA5C-DCAF-4C6C-86BA-03908DBEFF4B"), ClassInterface(ClassInterfaceType.None)>
Public Class HelloWorld
    Implements IHelloWorld

    Public Function SayHello() As String Implements IHelloWorld.SayHello
        Return "Hello World"
    End Function

End Class

在 Visual Studio 中选择“使程序集 COM 可见”

在 Visual Studio 中创建强键

构建项目。这将创建一个 tlb 文件。

您现在可以参考这是 VB6

要在 VB6 中使用,只需创建一个实例,然后调用具有 COM 接口的方法

Private Sub Command1_Click()

    Dim hello As New COMVisibleHelloWorld.HelloWorld
    MsgBox (hello.SayHello)

End Sub

结果:

【讨论】:

我按照 COMVisibleHelloWorld 的说明进行操作,但在编译时没有创建 tlb 文件:只有 .dll、.pdb。 AMD .xml。 好的,我在编译选项菜单上找到了“Register for COM interop”复选框并选中它。现在我有了 tlb 文件! 32位XP、VB6目标机产生运行时错误429,ActiveX组件无法创建对象。我引用了 tlb 文件。公共函数“SayHello”出现在自动完成中。我在 64 位和 x86 位配置中构建了 dll。都没有奏效。该dll位于源代码目录中。我也在 System32 中尝试过。 Private Declare Function SayHello Lib "C:\Temp\VB_Applications\My_DLL_Test\COMVisibleHelloWorld.tlb" () As String Private Sub btnMove_Click() Dim hello As New COMVisibleHelloWorld.HelloWorld Dim test As String MsgBox (hello.SayHello) End Sub 我尝试注册dll,提示无法注册文件。我想这可以吗? 要检查 dll 是否已注册,打开命令提示符并运行:“reg query HKLM\SOFTWARE\Classes /s /f COMVisibleHelloWorld.dll”这将搜索注册表并尝试查找 dll

以上是关于如何在 VB6 中使 VB.NET DLL 可调用?的主要内容,如果未能解决你的问题,请参考以下文章

Vista 中的 VB6 .NET 互操作问题

创建 VB.NET COM DLL

VB.net调用DLL,捕捉到AccessVioationException尝试读取或写入受保护的内存。这通常指示其他内存已损坏。

vb6中的RtlMoveMemory ByVal a,在vb.net中应如何表达?

用VB6.0或VB.NET或C#做一个客户端,用来“限制用户只能在办公室访问Web系统”

无法在 VB.NET 中使用带有来自 Visual C++ DLL 的指针参数的函数