[英]Can I get the device handle for a serial port that I am accessing using the .net SerialPort class?
我正在編寫一個C#.NET應用程序,該應用程序訪問公開串行端口接口的USB設備。 我正在使用方便的.NET SerialPort
類,它可以正常工作。
我的問題是我需要捕獲DBT_DEVICEQUERYREMOVE
事件,但是如果我使用DBT_DEVTYP_DEVICEINTERFACE
注冊,則不會得到該事件。 我確實得到了DBT_DEVICEARRIVAL
和DBT_DEVICEREMOVECOMPLETE
,但是沒有DBT_DEVICEQUERYREMOVE
。
從我的網絡研究看來,我需要使用DBT_DEVTYP_HANDLE
進行注冊,該操作需要一個句柄,例如CreateFile
返回的句柄。 由於SerialPort
類沒有公開此句柄,所以我想知道是否還有其他方法可以獲取該句柄(或某些其他方法來獲取感興趣的事件)。
我認為您可以使用一些反射來獲取句柄,但我不知道一種更好的方法來獲取.NET Framework當前正在使用的句柄。 SerialPort
使用稱為SerialStream
的內部類型。 此流具有所需的句柄。 由於我沒有要測試的串行端口,因此此代碼有些猜測:
var serialPort = new SerialPort();
object stream = typeof(SerialPort).GetField("internalSerialStream", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(serialPort);
var handle = (SafeFileHandle)stream.GetType().GetField("_handle", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(stream);
這將為您提供SafeFileHandle
,它是句柄的包裝。 您可以調用DangerousGetHandle
來獲取實際的IntPtr
。
該句柄僅在您在SerialPort上調用Open
之后才具有有效值,並且在處置后將變為無效。 在使用DangerousGetHandle之前,應首先檢查該IsInvalid
和IsClosed
值。
還有一種解決方案是獲取.Net的Serialport實現,然后根據自己的喜好更改它。
這是我為需要訪問該句柄的項目所做的,並且因為我在SerialPort上存在時序/異步問題。 所以我把它歸結為熊的必需品。
public class SimpleSerialPort : IDisposable
{
private const uint GenericRead = 0x80000000;
private const uint GenericWrite = 0x40000000;
private const int OpenExisting = 3;
private const uint Setdtr = 5; // Set DTR high
private FileStream _fileStream;
public void Close()
{
Dispose();
}
public int WriteTimeout { get; set; }
public SafeFileHandle Handle { get; private set; }
public void Open(string portName, uint baudrate)
{
// Check if port can be found
bool isValid =
SerialPort.GetPortNames()
.Any(x => String.Compare(x, portName, StringComparison.OrdinalIgnoreCase) == 0);
if (!isValid)
{
throw new IOException(string.Format("{0} port was not found", portName));
}
string port = @"\\.\" + portName;
Handle = CreateFile(port, GenericRead | GenericWrite, 0, IntPtr.Zero, OpenExisting, 0, IntPtr.Zero);
if (Handle.IsInvalid)
{
throw new IOException(string.Format("{0} port is already open", portName));
}
var dcb = new Dcb();
// first get the current dcb structure setup
if (GetCommState(Handle, ref dcb) == false)
{
throw new IOException(string.Format("GetCommState error {0}", portName));
}
dcb.BaudRate = baudrate;
dcb.ByteSize = 8;
dcb.Flags = 129;
dcb.XoffChar = 0;
dcb.XonChar = 0;
/* Apply the settings */
if (SetCommState(Handle, ref dcb) == false)
{
throw new IOException(string.Format("SetCommState error {0}", portName));
}
/* Set DTR, some boards needs a DTR = 1 level */
if (EscapeCommFunction(Handle, Setdtr) == false)
{
throw new IOException(string.Format("EscapeCommFunction error {0}", portName));
}
// Write default timeouts
var cto = new Commtimeouts
{
ReadTotalTimeoutConstant = 500,
ReadTotalTimeoutMultiplier = 0,
ReadIntervalTimeout = 10,
WriteTotalTimeoutConstant = WriteTimeout,
WriteTotalTimeoutMultiplier = 0
};
if (SetCommTimeouts(Handle, ref cto) == false)
{
throw new IOException(string.Format("SetCommTimeouts error {0}", portName));
}
// Create filestream
_fileStream = new FileStream(Handle, FileAccess.ReadWrite, 32, false);
}
public void Write(byte[] bytes)
{
_fileStream.Write(bytes, 0, bytes.Length);
}
public void Read(byte[] readArray)
{
for (int read = 0; read < readArray.Length;)
{
read += _fileStream.Read(readArray, read, readArray.Length - read);
}
}
public byte ReadByte()
{
byte[] readsBytes = new byte[1];
Read(readsBytes);
return readsBytes[0];
}
public void Dispose()
{
if (Handle != null)
{
Handle.Dispose();
}
if (_fileStream != null)
{
_fileStream.Dispose();
}
_fileStream = null;
Handle = null;
}
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern SafeFileHandle CreateFile(string lpFileName, uint dwDesiredAccess, int dwShareMode,
IntPtr securityAttrs, int dwCreationDisposition, int dwFlagsAndAttributes, IntPtr hTemplateFile);
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern bool GetCommState(
SafeFileHandle hFile, // handle to communications device
ref Dcb lpDcb // device-control block
);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool SetCommState(
SafeFileHandle hFile, // handle to communications device
ref Dcb lpDcb // device-control block
);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool EscapeCommFunction(
SafeFileHandle hFile, // handle to communications device
uint dwFunc
);
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern bool SetCommTimeouts(
SafeFileHandle hFile, // handle to comm device
ref Commtimeouts lpCommTimeouts // time-out values
);
[StructLayout(LayoutKind.Sequential)]
private struct Commtimeouts
{
public int ReadIntervalTimeout;
public int ReadTotalTimeoutMultiplier;
public int ReadTotalTimeoutConstant;
public int WriteTotalTimeoutMultiplier;
public int WriteTotalTimeoutConstant;
}
[StructLayout(LayoutKind.Sequential)]
private struct Dcb
{
private readonly uint DCBlength;
public uint BaudRate;
public uint Flags;
private readonly ushort WReserved;
private readonly ushort XonLim;
private readonly ushort XoffLim;
public byte ByteSize;
private readonly byte Parity;
private readonly byte StopBits;
public byte XonChar;
public byte XoffChar;
private readonly byte ErrorChar;
private readonly byte EofChar;
private readonly byte EvtChar;
private readonly ushort WReserved1;
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.