2009-07-09 3 views
2

Я обновлении vb.net приложение, которое обрабатывает события СОМ-объекта (возможно, написан в VB6) из рамок 1.1 в WPF 2,0/3,5неуправляемый код, вызывающий vb.net обратного вызова

Код: (имена объектов упрощенных для краткости)

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 хочет делегата.

Заранее спасибо.

ответ

0

Хотя я еще не 100% уверен, что проблема решена, до сих пор у меня не было больше никаких нарушений доступа.

В основном я удалил ключевое слово WithEvents, чтобы предотвратить использование VB собственной обработки COM -> .net и вместо этого использовать методы в библиотеке, предназначенной для клиентов C++. Я использовал <UnmanagedFunctionPointer(CallingConvention.Cdecl)> и передал библиотеку Marshal.GetFunctionPointerForDelegate IntPtr. Я также продолжал ссылаться на IntPtr, хотя он, возможно, был излишним.

Я смущен тем, что мне пришлось пройти все это, так как обработчики WithEvents отлично работали в .net 1.1. Основные отличия заключались в том, что я использовал форму для обработки обратных вызовов, а не для класса.

Одна затяжная проблема заключается в том, что отладчик иногда работает, когда я закрываю форму приложения. Я надеюсь, что это просто отладчик.

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 
+0

Спасибо за ответ. Я могу это сделать, однако, похоже, я не создаю должного неуправляемого делегата, потому что у меня все еще возникают сбои. Я работаю над возможным исправлением: я удалил ключевое слово WithEvents, чтобы не допустить, чтобы VB автоматически «подключал» delagates.Затем я использовал их документацию на C++, чтобы вручную передать управляемый IntPtr делегату. Я позволил этой версии работать в течение 2 дней без проблем, но сейчас у меня есть очень много кода, поэтому я не уверен, что я еще из леса. Я подключу другие события, которые мне нужны, и сделаю правильный тест. – wtjones