通过互操作将VB6对象传递给.NET对象?

5

我有一个使用VB6编写的应用程序,通过interop显示一个.NET DLL表单。

我希望.NET DLL中的一个事件可以导致VB6应用程序中的一个表单被显示。

我的想法是让VB6应用程序将一个表单的引用传递给.NET DLL。例如:

[VB6]
Dim objNetDllObject As New NetDllObject
objNetDllObject.PassVb6Form(MyForm)
objNetDllObject.ShowForm

[C#]
object Vb6Form; 
private void PassVb6Form(object form) { Vb6Form = form; }
private void button1_Click(object sender, EventArgs e) { Vb6Form.Show(); }

这个能行吗?

我在别处阅读到,在“进程边界”上发送对象可能会导致问题。这是正确的吗?


1
这不是一个进程边界...它是同一个进程。是的,这很麻烦,但它可以工作。 - Jeff
2个回答

4

有一种方法是在.NET中定义COM接口:

<System.Runtime.InteropServices.GuidAttribute("0896D946-8A8B-4E7D-9D0D-BB29A52B5D08"), _
InterfaceType(ComInterfaceType.InterfaceIsIDispatch)> _
Public Interface IEventHandler
    Sub OnEvent(ByRef sender As Object, ByRef e As Object)
End Interface

在VB6中实现此接口

Implements MyInterop.IEventHandler

Private Sub IEventHandler_OnEvent(ByRef sender As Variant, ByRef e As Variant)
    Dim id
    id = e.Entity.Id
    ' As long as e is COM Visible (not necessarily COM registered, this will work)
End Sub

然后在.NET中拥有一个静态集合的IEventHandlers的注册器:

<ComClass(ComRegistrar.ClassId, ComRegistrar.InterfaceId, ComRegistrar.EventsId>
Public Class ComRegistrar

   Private Shared ReadOnly _eventHandlers As New Dictionary(Of String, List(Of IEventHandler))


   ' This is called by .NET code to fire events to VB6
   Public Shared Sub FireEvent(ByVal eventName As String, ByVal sender As Object, ByVal e As Object)
        For Each eventHandler In _eventHandlers(eventName)
                eventHandler.OnEvent(sender, e)
        Next
   End Sub

   Public Sub RegisterHandler(ByVal eventName As String, ByVal handler As IEventHandler)
        Dim handlers as List(Of IEventHandler)
        If Not _eventHandlers.TryGetValue(eventName, handlers)
             handlers = New List(Of IEventHandler)
             _eventHandlers(eventName) = handlers
        End If
        handlers.Add(handler)
   End Sub

End Class

你的.NET代码会调用FireEvent方法,如果VB6之前调用了RegisterHandler方法,那么你的VB6 IEventHandler将被调用。


我的方法不是更简单吗?我试图避免所有那些事件处理的东西。 - CJ7
是的,更简单,但您需要使用后期绑定来进行回调。 - Jeff
在这种情况下,晚期绑定有哪些风险? - CJ7
1
跟平常一样 :) ... 方法不存在。你没有正确调用它。签名更改...等等。 - Jeff
签名会有什么变化? - CJ7
显示剩余3条评论

0
您还可以使用 ComSourceInterfacesAttribute,这可以使您的代码变得更简单一些(或者至少从 VB6 的角度来看更自然)。 您将拥有类似以下的一些代码:
C# 库:
namespace WindowsFormsControlLibrary1
{
    using System;
    using System.Runtime.InteropServices;
    using System.Windows.Forms;

    [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
    public interface IMyFormEvents
    {
        [DispId(1)]
        void MyEvent();
    }

    public delegate void MyEventEventHandler();

    [ComSourceInterfaces(typeof(IMyFormEvents))]
    public partial class MyForm : Form
    {
        public event MyEventEventHandler MyEvent;

        public MyForm()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            if (this.MyEvent != null)
            {
                this.MyEvent();
            }
        }
    }
}

还有VB6客户端:

Option Explicit

Private WithEvents f As WindowsFormsControlLibrary1.MyForm

Private Sub Command1_Click()
    Set f = New WindowsFormsControlLibrary1.MyForm
    Call f.Show
End Sub

Private Sub f_MyEvent()
    MsgBox "Event was raised from .NET"
    'Open another VB6 form or do whatever is needed
End Sub

如果您将从VB6应用程序中大量使用.NET UI,我强烈建议使用Interop Forms Toolkit来使事情更简单。(它可以帮助生成像这些示例一样的代码,以及处理其他一些常见情况)。


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