在vb6中使用WithEvents和.Net(VB)dll

时间:2018-03-24 21:02:30

标签: vb.net vb6

我已经研究过,并且阅读了我能找到的所有内容。我很可能已经看到了我的问题的解决方案,但没有认识到它。看来森林对我来说太厚了。

我在vb.net上写了一个dll - VS2010。它在vb.net项目中使用时非常有效。我已启用COM等,以允许它与VB6一起使用。

直到我需要这些事件,它才能按照VB6中的计划运行。但是现在试图让WithEvents部分工作是我完全迷失的地方!

一旦时间比较函数变为真(或相等),我的VB.Net dll就会引发一个事件。它还返回事件的实际时间。

在我的VB6项目中,使用WithEvents函数需要声明在类模块中。我无法理解这将如何/应该如何工作。 正如我之前所说,很多帖子我已经阅读了它必须在类模块中的事实,但没有一个确切地说明如何在一个干净的直接方法中实现这一点。好吧,无论如何,至少对我来说是直截了当的。

以下代码是我在添加事件之前如何使用dll。所有属性和操作等都能正常工作。它位于.bas模块中。

Public PT As New PrecisionTimer.PrecisionTimer

这是如何在表单上使用它的示例:

Private Sub Command3_Click()
Dim aa As Integer

    aa = PT.SetTimerEvent(Val(Text6.Text))
    Select Case aa
        Case -1
            OkToInitiate = True
        Case False
            OkToInitiate = False
    End Select

End Sub

但是现在我需要对dll中的事件作出反应。 这是VB.Net dll中引发事件的行:

RaiseEvent OTE(ActualTriggeredTime.ToString())

所以,有人可以帮助我,我在确定如何实现这一目标时遇到了很多麻烦。

谢谢!

更多信息:
@TnTinMn,对你来说,CM从未成为我的强项。以下是MyClass中的代码:

Option Explicit

Public WithEvents PTM As PrecisionTimer.PrecisionTimer

Private Sub PTM_OTE(ByVal ActualTriggeredTime As Variant)
Dim aa As Integer
   aa = 1
End Sub

现在可以删除PTM_OTE子,并且会自动显示一个新的PTM_OTE子,当然没有aa = 1代码。

在我的Module1.bas中:

Option Explicit
Public PT As New MyClass.PTM
Public OkToInitiate As Boolean

您是否在我的代码中看到错误?

在对象浏览器中,我确实看到了OTE事件。在这一点上,我想我应该能够在左上角的代码编辑器中看到PT,但我没有?!?!

更多信息:
我在VB.Net dll中添加了一个附加函数到事件例程 - 一个TriggeredFlag。

Public Sub OnTimedEvent(source As Object, e As ElapsedEventArgs)
   'Other code including basic error handling       
   RaiseEvent OTE(ActualTriggeredTime.ToString())
   TriggeredFlag = True
End Sub

现在当我在我的vb6项目中使用dll时,我可以监视TriggeredFlag。它确实按预期变化。然而事件似乎没有收到。我相信问题出在VB6代码中 - 类模块中的WithEvents语句(可能)。这是我的整个课程模块:

Option Explicit

Public WithEvents PTM As PrecisionTimer.PrecisionTimer

Public Sub Class_Initialize()
    Set PTM = New PrecisionTimer.PrecisionTimer
End Sub

Private Sub PTM_OTE(ByVal ActualTriggeredTime As String)
Dim aa As Integer
    aa = 1
End Sub

最后的附加信息:

感谢所有帮助解决这个问题的人! 这是我的Module1.Bas最终:

Option Explicit

Public PT As New PrecisionTimer.PrecisionTimer
Public DT As New DTParams

Public OkToInitiate As Boolean

在表格的“常规”部分中:

Option Explicit

Public WithEvents TimerEvents As PrecisionTimer.PrecisionTimer

Form_load例程包括:

Set TimerEvents = PT

这是TimerEvents_OTE例程:

Private Sub TimerEvents_OTE(ByVal ActualTriggeredTime As String)
'Fires when the "Timer Done" event fires

    Call SetTimerText(ActualTriggeredTime)

End Sub

最后,没有使用类模块。

再次感谢所有人!

3 个答案:

答案 0 :(得分:2)

您似乎不愿意分享您的.Net代码。为了给您一个工作示例,请尝试实现以下示例,该示例将详细说明创建公开给COM的工作类库的步骤。我没有安装VB6,但已使用MS Office VBA进行了测试。据我所知,VBA是语言,VB6是该语言的主机。有关详细信息,请参阅:Difference between Visual Basic 6.0 and VBA

第1步:创建COM类库。 以管理员身份启动Visual Studio。这样VS就可以在注册表中注册COM组件。 从"空项目(.Net Framework)创建一个新项目 - Visual Basic"模板。我将该项目命名为#34; Demo COM Exposed Event"。转到项目属性 - 应用程序选项卡并设置"应用程序类型"到"班级图书馆"。您还可以清除"根命名空间"框以强制所有内容都在全局命名空间中,但这不是必需的,因为COM无法识别名称空间。 App Tab

接下来打开Build Configuration Manager,为项目定义并激活X86(32位)配置。

enter image description here

enter image description here

enter image description here

enter image description here

接下来,将项目配置为注册COM类。这是在"编译选项卡"在项目属性中。

enter image description here

下面的VB.Net代码定义了COMDemoClass。此类公开一个事件(Event1),一个方法(SingleFireEvent1)来引发事件,一个布尔属性(AutoFireEvent1)启动/停止一个可以触发的计时器{{ 1}}。

Event1

此时,构建项目以生成Dll和类型库。这些应该可以在Solution Explorer中查看。

Generated Class and Tlb

第2步:在VBA代码中使用库。

在VB IDE中,将项目引用添加到在步骤1中创建的类型库。

Add Proj Ref

添加&#34;类模块&#34;并命名为&#34; ExposeVBNetLib&#34;并将此代码添加到模块中。请注意,您可以向Form或其他类类型模块添加类似的代码;您无法在标准模块中定义Imports System.Runtime.InteropServices Imports System.Timers <ComClass(COMDemoClass.ClassId, COMDemoClass.InterfaceId, COMDemoClass.EventsId)> Public Class COMDemoClass #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 = "db10634a-91fe-4cde-a2da-5421578e6142" Public Const InterfaceId As String = "22d6da07-b40c-4a04-9551-9c375bf99c06" Public Const EventsId As String = "2096fe58-d50c-4d19-9039-a6ad4193385c" #End Region <ComVisible(False)> Delegate Sub _Event1(arg As String) Public Event Event1 As _Event1 Private tmr As New System.Timers.Timer With {.AutoReset = True, .Interval = 500, .Enabled = False} Private _AutoFireEvent1 As Boolean ' 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() AddHandler tmr.Elapsed, AddressOf tmr_Elapsed End Sub Private Sub tmr_Elapsed(sender As Object, e As ElapsedEventArgs) SingleFireEvent1(DateTime.Now.ToLongTimeString()) End Sub Public Sub SingleFireEvent1(Optional arg As String = "Hello") RaiseEvent Event1(arg) End Sub Public Property AutoFireEvent1 As Boolean Get Return _AutoFireEvent1 End Get Set(value As Boolean) If value <> _AutoFireEvent1 Then _AutoFireEvent1 = value tmr.Enabled = value End If End Set End Property End Class 变量。

WithEvents

此类订阅COM类 Option Explicit Private WithEvents vbNetCOMClass As Demo_COM_Exposed_Event.COMDemoClass Private Sub Class_Initialize() Set vbNetCOMClass = New Demo_COM_Exposed_Event.COMDemoClass End Sub Private Sub Class_Terminate() Set vbNetCOMClass = Nothing End Sub To test the VBA class, add the following code to a standard Module. Option Explicit Private instance As ExposeVBNetLib ' a variable to keep the class reference alive between methods Sub CreateAndLaunch() Set instance = New ExposeVBNetLib instance.SingleFireEvent1 "It works" instance.AutoFireEvent1 = True End Sub Sub ShutDown_instance() If Not (instance Is Nothing) Then instance.AutoFireEvent1 = False Set instance = Nothing End If End Sub Private Sub vbNetCOMClass_Event1(ByVal arg As String) Debug.Print arg End Sub Public Property Get AutoFireEvent1() As Boolean AutoFireEvent1 = vbNetCOMClass.AutoFireEvent1 End Property Public Property Let AutoFireEvent1(arg As Boolean) vbNetCOMClass.AutoFireEvent1 = arg End Property Public Sub SingleFireEvent1(arg As String) vbNetCOMClass.SingleFireEvent1 arg End Sub 的{​​{1}}并处理方法Event1中的事件。此方法将接收的参数打印到&#34;立即窗口&#34;。

第3步 - 测试

在标准VBA模块中,放置以下代码:

COMDemoClass

运行方法vbNetCOMClass_Event1以启动代码。运行方法Option Explicit Private instance As ExposeVBNetLib ' a variable to keep the class reference alive between methods Sub CreateAndLaunch() Set instance = New ExposeVBNetLib instance.SingleFireEvent1 "It works" instance.AutoFireEvent1 = True End Sub Sub ShutDown_instance() If Not (instance Is Nothing) Then instance.AutoFireEvent1 = False Set instance = Nothing End If End Sub 以停止代码。

Test Run GIF

最后,您应该能够通过配置项目来启动VBA主机,在Visual Studio中调试.Net代码。就我而言,这是Excel和你的VB6。这是通过&#34; Debug选项卡&#34;在项目属性下,通过设置&#34;启动外部程序&#34;在&#34;开始选项&#34;。

enter image description here

答案 1 :(得分:1)

WithEvents不必在类模块中。它可以在

  • 一个课程模块
  • 用户控件
  • 表格

但它不能在模块中。

您的命令处理程序(Command3_Click)位于表单中。您可以使用相同的格式声明计时器

Public WithEvents TimerEvents As New PrecisionTimer.PrecisionTimer

由于您已在模块中将其命名为PT,因此我会在表单中使用其他名称,例如TimerEvents。

声明此变量后,您可以在编辑器窗口左上角的列表中选择它...

enter image description here

然后在编辑器窗口右上角的列表中选择事件...

enter image description here

此VB6将自动插入事件处理程序,您可以在屏幕截图的底部看到。

在命令处理程序中,必须在新变量

中存储对计时器对象的引用
Set TimerEvents = PT

所以完整的函数看起来像这样

Private Sub Command3_Click()

    Dim aa As Integer

    Set TimerEvents = PT

    aa = PT.SetTimerEvent(Val(Text6.Text))
    Select Case aa
        Case -1
            OkToInitiate = True
        Case False
            OkToInitiate = False
    End Select

End Sub

但是,我猜它有一个更好的地方来初始化TimerEvents变量。

如果要停止处理事件,请将变量设置为Nothing。

Set TimerEvents = Nothing

答案 2 :(得分:-1)

尝试使用WithEvents声明PrecisionTimer:

Public WithEvents PT As New PrecisionTimer.PrecisionTimer

然后为OTE添加一个事件处理程序:

Public Sub PrecisionTimer_OTE(ByVal ActualTriggeredTime As String) Handles PT.OTE
...
End Sub