【问题标题】:Unmanaged code calling vb.net callback非托管代码调用 vb.net 回调
【发布时间】:2009-07-09 19:16:13
【问题描述】:

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

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

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

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

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

问题 1:如何以这种方式将委托与 AddHandler 一起使用? 问题二:Marshal.GetFunctionPointerForDelegate()需要参与吗?它返回一个 IntPtr 但 AddHandler 需要一个委托。

提前致谢。

【问题讨论】:

    标签: vb.net interop delegates


    【解决方案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
    

    【讨论】:

    • 感谢您的回复。我可以这样做,但是我似乎没有创建一个适当的非托管委托,因为我仍然会崩溃。我正在研究一个可能的修复方法:我删除了 WithEvents 关键字以防止 VB 自动“连接”委托。然后,我使用他们的 C++ 文档手动将托管 IntPtr 传递给委托。我让这个版本运行了 2 天没有问题,但我现在禁用了很多代码,所以我不确定我是否已经走出困境。我将连接我需要的其他事件并进行适当的测试。
    【解决方案2】:

    虽然我还不能 100% 确定问题是否已解决,但到目前为止我还没有遇到任何访问违规。

    基本上,我删除了 WithEvents 关键字以防止 VB 使用其自己的 COM -> .net 错误处理,而是使用了用于 C++ 客户端的库中的方法。我使用了&lt;UnmanagedFunctionPointer(CallingConvention.Cdecl)&gt; 并向库传递了Marshal.GetFunctionPointerForDelegate IntPtr。我还保留了对 IntPtr 的引用,尽管它可能有点矫枉过正。

    我很困惑我必须经历这一切,因为 WithEvents 处理程序在 .net 1.1 中完美运行。主要区别在于我使用表单而不是类来处理回调。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-08-24
      • 2011-01-31
      • 1970-01-01
      • 2012-07-03
      • 2015-02-24
      • 1970-01-01
      • 1970-01-01
      • 2010-09-18
      相关资源
      最近更新 更多