回憶剛進公司那會兒,手頭的第一個工作就是完成虛擬鍵盤,也就是通過驅(qū)動程序向鍵盤端口寫入數(shù)據(jù),
這份活至今記憶猶新,那會兒寫的是個過濾驅(qū)動程序,也就是將我的虛擬設(shè)備綁定到真實的鍵盤設(shè)備上,
當(dāng)驅(qū)動程序編譯完成以后,我也總是通過下面的這個工具來安裝驅(qū)動程序,
每編譯好一次就使用這個工具重新安裝驅(qū)動一次,然后通過 DbgView 來打印消息,
那會兒還真傻,為了弄出這么個虛擬鍵盤,都不曉得安裝了驅(qū)動多少回,
直到后來,當(dāng)驅(qū)動程序完成以后,就需要部署驅(qū)動程序了,在網(wǎng)上找了很多資料,
大部分也都是通過 INF 文件來實現(xiàn),而對于 WDM 驅(qū)動程序,則還可以通過服務(wù)控制臺來實現(xiàn)安裝,
模模糊糊還記得當(dāng)初就是通過這個服務(wù)控制臺來實現(xiàn)驅(qū)動程序服務(wù)的安裝的。
當(dāng)初的實現(xiàn)是這樣的,通過編寫一個 DLL 來調(diào)用服務(wù)控制臺 API 從而完成驅(qū)動程序的安裝,
然后再在 C# (應(yīng)用程序是使用的 C# WinForm ,驅(qū)動程序必須和這個應(yīng)用程序通信)中通過平臺調(diào)用,
訪問這個 DLL ,這樣就可以實現(xiàn)驅(qū)動程序的動態(tài)加載以及動態(tài)啟動服務(wù)和停止服務(wù)等等操作了。
而在下面呢,我也算是對以前寫的那個 DLL 做一個總結(jié),將其總結(jié)為一個 C# 類,這樣以后用起來會更加方便。
整個的類,我按分層的思想將其分為三塊(其實這里將其這樣劃分不是非常合適):
DriverEntity.cs
這里即是所謂的實體層,在該類下面呢,主要包括的是將要在 DriverBLL 中使用到的一些常量數(shù)據(jù),
這些數(shù)據(jù)呢包括服務(wù)的類型,服務(wù)啟動類型,當(dāng)然也包括了將會使用到的一些結(jié)構(gòu)類型等等信息。
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
這個類即是所謂的數(shù)據(jù)訪問層,
一般來說,數(shù)據(jù)訪問層用在使用數(shù)據(jù)庫的情況下比較合適,
但是在這里我將其抽象為只要是提供最基本的數(shù)據(jù)服務(wù)的 API ,我都將其放在數(shù)據(jù)訪問層中,
所以這里主要是 C# 平臺調(diào)用時,對于將要調(diào)用的 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
這里就是所謂的業(yè)務(wù)邏輯層了,其實呢,說白了,其中包括幾個重要的方法的實現(xiàn),
比如啟動驅(qū)動程序服務(wù),停止驅(qū)動程序服務(wù),安裝啟動程序,卸載驅(qū)動程序等方法的實現(xiàn)。
該類是為應(yīng)用程序提供驅(qū)動程序安裝功能的直接類。
using System;
using TaskManager.Entity;
using TaskManager.DAL;
namespace TaskManager.BLL
{
public class DriverBLL
{
/// <summary>
/// 啟動驅(qū)動程序
/// </summary>
/// <param name="svcName"></param>
/// <returns></returns>
public bool StartDriver(String svcName)
{
IntPtr scManagerHandle;
IntPtr schDriverService;
//打開服務(wù)控制臺管理器
scManagerHandle = DriverDAL.OpenSCManager(null, null, DriverEntity.SC_MANAGER_CREATE_SERVICE);
if (null == scManagerHandle || IntPtr.Zero == scManagerHandle)
{
return false;
}
//打開服務(wù)
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>
/// 停止驅(qū)動程序服務(wù)
/// </summary>
/// <param name="svcName"></param>
/// <returns></returns>
public bool StopDriver(String svcName)
{
IntPtr scManagerHandle;
IntPtr schDriverService;
DriverEntity.SERVICE_STATUS serviceStatus;
//打開服務(wù)控制臺管理器
scManagerHandle = DriverDAL.OpenSCManager(null, null, DriverEntity.SC_MANAGER_CREATE_SERVICE);
if (null == scManagerHandle || IntPtr.Zero == scManagerHandle)
{
return false;
}
//打開服務(wù)
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();
//停止服務(wù)
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>
/// 判斷驅(qū)動程序是否已經(jīng)安裝
/// </summary>
/// <param name="svcName"></param>
/// <returns></returns>
public bool DriverIsInstalled(string svcName)
{
IntPtr scManagerHandle;
IntPtr schDriverService;
//打開服務(wù)控制臺管理器
scManagerHandle = DriverDAL.OpenSCManager(null, null, DriverEntity.SC_MANAGER_ALL_ACCESS);
if (null == scManagerHandle || IntPtr.Zero == scManagerHandle)
{
return false;
}
//打開驅(qū)動程序服務(wù)
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>
/// 安裝驅(qū)動程序服務(wù)
/// </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;
//打開服務(wù)控制臺管理器
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>
/// 卸載驅(qū)動程序服務(wù)
/// </summary>
/// <param name="svcName"></param>
public void DriverUnInstall(String svcName)
{
IntPtr scManagerHandle;
IntPtr schDriverService;
//打開服務(wù)控制臺管理器
scManagerHandle = DriverDAL.OpenSCManager(null, null, DriverEntity.SC_MANAGER_ALL_ACCESS);
if (null == scManagerHandle || IntPtr.Zero == scManagerHandle)
{
return;
}
//打開驅(qū)動程序服務(wù)
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);
}
}
}
}
上面的這個類呢,說實在的,對于沒用過驅(qū)動程序的來說,屁用沒一點,
但是如果某位也在煩惱驅(qū)動程序的安裝的話,那么恭喜你,你中獎了 . . .
版權(quán)所有,歡迎轉(zhuǎn)載,但轉(zhuǎn)載請注明: 轉(zhuǎn)載自 Zachary.XiaoZhen - 夢想的天空