2009-12-30 3 views
2

J'ai une DLL que j'emballe pour que je puisse l'appeler à partir de C#. Une fonction utilise des événements pour vous avertir quand un état a changé, et la détermination de faire face à cela a pris un peu de creuser. Cela semble fonctionner, mais je suis curieux de savoir si quelqu'un a plus d'expérience dans ce domaine que moi et peut vous conseiller.C# et E/S chevauchées natives

La fonction est définie dans le fichier .h de la dll comme:

int NotifyStateChange(OVERLAPPED *overlapped); 
typedef int (*NOTIFY_STATE_CHANGE_PROC)(OVERLAPPED *); 

Exemple de code C l'appelant:

OVERLAPPED overlapped; 
overlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); 
fns.NotifyStateChange(&overlapped); 
WaitForSingleObject(overlapped.hEvent, INFINITE); 
// ...query for the new state or whatever... 

Voici comment je l'ai approché en C#:

[DllImport("myfuncs.dll")] 
unsafe public static extern int NotifyStateChange(NativeOverlapped* lpOverlapped); 

static private ManualResetEvent m_stateChangeEvent = new ManualResetEvent(false); 

public static DeviceState WaitForStateChange() 
{ 
    unsafe 
    { 
     Overlapped overlapped = new Overlapped(0, 0, 
      m_stateChangeEvent.SafeWaitHandle.DangerousGetHandle(), null); 
     IOCompletionCallback callback = StateChangeCallback; 
     byte[] userData = new byte[100]; 
     NativeOverlapped* nativeOverlapped = overlapped.Pack(callback, userData); 
     NotifyStateChange(nativeOverlapped); 
     m_stateChangeEvent.WaitOne(); 
     Overlapped.Unpack(nativeOverlapped); 
     Overlapped.Free(nativeOverlapped); 
    } 
    return GetCurrentState(); 
} 

[ComVisibleAttribute(true)] 
unsafe static public void StateChangeCallback (
    uint errorCode, 
    uint bytesTransferred, 
    NativeOverlapped* overlapped) 
{ 
    m_stateChangeEvent.Set(); 
} 

Une chose que je ne comprends pas, c'est le besoin de userData. NotifyStateChange ne déclenche qu'un événement, il ne renvoie aucune donnée. Le passage d'une valeur null UserData à Pack() semble fonctionner correctement, mais je crains que quelque chose ne se passe avec UserData sous les couvertures dont je ne suis pas conscient.

J'apprécie n'importe quel conseil sur s'il y a une manière plus appropriée de faire ceci.

Eric

+0

la DLL elle-même accepte donc une structure et CHEVAUCHEMENT informera le hEvent sur elle en cas de changement d'état? Puis-je dire que c'est très inhabituel. Il pourrait simplement accepter un handle d'événement et le notifier, plutôt que d'exiger une structure conçue pour les E/S ... –

+0

Oui, oui, oui et oui. Je n'ai pas écrit l'original ... –

Répondre

4

Vous bloquez déjà sur le handle d'événement, il n'est pas nécessaire d'utiliser la classe Overlapped et le rappel. Tout ce que vous avez à faire est de définir le membre NativeOverlapped.EventHandle à la valeur de retour DangerousGetHandle(). La DLL va définir l'événement. De même, déclarez l'argument pour NotifyStateChange comme ref au lieu d'un pointeur, vous évite d'avoir à utiliser le mot-clé unsafe.

1

Il semble que les concepteurs de DLL ont décidé d'utiliser, pour une raison quelconque, la structure OVERLOAPPED quand ils ne pouvaient tout simplement dû utiliser une simple poignée pour un événement à signaler. Apparemment, ils ne doivent pas regarder les autres champs de la structure OVERLAPPED, car la DLL ne semble pas l'utiliser pour effectuer une opération d'E/S quelconque en utilisant les données qui se chevauchent (le pointeur et les décalages). Donc, sans en savoir beaucoup sur cette DLL, il semblerait que votre utilisation est correcte, et vous pouvez passer nil pour les données et 0 pour les offsets.

Mais gardez à l'esprit que c'est juste une supposition. Si possible, contactez le (s) auteur (s) DLL et demandez des éclaircissements si l'hypothèse qu'ils ignorent le pointeur et les décalages est correcte.

En guise de remarque, je ne bloquerais pas un thread qui attend des changements d'état si vous voulez quand même recevoir un callback. Il suffit d'utiliser le rappel pour traiter l'événement (changement d'état), le système évoluera beaucoup mieux.

2

Ah oui - c'est exactement pourquoi je demande à stackoverflow les questions difficiles. Cela semble évident maintenant. Voici le code beaucoup plus simple ...

[DllImport("myfuncs.dll")] 
    public static extern int NotifyStateChange(ref NativeOverlapped lpOverlapped); 

    public static DeviceState WaitForStateChange() 
    { 
     ManualResetEvent stateChangeEvent = new ManualResetEvent(false); 
     NativeOverlapped nativeOverlapped = new NativeOverlapped(); 
     nativeOverlapped.EventHandle = 
      stateChangeEvent.SafeWaitHandle.DangerousGetHandle(); 
     NotifyStateChange(ref nativeOverlapped); 
     stateChangeEvent.WaitOne(); 

     return GetCurrentState(); 
    } 

merci!

Eric

Questions connexes