前言
Windows2000以后,随着系统安全性的提高和驱动机制的改变,设备的I/O操作需要ring0权限,在应用的ring3已经很难使用。早期有WinIo库流行过一段时间,最近有个特殊的需求要在Win7/Win2019/Win10下操作I/O,发现WinIo已经不好使,即使后面更新的WinIo3.0也有驱动签名的问题,不容易使用。后来网上找到了开源的Inpout库,有32位和64为版本,仅安装时需要管理员权限,使用时普通权限即可,非常方便。
使用方法
开源库中有C++和C#的使用实例,已经操作Beep的Demo供参考。
使用前需要先以管理员权限执行InstallDriver.exe,执行成功会有提示。
C#编程方法
它的读写是基于16位和32位数据的,C#的调用封装如下:
[DllImport("inpout32.dll")]
private static extern UInt32 IsInpOutDriverOpen();
[DllImport("inpout32.dll")]
private static extern void Out32(short PortAddress, short Data);
[DllImport("inpout32.dll")]
private static extern char Inp32(short PortAddress);
[DllImport("inpout32.dll")]
private static extern void DlPortWritePortUshort(short PortAddress, ushort Data);
[DllImport("inpout32.dll")]
private static extern ushort DlPortReadPortUshort(short PortAddress);
[DllImport("inpout32.dll")]
private static extern void DlPortWritePortUlong(int PortAddress, uint Data);
[DllImport("inpout32.dll")]
private static extern uint DlPortReadPortUlong(int PortAddress);
[DllImport("inpoutx64.dll")]
private static extern bool GetPhysLong(ref int PortAddress, ref uint Data);
[DllImport("inpoutx64.dll")]
private static extern bool SetPhysLong(ref int PortAddress, ref uint Data);
[DllImport("inpoutx64.dll", EntryPoint="IsInpOutDriverOpen")]
private static extern UInt32 IsInpOutDriverOpen_x64();
[DllImport("inpoutx64.dll", EntryPoint = "Out32")]
private static extern void Out32_x64(short PortAddress, short Data);
[DllImport("inpoutx64.dll", EntryPoint = "Inp32")]
private static extern char Inp32_x64(short PortAddress);
[DllImport("inpoutx64.dll", EntryPoint = "DlPortWritePortUshort")]
private static extern void DlPortWritePortUshort_x64(short PortAddress, ushort Data);
[DllImport("inpoutx64.dll", EntryPoint = "DlPortReadPortUshort")]
private static extern ushort DlPortReadPortUshort_x64(short PortAddress);
[DllImport("inpoutx64.dll", EntryPoint = "DlPortWritePortUlong")]
private static extern void DlPortWritePortUlong_x64(int PortAddress, uint Data);
[DllImport("inpoutx64.dll", EntryPoint = "DlPortReadPortUlong")]
private static extern uint DlPortReadPortUlong_x64(int PortAddress);
[DllImport("inpoutx64.dll", EntryPoint = "GetPhysLong")]
private static extern bool GetPhysLong_x64(ref int PortAddress, ref uint Data);
[DllImport("inpoutx64.dll", EntryPoint = "SetPhysLong")]
private static extern bool SetPhysLong_x64(ref int PortAddress, ref uint Data);
使用之前,程序需要先进行初始化,并判断操作系统是32位还是64位,方法如下:
bool m_bX64 = false;
try
{
uint nResult = 0;
try
{
nResult = IsInpOutDriverOpen();
}
catch (BadImageFormatException)
{
nResult = IsInpOutDriverOpen_x64();
if (nResult != 0)
m_bX64 = true;
}
if (nResult == 0)
{
//"Unable to open InpOut32 driver";
}
}
catch (DllNotFoundException ex)
{
System.Diagnostics.Debug.WriteLine(ex.ToString());
//"Unable to find InpOut32.dll";
}
读写Beep的示例如下:
private void Beep(uint freq)
{
if (m_bX64)
{
Out32_x64(0x43, 0xB6);
Out32_x64(0x42, (byte)(freq & 0xFF));
Out32_x64(0x42, (byte)(freq >> 9));
System.Threading.Thread.Sleep(10);
Out32_x64(0x61, (byte)(Convert.ToByte(Inp32_x64(0x61)) | 0x03));
}
else
{
Out32(0x43, 0xB6);
Out32(0x42, (byte)(freq & 0xFF));
Out32(0x42, (byte)(freq >> 9));
System.Threading.Thread.Sleep(10);
Out32(0x61, (byte)(Convert.ToByte(Inp32(0x61)) | 0x03));
}
}
private void StopBeep()
{
if (m_bX64)
Out32_x64(0x61, (byte)(Convert.ToByte(Inp32_x64(0x61)) & 0xFC));
else
Out32(0x61, (byte)(Convert.ToByte(Inp32(0x61)) & 0xFC));
}
private void ThreadBeeper()
{
for (uint i = 440000; i < 500000; i += 1000)
{
uint freq = 1193180000 / i; // 440Hz
Beep(freq);
}
StopBeep();
}
其他:
在使用VS编译时,生成的“目标平台”选“Any CPU”,不要勾选“首选32位(P)”
引用
inpout32库的镜像地址:https://github.com/PascalMing/InpOut32