没有 SafeHandle 的 DllImport 导致 MissingMethodException
DllImport with out SafeHandle results in MissingMethodException
我写了一个包装器 class 来访问 QuickUsb 的 c# 中的非托管库。有关完整的实施,请参阅此 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>
您必须为派生自 SafeHandle, especially when you it with p/invoke, as defined here: SafeHandle
的 class 提供 public 无参数构造函数
Your subclass of SafeHandle is only required to provide three methods
.ctor() – A default constructor that initializes the SafeHandle. This
method is used by P/Invoke when it returns a SafeHandle to your
process
bool IsInvalid { get; } – a property to determine if the
current value of the handle is valid or not
bool ReleaseHandle() –
clean up the contained resource
p/invoke 无论如何都会神奇地设置值。它也在 official documentation:
When you inherit from SafeHandle, you must override the following
members: IsInvalid and ReleaseHandle. You should also provide a
default constructor that calls the base constructor with a value that
represent an invalid handle value, and a Boolean value indicating
whether the native handle is owned by the SafeHandle and consequently
should be freed when that SafeHandle has been disposed.
由于 SafeHandleZeroOrMinusOneIsInvalid
没有定义 public 无参数构造函数,您必须定义它。
我写了一个包装器 class 来访问 QuickUsb 的 c# 中的非托管库。有关完整的实施,请参阅此 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>
您必须为派生自 SafeHandle, especially when you it with p/invoke, as defined here: SafeHandle
的 class 提供 public 无参数构造函数Your subclass of SafeHandle is only required to provide three methods
.ctor() – A default constructor that initializes the SafeHandle. This method is used by P/Invoke when it returns a SafeHandle to your process
bool IsInvalid { get; } – a property to determine if the current value of the handle is valid or not
bool ReleaseHandle() – clean up the contained resource
p/invoke 无论如何都会神奇地设置值。它也在 official documentation:
When you inherit from SafeHandle, you must override the following members: IsInvalid and ReleaseHandle. You should also provide a default constructor that calls the base constructor with a value that represent an invalid handle value, and a Boolean value indicating whether the native handle is owned by the SafeHandle and consequently should be freed when that SafeHandle has been disposed.
由于 SafeHandleZeroOrMinusOneIsInvalid
没有定义 public 无参数构造函数,您必须定义它。