C#和本机重叠I / O.

时间:2009-12-30 21:06:10

标签: c# pinvoke overlapped-io

我有一个C dll,我正在包装,以便我可以从C#调用它。一个函数使用事件在状态发生变化时通知您,并且计算出来处理它需要进行一些挖掘。它似乎工作正常,但我很好奇是否有人比我更有经验,可以提供任何建议。

该函数在dll的.h文件中定义为:

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

调用它的示例C代码:

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

这就是我在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();
}

我不清楚的一件事是需要userData。 NotifyStateChange只会触发一个事件,它不会返回任何数据。将null userData传递给Pack()似乎工作正常,但我担心有些东西可能会在我不知道的封面下发生。

如果有更合适的方法,我很感激任何建议。

埃里克

3 个答案:

答案 0 :(得分:4)

您已经阻止事件句柄,不需要使用Overlapped类和回调。您所要做的就是将NativeOverlapped.EventHandle成员设置为DangerousGetHandle()返回值。 DLL将设置事件。

此外,将NotifyStateChange的参数声明为ref而不是指针,使您不必使用unsafe关键字。

答案 1 :(得分:3)

啊是的 - 这正是我向stackoverflow提出难题的原因。现在似乎很明显。这是简化的代码......

    [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();
    }

谢谢!

埃里克

答案 2 :(得分:1)

似乎DLL设计者决定使用OVERLOAPPED结构,无论出于何种原因,他们只需使用简单的HANDLE就可以发出事件信号。显然他们不会查看OVERLAPPED结构中的其他字段,因为DLL似乎没有使用它来使用重叠数据(指针和偏移量)执行任何类型的I / O操作。因此,在不了解所述DLL的情况下,看起来您的使用是正确的,并且您可以传递nil表示数据,0表示偏移量。

但请记住,这只是猜测。如果可能,请联系DLL作者,如果他们忽略指针和偏移的假设是正确的,请询问澄清。

作为旁注,如果你要收到一个回调,我不会阻止等待状态变化的线程。只需使用回调来处理事件(状态改变),系统将更好地扩展。