没有SafeHandle的DllImport导致MissingMethodException

时间:2017-07-12 17:26:42

标签: c# pinvoke

我编写了一个包装类来访问c#for QuickUsb中的非托管lib。对于完整的实现,请参阅此gist

这个问题的主要关注点如下:

public class QuickUsbPort
{
    private class SafeQuickUsbHandle : SafeHandleZeroOrMinusOneIsInvalid
    {
        [DllImport("QuickUsb.dll", CharSet = CharSet.Ansi)] static extern
            int QuickUsbClose(IntPtr handle);

        public SafeQuickUsbHandle(IntPtr handle) : base(true)
        {
            SetHandle(handle);
        }

        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
        protected override bool ReleaseHandle()
        {
            return QuickUsbClose(handle) != 0;
        }
    }

    private static class NativeLib
    {
        [DllImport("QuickUsb.dll", CharSet = CharSet.Ansi)] static extern
            int QuickUsbOpen(out SafeQuickUsbHandle handle, string deviceName);

        public static SafeQuickUsbHandle Open(string deviceName)
        {
            if (QuickUsbOpen(out SafeQuickUsbHandle handle, deviceName) == 0)
            {
                throw new QuickUsbException("Open", new List<Tuple<string, string>>
                {
                    new Tuple<string, string>("deviceName", deviceName),
                });
            }
            return handle;
        }
    }
}

在调用handle这个代码抛出SafeQuickUsbHandle时,Open()作为MissingMethodException编组似乎存在问题。但是,以下修改不会引发此类异常:

        [DllImport("QuickUsb.dll", CharSet = CharSet.Ansi)] static extern
            int QuickUsbOpen(out IntPtr handle, string deviceName);

        public static SafeQuickUsbHandle Open(string deviceName)
        {
            if (QuickUsbOpen(out IntPtr handle, deviceName) == 0)
            {
                throw new QuickUsbException("Open", new List<Tuple<string, string>>
                {
                    new Tuple<string, string>("deviceName", deviceName),
                });
            }
            return new SafeQuickUsbHandle(handle);
        }

所以我想知道我是否遗漏了SafeQuickUsbHandle实现的某些方面,以允许c#正确编组和处理句柄。

请注意,在dll中,handle是指向句柄的指针:

/// <param name="handle">
/// A PQHANDLE that points to a QHANDLE in which to place the new device ID.
/// If successful, hDevice will contain the new QHANDLE</param>

1 个答案:

答案 0 :(得分:3)

您必须为从SafeHandle派生的类提供公共无参数构造函数,尤其是当您使用p / invoke时,如此处所定义:SafeHandle

  

您的SafeHandle子类只需要提供三种方法

     

.ctor() - 初始化SafeHandle的默认构造函数。这个   P / Invoke在将SafeHandle返回给你的时使用它   过程

     

bool IsInvalid {get; } - 确定是否的属性   句柄的当前值是否有效

     

bool ReleaseHandle() -   清理包含的资源

p / invoke无论如何都会神奇地设置值。它也出现在official documentation

  

从SafeHandle继承时,必须覆盖以下内容   成员:IsInvalid和ReleaseHandle。你还应该提供一个   默认构造函数,使用值调用基础构造函数   表示无效的句柄值,以及指示的布尔值   本机句柄是否由SafeHandle拥有,因此   在处理好SafeHandle时应该释放。

由于import numpy as np qts.index = np.round(qts.index, decimals=1) 没有定义公共无参数构造函数,所以必须这样做。