Неуправляемая c ++ DLL в C # ... WINAPI и указатели - PullRequest
3 голосов
/ 06 сентября 2011

Меня попросили интегрировать веб-камеру ZoneTrigger в мой проект. SDK, представленный на сайте, - это C ++, также образец. Мне удалось получить несколько функций для работы. место, где я застрял, - это функция, где выполняется обратный вызов. Код в образце c ++ функции обратного вызова

ZT_SetCallbackProc(ZoneTriggerCallbackProc);

// в заголовочном файле

typedef int (WINAPI *f_ZT_SetCallbackProc) (void *proc);
/*
Sets up the callback function for your application.
The proc should be declared like this:

int WINAPI ZoneTriggerCallbackProc(int MessageType, ZT_TRIG_STRUCT *trigInfo);

MessageType may be one of the following:
0:  Zone Trigger sends a trig. The trigInfo contains data about the hot spots that generated the trig.
1:  Zone Trigger has started and is notifying us that it is ready. This only occurs when Zone Trigger starts after the interface DLL is loaded.
2:  Zone Trigger is shutting down. You application may need to know this. If Zone Trigger is started again, your application will get message 1.
3:  Zone Trigger's Hot spot scheme has changed (a Hot Spot was added or deleted)
*/

мой код C #:

[DllImport("ZTcom.dll")]
    private static extern IntPtr ZT_SetCallbackProc(int ZoneTriggerCallbackProc);

 private unsafe int ZoneTriggerCallbackProc(int MessageType, ref ZT_TRIG_STRUCT trigInfo)
    {
        switch (MessageType)
        {

            case 0:     //Trig from a Zone Trigger hot spot
                // string s1 = new string(trigInfo.SpotName);
                MessageBox.Show("Got a trig from spot" + trigInfo.SpotIndex.ToString()+ s1 );
                break;

            case 1:     //Zone Trigger has started and is notifying us that it is ready
                MessageBox.Show("Zone Trigger issued a ready notification.\r\n");
                break;

            case 2:     //Zone Trigger is shutting down
                MessageBox.Show("Zone Trigger has left the building.\r\n");
                break;

            case 3:     //Hot spot scheme updated, you might want yo re-enumerate the hot spots
                MessageBox.Show("Zone Trigger's hot spots have been updated.\r\n");
                break;


        }
        return 0;
    }

Я дошел до этого ... но я не понимаю, как вызвать функцию ZT_SetCallbackProc?

 IntPtr tg = IntPtr.Zero;
            tg = ZT_SetCallbackProc(ZoneTriggerCallbackProc);

это дает ошибку, что ZoneTriggerCallbackProc является группой методов. Пожалуйста, помогите ... заранее.

Ответы [ 3 ]

4 голосов
/ 06 сентября 2011

Даниэль ответ имеет простой и быстрый маршрут. Если вы не хотите сталкиваться с проблемами (так как делегат может быть собран GC, что приведет к исключению AccessViolationException), вам нужно будет сделать следующее.

Декларации типа / pinvoke от Даниэля (для полноты):

// int WINAPI ZoneTriggerCallbackProc(int MessageType, ZT_TRIG_STRUCT *trigInfo);  
delegate int ZoneTriggerCallbackProc(int messageType, ref ZT_TRIG_STRUCT trigInfo); 
[DllImport("ZTcom.dll")]   
private static extern IntPtr ZT_SetCallbackProc(ZoneTriggerCallbackProc callbackProc);  

В вашем классе-оболочке храните ссылку на делегат, чтобы GC не собирал делегат, пока установлен обратный вызов.

public class ZoneTrigger : CriticalFinalizerObject
{
  private ZoneTriggerCallbackProc _zoneTriggerCallback;
  private IntPtr _zoneTriggerCallbackCookie;

  public ZoneTrigger()
  {
    _zoneTriggerCallback = ZoneTriggerCallback;
    // Why not just do it here?
    _zoneTriggerCallbackCookie = NativeMethods.ZT_SetCallbackProc(_zoneTriggerCallback);
    if (_zoneTriggerCallbackCookie == IntPtr.Zero)
       throw new Exception("Failed to set callback");
  }

   private unsafe int ZoneTriggerCallback(int MessageType, ref ZT_TRIG_STRUCT trigInfo)
   {
     // ...
   }

  ~ZoneTrigger()
  {
     var oldCookie = Interlocked.Exchange(ref _zoneTriggerCallback, IntPtr.Zero);
     if (oldCookie != IntPtr.Zero)
       ZT_ClearCallbackProc(oldCookie);
  }
}

NB: Пожалуйста, примите ответ Даниила, это скорее дополнение к нему.

2 голосов
/ 06 сентября 2011

Функция обратного вызова - это метод.Поэтому вам нужно передать ему метод.В C # вы получите это, определив делегата:

// int WINAPI ZoneTriggerCallbackProc(int MessageType, ZT_TRIG_STRUCT *trigInfo); 
delegate int ZoneTriggerCallbackProc(int messageType, ref ZT_TRIG_STRUCT trigInfo);

[DllImport("ZTcom.dll")] 
private static extern IntPtr ZT_SetCallbackProc(ZoneTriggerCallbackProc callbackProc);
0 голосов
/ 06 сентября 2011

Вызовите функцию следующим образом ....

 ZT_TRIG_STRUCT triginfo = new ZT_TRIG_STRUCT();
 IntPtr tg = IntPtr.Zero;
        tg = ZT_SetCallbackProc(ZoneTriggerCallbackProc(0,triginfo));
...