Неуправляемый код, вызывающий обратный вызов vb.net - PullRequest
2 голосов
/ 09 июля 2009

Я обновляю приложение vb.net, которое обрабатывает события COM-объекта (возможно, написанного на VB6) с платформы 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"

При наведении указателя мыши на упомянутый обработчик событий он имеет подпись: Делегировать Sub _IServiceMonitorEvents_ServiceConnectionUpEventHandler (ByVal MonitorId как целое число, ByVal UserArg как целое число)

Подписи идентичны, поэтому я не уверен, в чем проблема.

Вопрос 1: Как использовать делегат с AddHandler таким образом? Вопрос 2: Marshal.GetFunctionPointerForDelegate() нужно участвовать? Он возвращает IntPtr, но AddHandler хочет получить делегата.

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

Ответы [ 2 ]

1 голос
/ 12 июля 2009

Попробуйте объявить вашего делегата ожидаемым классом делегата:

   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 голосов
/ 20 июля 2009

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

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

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

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

...