非托管代码调用vb.net回调

时间:2009-07-09 19:16:14

标签: vb.net interop delegates

我正在升级vb.net应用程序,它处理从框架1.1到WPF 2.0 / 3.5的COM对象(可能用VB6编写)的事件

代码:(为简洁起见,简化了对象名称)

public class MyClass
   Private WithEvents serviceMonitor As COMOBJECT.ServiceMonitor

   Public Sub New()
       serviceMonitor = New COMOBJECT.ServiceMonitor()
       serviceMonitor.Connect([some ip address])
   End Sub

   Private Sub ServiceMonitor_ServiceConnectionUp(ByVal MonitorId As Integer, ByVal UserArg As Integer) _ 
        Handles serviceMonitor.ServiceConnectionUp

        Debug.WriteLine("connection up!")
   End Sub

    ' other similar handlers omitted
End Class

应用程序将按预期获得回调,但是在几秒钟内我就会收到访问冲突。基本的回调代码类似于.net 1.1版本,尽管它运行得很好。

根据我对错误的研究,它是由垃圾收集器移动的东西引起的。由于我没有传递DLL任何操作对象,我猜测回调是问题。其他人通过<UnmanagedFunctionPointer(CallingConvention.Cdecl)>和/或Marshal.GetFunctionPointerForDelegate的委托来解决这个问题。

不幸的是,我发现的所有示例都是DLL具有某种SetCallback(IntPtr)方法的情况。我正在使用WithEvents和Handles关键字。这是我的尝试(注意我删除了Handles关键字,以便我可以使用AddHandler:

<UnmanagedFunctionPointer(CallingConvention.Cdecl)> _
   Delegate Sub ServiceMonitor_ServiceConnectionUpDelegate(ByVal MonitorId As Integer, ByVal UserArg As Integer)

public class MyClass
   Private WithEvents serviceMonitor As COMOBJECT.ServiceMonitor

   Public Sub New()
       serviceMonitor = New COMOBJECT.ServiceMonitor()
       del = New ServiceMonitor_ServiceConnectionUpDelegate(AddressOf ServiceMonitor_ServiceConnectionUp)
       AddHandler serviceMonitor.ServiceConnectionUp, del ' <--- Error here
       serviceMonitor.Connect([some ip address])
   End Sub

   Private Sub ServiceMonitor_ServiceConnectionUp(ByVal MonitorId As Integer, ByVal UserArg As Integer) 

        Debug.WriteLine("connection up!")
    End Sub

    ' other similar handlers omitted
End Class

我在AddHandler行上遇到的错误是:“Value of type MyClass.ServiceMonitor_ServiceConnectionUpDelegate cannot be converted to COMOBJECT._IServiceMonitorEvents_ServiceConnectionUpEventHandler

当我将鼠标悬停在上面提到的事件处理程序时,它有一个签名:     委托Sub _IServiceMonitorEvents_ServiceConnectionUpEventHandler(ByVal MonitorId As Integer,ByVal UserArg As Integer)

签名完全相同,所以我不确定问题是什么。

问题1:如何以这种方式使用AddHandler代理? 问题2:Marshal.GetFunctionPointerForDelegate()是否需要参与?它返回一个IntPtr,但AddHandler想要一个委托。

提前致谢。

2 个答案:

答案 0 :(得分:1)

尝试将您的委托声明为期望的委托类:

   Public Sub New()
       serviceMonitor = New COMOBJECT.ServiceMonitor()
       del = New COMOBJECT._IServiceMonitorEvents_ServiceConnectionUpEventHandler(AddressOf ServiceMonitor_ServiceConnectionUp)
       AddHandler serviceMonitor.ServiceConnectionUp, del
       serviceMonitor.Connect([some ip address])
   End Sub

答案 1 :(得分:0)

虽然我尚未100%确定该问题已得到解决,但到目前为止我还没有违反任何访问权限。

基本上我删除了WithEvents关键字以防止VB使用自己的COM - &gt; .net错误处理,而是使用用于C ++客户端的库中的方法。我使用了<UnmanagedFunctionPointer(CallingConvention.Cdecl)>并将库Marshal.GetFunctionPointerForDelegate IntPtr传递给了库。我也提到了IntPtr,虽然它可能有点矫枉过正。

我很困惑,因为WithEvents处理程序在.net 1.1中完美运行,所以我必须完成所有这些操作。主要区别在于我使用表单来处理回调而不是类。

一个挥之不去的问题是,当我关闭应用程序表单时,调试器有时会保持运行。我希望它只是一个调试器怪癖。