驅動程序安裝類(C#)

回憶剛進公司那會兒,手頭的第一個工作就是完成虛擬鍵盤,也就是通過驅動程序向鍵盤端口寫入數據,

這份活至今記憶猶新,那會兒寫的是個過濾驅動程序,也就是將我的虛擬設備綁定到真實的鍵盤設備上,

當驅動程序編譯完成以後,我也總是通過下面的這個工具來安裝驅動程序,

image

每編譯好一次就使用這個工具重新安裝驅動一次,然後通過 DbgView 來打印消息,

那會兒還真傻,爲了弄出這麼個虛擬鍵盤,都不曉得安裝了驅動多少回,

直到後來,當驅動程序完成以後,就需要部署驅動程序了,在網上找了很多資料,

大部分也都是通過 INF 文件來實現,而對於 WDM 驅動程序,則還可以通過服務控制檯來實現安裝,

模模糊糊還記得當初就是通過這個服務控制檯來實現驅動程序服務的安裝的。

          

當初的實現是這樣的,通過編寫一個 DLL 來調用服務控制檯 API 從而完成驅動程序的安裝,

然後再在 C# (應用程序是使用的 C# WinForm ,驅動程序必須和這個應用程序通信)中通過平臺調用,

訪問這個 DLL ,這樣就可以實現驅動程序的動態加載以及動態啓動服務和停止服務等等操作了。

而在下面呢,我也算是對以前寫的那個 DLL 做一個總結,將其總結爲一個 C# 類,這樣以後用起來會更加方便。

整個的類,我按分層的思想將其分爲三塊(其實這裏將其這樣劃分不是非常合適):

image

               

DriverEntity.cs

這裏即是所謂的實體層,在該類下面呢,主要包括的是將要在 DriverBLL 中使用到的一些常量數據,

這些數據呢包括服務的類型,服務啓動類型,當然也包括了將會使用到的一些結構類型等等信息。

              

using System;
using System.Runtime.InteropServices;
 
namespace TaskManager.Entity
{
    public class DriverEntity
    {
        // Service Types (Bit Mask)
        public static readonly UInt32 SERVICE_KERNEL_DRIVER          = 0x00000001;
        public static readonly UInt32 SERVICE_FILE_SYSTEM_DRIVER     = 0x00000002;
        public static readonly UInt32 SERVICE_ADAPTER                = 0x00000004;
        public static readonly UInt32 SERVICE_RECOGNIZER_DRIVER      = 0x00000008;
        public static readonly UInt32 SERVICE_WIN32_OWN_PROCESS      = 0x00000010;
        public static readonly UInt32 SERVICE_WIN32_SHARE_PROCESS    = 0x00000020;
        public static readonly UInt32 SERVICE_INTERACTIVE_PROCESS    = 0x00000100;
        public static readonly UInt32 SERVICE_WIN32                  = 
            SERVICE_WIN32_OWN_PROCESS | SERVICE_WIN32_SHARE_PROCESS;
 
        public static readonly UInt32 SERVICE_DRIVER                 = 
            SERVICE_KERNEL_DRIVER | SERVICE_FILE_SYSTEM_DRIVER | SERVICE_RECOGNIZER_DRIVER;
 
        public static readonly UInt32 SERVICE_TYPE_ALL               = 
            SERVICE_WIN32 | SERVICE_ADAPTER | SERVICE_DRIVER | SERVICE_INTERACTIVE_PROCESS;
 
        // Start Type
        public static readonly UInt32 SERVICE_BOOT_START            = 0x00000000;
        public static readonly UInt32 SERVICE_SYSTEM_START          = 0x00000001;
        public static readonly UInt32 SERVICE_AUTO_START            = 0x00000002;
        public static readonly UInt32 SERVICE_DEMAND_START          = 0x00000003;
        public static readonly UInt32 SERVICE_DISABLED              = 0x00000004;
 
        // Error control type
        public static readonly UInt32 SERVICE_ERROR_IGNORE          = 0x00000000;
        public static readonly UInt32 SERVICE_ERROR_NORMAL          = 0x00000001;
        public static readonly UInt32 SERVICE_ERROR_SEVERE          = 0x00000002;
        public static readonly UInt32 SERVICE_ERROR_CRITICAL        = 0x00000003;
 
        // Controls
        public static readonly UInt32 SERVICE_CONTROL_STOP          = 0x00000001;
        public static readonly UInt32 SERVICE_CONTROL_PAUSE         = 0x00000002;
        public static readonly UInt32 SERVICE_CONTROL_CONTINUE      = 0x00000003;
        public static readonly UInt32 SERVICE_CONTROL_INTERROGATE   = 0x00000004;
        public static readonly UInt32 SERVICE_CONTROL_SHUTDOWN      = 0x00000005;
 
        // Service object specific access type
        public static readonly UInt32 SERVICE_QUERY_CONFIG          = 0x0001;
        public static readonly UInt32 SERVICE_CHANGE_CONFIG         = 0x0002;
        public static readonly UInt32 SERVICE_QUERY_STATUS          = 0x0004;
        public static readonly UInt32 SERVICE_ENUMERATE_DEPENDENTS  = 0x0008;
        public static readonly UInt32 SERVICE_START                 = 0x0010;
        public static readonly UInt32 SERVICE_STOP                  = 0x0020;
 
        public static readonly UInt32 SERVICE_ALL_ACCESS            = 0xF01FF;
 
        // Service Control Manager object specific access types
        public static readonly UInt32 SC_MANAGER_ALL_ACCESS         = 0xF003F;
        public static readonly UInt32 SC_MANAGER_CREATE_SERVICE     = 0x0002;
        public static readonly UInt32 SC_MANAGER_CONNECT            = 0x0001;
        public static readonly UInt32 SC_MANAGER_ENUMERATE_SERVICE  = 0x0004;
        public static readonly UInt32 SC_MANAGER_LOCK               = 0x0008;
        public static readonly UInt32 SC_MANAGER_MODIFY_BOOT_CONFIG = 0x0020;
        public static readonly UInt32 SC_MANAGER_QUERY_LOCK_STATUS  = 0x0010;
 
        // These are the generic rights.
        public static readonly UInt32 GENERIC_READ                  = 0x80000000;
        public static readonly UInt32 GENERIC_WRITE                 = 0x40000000;
        public static readonly UInt32 GENERIC_EXECUTE               = 0x20000000;
        public static readonly UInt32 GENERIC_ALL                   = 0x10000000;
 
        //Driver Device Name
        public static readonly String TaskManager_Driver_Nt_Device_Name     = "\\Device\\TaskManagerDevice";
        public static readonly String TaskManager_Driver_Dos_Device_Name    = "\\DosDevices\\TaskManagerDevice";
 
 
 
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
        public struct SECURITY_ATTRIBUTES
        {
            public UInt32 nLength;
            public IntPtr lpSecurityDescriptor;
            public bool bInheritHandle;
        }
 
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
        public struct OVERLAPPED
        {
            public UInt32 Internal;
            public UInt32 InternalHigh;
            public UInt32 Offset;
            public UInt32 OffsetHigh;
            public IntPtr hEvent;
        }
 
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
        public struct SERVICE_STATUS
        {
            public UInt32 dwServiceType;
            public UInt32 dwCurrentState;
            public UInt32 dwControlsAccepted;
            public UInt32 dwWin32ExitCode;
            public UInt32 dwServiceSpecificExitCode;
            public UInt32 dwCheckPoint;
            public UInt32 dwWaitHint;
        }
    }
} 

                            

DriverDAL.cs

這個類即是所謂的數據訪問層,

一般來說,數據訪問層用在使用數據庫的情況下比較合適,

但是在這裏我將其抽象爲只要是提供最基本的數據服務的 API ,我都將其放在數據訪問層中,

所以這裏主要是 C# 平臺調用時,對於將要調用的 Win32 API 的一個聲明,

其中包括了 CreateFile ,OpenService 等等 API 的聲明。

                     

using System;
using System.Runtime.InteropServices;
using TaskManager.Entity;
 
namespace TaskManager.DAL
{
    public class DriverDAL
    {
        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr CreateFile(
            String lpFileName, 
            UInt32 dwDesiredAccess, 
            UInt32 dwShareMode, 
            ref DriverEntity.SECURITY_ATTRIBUTES lpSecurityAttributes, 
            UInt32 dwCreationDisposition, 
            UInt32 dwFlagsAndAttributes, 
            IntPtr hTemplateFile
            );
 
        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        public static extern bool WriteFile(
            IntPtr hFile, 
            byte[] lpBuffer, 
            UInt32 nNumberOfBytesToWrite, 
            ref UInt32 lpNumberOfBytesWritten, 
            ref DriverEntity.OVERLAPPED lpOverlapped
            );
 
        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        public static extern bool DeviceIoControl(
            IntPtr hDevice, 
            UInt32 dwIoControlCode, 
            byte[] lpInBuffer, 
            UInt32 nInBufferSize, 
            byte[] lpOutBuffer, 
            UInt32 nOutBufferSize, 
            ref UInt32 lpBytesReturned, 
            ref DriverEntity.OVERLAPPED lpOverlapped
            );
 
        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        public static extern bool CloseHandle(
            IntPtr hObject
            );
 
        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr CreateEvent(
            ref DriverEntity.SECURITY_ATTRIBUTES lpEventAttributes, 
            bool bManualReset, 
            bool bInitialState, 
            String lpName
            );
 
        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        public static extern UInt32 WaitForSingleObject(
            IntPtr hHandle, 
            UInt32 dwMilliseconds
            );
 
        [DllImport("kernel32.dll")]
        public static extern UInt32 GetLastError();  
 
 
        [DllImport("advapi32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr OpenSCManager(
            String lpMachineName, 
            String lpDatabaseName, 
            UInt32 dwDesiredAccess
            );
 
        [DllImport("advapi32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr CreateService(
            IntPtr hSCManager, 
            String lpServiceName, 
            String lpDisplayName, 
            UInt32 dwDesiredAccess, 
            UInt32 dwServiceType, 
            UInt32 dwStartType, 
            UInt32 dwErrorControl, 
            String lpBinaryPathName, 
            String lpLoadOrderGroup, 
            ref UInt32 lpdwTagId,
            String lpDependencies, 
            String lpServiceStartName, 
            String lpPassword
            );
 
        [DllImport("advapi32.dll", CharSet = CharSet.Auto)]
        public static extern bool CloseServiceHandle(
            IntPtr hSCObject
            );
 
        [DllImport("advapi32.dll", CharSet = CharSet.Auto)]
        public static extern bool StartService(
            IntPtr hService, 
            UInt32 dwNumServiceArgs, 
            String lpServiceArgVectors
            );
 
 
        [DllImport("advapi32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr OpenService(
            IntPtr hSCManager, 
            String lpServiceName, 
            UInt32 dwDesiredAccess
            );
 
        [DllImport("advapi32.dll", CharSet = CharSet.Auto)]
        public static extern bool DeleteService(
            IntPtr hService
            );
 
        [DllImport("advapi32.dll", CharSet = CharSet.Auto)]
        public static extern bool ControlService(
            IntPtr hService, 
            UInt32 dwControl, 
            ref DriverEntity.SERVICE_STATUS lpServiceStatus
            );
    }
}

 

DriverBLL.cs

這裏就是所謂的業務邏輯層了,其實呢,說白了,其中包括幾個重要的方法的實現,

比如啓動驅動程序服務,停止驅動程序服務,安裝啓動程序,卸載驅動程序等方法的實現。

該類是爲應用程序提供驅動程序安裝功能的直接類。

                  

using System;
using TaskManager.Entity;
using TaskManager.DAL;
 
namespace TaskManager.BLL
{
    public class DriverBLL
    {
        /// <summary>
        /// 啓動驅動程序
        /// </summary>
        /// <param name="svcName"></param>
        /// <returns></returns>
        public bool StartDriver(String svcName)
        {
            IntPtr scManagerHandle;
            IntPtr schDriverService;
 
            //打開服務控制檯管理器
            scManagerHandle = DriverDAL.OpenSCManager(null, null, DriverEntity.SC_MANAGER_CREATE_SERVICE);
            if (null == scManagerHandle || IntPtr.Zero == scManagerHandle)
            {
                return false;
            }
 
            //打開服務
            schDriverService = DriverDAL.OpenService(scManagerHandle, svcName, DriverEntity.SERVICE_ALL_ACCESS);
            if (null == schDriverService || IntPtr.Zero == schDriverService)
            {
                DriverDAL.CloseServiceHandle(scManagerHandle);
                return false;
            }
 
            if (false == DriverDAL.StartService(schDriverService, 0, null))
            {
                DriverDAL.CloseServiceHandle(schDriverService);
                DriverDAL.CloseServiceHandle(scManagerHandle);
                return false;
            }
 
            DriverDAL.CloseServiceHandle(schDriverService);
            DriverDAL.CloseServiceHandle(scManagerHandle);
 
            return true;
        }
 
 
        /// <summary>
        /// 停止驅動程序服務
        /// </summary>
        /// <param name="svcName"></param>
        /// <returns></returns>
        public bool StopDriver(String svcName)
        {
            IntPtr scManagerHandle;
            IntPtr schDriverService;
 
            DriverEntity.SERVICE_STATUS serviceStatus;
 
            //打開服務控制檯管理器
            scManagerHandle = DriverDAL.OpenSCManager(null, null, DriverEntity.SC_MANAGER_CREATE_SERVICE);
            if (null == scManagerHandle || IntPtr.Zero == scManagerHandle)
            {
                return false;
            }
 
            //打開服務
            schDriverService = DriverDAL.OpenService(scManagerHandle, svcName, DriverEntity.SERVICE_ALL_ACCESS);
            if (null == schDriverService || IntPtr.Zero == schDriverService)
            {
                DriverDAL.CloseServiceHandle(scManagerHandle);
                return false;
            }
 
            serviceStatus = new DriverEntity.SERVICE_STATUS();
 
            //停止服務
            if (false == DriverDAL.ControlService(schDriverService, DriverEntity.SERVICE_CONTROL_STOP, ref serviceStatus))
            {
                DriverDAL.CloseServiceHandle(schDriverService);
                DriverDAL.CloseServiceHandle(scManagerHandle);
 
                return false;
            }
            else
            {
                DriverDAL.CloseServiceHandle(schDriverService);
                DriverDAL.CloseServiceHandle(scManagerHandle);
 
                return true;
            }
        }
 
 
        /// <summary>
        /// 判斷驅動程序是否已經安裝
        /// </summary>
        /// <param name="svcName"></param>
        /// <returns></returns>
        public bool DriverIsInstalled(string svcName)
        {
            IntPtr scManagerHandle;
            IntPtr schDriverService;
 
            //打開服務控制檯管理器
            scManagerHandle = DriverDAL.OpenSCManager(null, null, DriverEntity.SC_MANAGER_ALL_ACCESS);
            if (null == scManagerHandle || IntPtr.Zero == scManagerHandle)
            {
                return false;
            }
 
            //打開驅動程序服務
            schDriverService = DriverDAL.OpenService(scManagerHandle, svcName, DriverEntity.SERVICE_ALL_ACCESS);
            if (null == schDriverService || IntPtr.Zero == schDriverService)
            {
                DriverDAL.CloseServiceHandle(scManagerHandle);
                return false;
            }
 
            DriverDAL.CloseServiceHandle(schDriverService);
            DriverDAL.CloseServiceHandle(scManagerHandle);
 
            return true;
        }
 
 
        /// <summary>
        /// 安裝驅動程序服務
        /// </summary>
        /// <param name="svcDriverPath"></param>
        /// <param name="svcDriverName"></param>
        /// <param name="svcDisplayName"></param>
        /// <returns></returns>
        public bool DriverInstall(String svcDriverPath, String svcDriverName, String svcDisplayName)
        {
            UInt32 lpdwTagId;
            IntPtr scManagerHandle;
            IntPtr schDriverService;
 
            //打開服務控制檯管理器
            scManagerHandle = DriverDAL.OpenSCManager(null, null, DriverEntity.SC_MANAGER_CREATE_SERVICE);
            if (null == scManagerHandle || IntPtr.Zero == scManagerHandle)
            {
                return false;
            }
            if (DriverIsInstalled(svcDriverName) == false)
            {
                lpdwTagId = 0;
                schDriverService = DriverDAL.CreateService(
                    scManagerHandle, svcDriverName, svcDisplayName, 
                    DriverEntity.SERVICE_ALL_ACCESS, 
                    DriverEntity.SERVICE_KERNEL_DRIVER, 
                    DriverEntity.SERVICE_DEMAND_START, 
                    DriverEntity.SERVICE_ERROR_NORMAL, 
                    svcDriverPath, null, 
                    ref lpdwTagId, 
                    null, null, null
                    );
 
                DriverDAL.CloseServiceHandle(scManagerHandle);
                if (null == schDriverService || IntPtr.Zero == schDriverService)
                {
                    return false;
                }
                else
                {
                    return true;
                }
            }
 
            DriverDAL.CloseServiceHandle(scManagerHandle);
            return true;
        }
 
 
        /// <summary>
        /// 卸載驅動程序服務
        /// </summary>
        /// <param name="svcName"></param>
        public void DriverUnInstall(String svcName)
        {
            IntPtr scManagerHandle;
            IntPtr schDriverService;
 
            //打開服務控制檯管理器
            scManagerHandle = DriverDAL.OpenSCManager(null, null, DriverEntity.SC_MANAGER_ALL_ACCESS);
            if (null == scManagerHandle || IntPtr.Zero == scManagerHandle)
            {
                return;
            }
 
            //打開驅動程序服務
            schDriverService = DriverDAL.OpenService(scManagerHandle, svcName, DriverEntity.SERVICE_ALL_ACCESS);
            if (null == schDriverService || IntPtr.Zero == schDriverService)
            {
                DriverDAL.CloseServiceHandle(scManagerHandle);
                return;
            }
            else
            {
                DriverDAL.DeleteService(schDriverService);
 
                DriverDAL.CloseServiceHandle(schDriverService);
                DriverDAL.CloseServiceHandle(scManagerHandle);
            }
        }
    }
}

            

上面的這個類呢,說實在的,對於沒用過驅動程序的來說,屁用沒一點,

但是如果某位也在煩惱驅動程序的安裝的話,那麼恭喜你,你中獎了 . . .

                      

版權所有,迎轉載,但轉載請註明: 轉載自 Zachary.XiaoZhen - 夢想的天空

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章