Windows下使用Inpout库直接读写IO设备端口

前言

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

你可能感兴趣的:(IoT,编程,设备I/O读写,inpout,Windows,C#)