【问题标题】:C# and native overlapped I/OC# 和本机重叠 I/O
【发布时间】:2009-12-30 21:06:10
【问题描述】:

我有一个要包装的 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() 似乎工作正常,但我担心 userData 可能会在我不知道的情况下发生一些事情。

如果有更合适的方法可以做到这一点,我很感激任何建议。

埃里克

【问题讨论】:

  • 那么 DLL 本身接受一个 OVERLAPPED 结构,并在状态改变时通知它上面的 hEvent?我可以说这是非常不寻常的。它可以简单地接受一个事件句柄并通知它,而不是需要一个为 I/O 设计的结构......
  • 是的,是的,是的,是的。原著不是我写的……

标签: c# pinvoke overlapped-io


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

    啊,是的 - 这正是我向 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();
        }
    

    谢谢!

    埃里克

    【讨论】:

      【解决方案3】:

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

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

      附带说明,如果您无论如何都要获得回调,我不会阻塞等待状态更改的线程。只需使用回调来处理事件(状态变化),系统的伸缩性就会好很多。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-05-24
        • 2013-02-04
        • 2023-03-19
        • 2019-03-06
        • 2010-09-08
        • 2011-12-04
        • 1970-01-01
        相关资源
        最近更新 更多