概述
前面 安装驱动程序(1)----驱动预安装 一文讨论了总线驱动/功能驱动和单层过滤驱动的安装,本文将讨论过滤驱动的安装。可能你会觉得奇怪,过滤驱动有必要需要单独讨论吗?
答案是肯定的。1.笔者的同事,前阵子遇到一个类过滤驱动,由于某些原因安装的时候出现问题。笔者凑过去一看,inf文件仅仅提供了ClassGuid,居然没有HardwareID这一栏。而以devcon install安装需要提供hardwareID,因此devcon被pass了,得另谋出路;2.设备堆栈中有多个过滤驱动,仍以toaster为例,如果为toaster选择安装%WinDDK%srcgeneraltoasterwdminf%ARCH%toasterf.inf,那toaster设备栈上将有5个驱动程序:类过滤驱动clsupper/clslower,设备过滤驱动devupper/devlower和功能驱动本身toaster。如果想添加/移除制定位置上的一个过滤驱动,怎么办?带着这2个问题,我们往下看。
先说安装类过滤驱动。MS提供了类过滤驱动的inf文件模板,位于%WinDDK%srcsetupinfsclasfiltClasFilt.inf,只要替换其中的classguid和sys文件名并在inf文件中指明UpperFilter或LowerFilter即可。以toaster为例,如果想安装下层类过滤驱动,按如下方式修改ClassFilt.inf,即可(又要恢复虚拟机快照了):
[Version]
signature = "$Windows NT$"
; Distribution Media information
;
[SourceDisksNames]
1 = %ClasFilt.MediaDesc%
[SourceDisksFiles]
;原本是clasfilt.sys
clslower.sys = 1
[DestinationDirs]
;
; Driver to be installed in the drivers subdirectory.
;
DefaultDestDir = 12 ; DIRID_DRIVERS
[DefaultInstall.NT]
;CopyFiles = @clasfilt.sys 指向要拷贝的sys文件路径
CopyFiles = @clslower.sys
AddReg = ClassFilter_AddReg
[ClassFilter_AddReg]
;替换{setup-ClassGUID}为toaster的classguid 原本为HKLM, SystemCurrentControlSetControl
Class{setup-ClassGUID}, UpperFilters, 0x00010008, clasfilt
HKLM, SystemCurrentControlSetControlClass{b85b7c50-6a01-11d2-b841-00c04fad5171},
LowerFilters, 0x00010008, clasfilt
[DefaultInstall.NT.Services]
AddService = clasfilt, , clasfilt_Service_Inst, clasfilt_EventLog_Inst
[clasfilt_Service_Inst]
DisplayName
= %ClasFilt.SvcDesc%
ServiceType
= %SERVICE_KERNEL_DRIVER%
StartType
= %SERVICE_DEMAND_START%
ErrorControl
= %SERVICE_ERROR_IGNORE%
;原本为ServiceBinary
= %12%clasfilt.sys 指向驱动程序二进制文件的路径
ServiceBinary
= %12%clslower.sys
[clasfilt_EventLog_Inst]
AddReg = clasfilt_EventLog_AddReg
[clasfilt_EventLog_AddReg]
;HKR,,EventMessageFile, %REG_EXPAND_SZ%,"%%SystemRoot%%System32IoLogMsg.dll;%%SystemRoot
%%System32driversclasfilt.sys"
HKR,,EventMessageFile, %REG_EXPAND_SZ%,"%%SystemRoot%%System32IoLogMsg.dll;%%SystemRoot%
%System32driversclslower.sys"
HKR,,TypesSupported, %REG_DWORD%, 7
[Strings]
;在注册表中显示的名字
ClasFilt.SvcDesc = "Lower Class Filter Driver"
; Change the media description to describe your media.
;
ClasFilt.MediaDesc
= "Class Filter Driver Disc"
; Useful constants
SERVICE_KERNEL_DRIVER = 1
SERVICE_DEMAND_START
= 3
SERVICE_ERROR_IGNORE
= 0
REG_EXPAND_SZ
= 0x00020000
REG_DWORD
= 0x00010001
修改inf文件后,可以通过右键安装,也可以通过代码现实:
TCHAR szCommandLine[] = TEXT("DefaultInstall 132 .\clasfilt.inf");
InstallHinfSection(NULL, NULL, szCommandLine, SW_SHOW);
来看下安装类过滤驱动前后对比:
以下是安装前
以下是右键安装后:
2.上面讨论了安装类过滤驱动,现在来讨论第二个问题,往现有设备栈中插入/删除设备过滤驱动。实现思路和前面创建虚拟设备差不多,都是通过SetupDi接口从注册表中获得信息。不过由于描述整个过程过于复杂,我决定还是直接贴出代码:
#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable : 4129)
#include <driverspecs.h>
#define _In_
#define _Inout_
#define _In_reads_
//#include "BtAcpi.h"
#pragma comment(lib,"setupapi.lib")
#pragma comment(lib,"difxapi.lib")
#pragma comment(lib,"Shlwapi.lib")
#pragma comment(lib,"bthprops.lib")
#include "CommonHeaders.h"
#include "addprofiledriver.h"
#if DBG
#include <assert.h>
#define ASSERT(condition) assert(condition)
#else
#define ASSERT(condition)
#endif
#ifdef _DEBUG
#define LOGMESSAGE(str) printf str;
#else
#define LOGMESSAGE(str)
#endif
DEFINE_GUID(GUID_DEVCLASS_MSTOASTER, 0xb85b7c50, 0x6a01, 0x11d2, 0xb8, 0x41, 0x00, 0xc0, 0x4f, 0xad, 0x51, 0x71);
//{b85b7c50-6a01-11d2-b841-00c04fad5171}
#define CMD_REMOVE_FILTER
"/removefilter"
#define CMD_ADD_FILTER
"/addfilter"
typedef enum TOS_ADD_FILTER_ERR_NO {
TOS_ADD_FILTER_GENERIC_ERROR = 1,
TOS_ADD_FILTER_COPY_SUCCESS,
TOS_ADD_FILTER_COPY_FAILED,
TOS_ADD_FILTER_FILE_NOT_FOUND,
TOS_ADD_FILTER_CREATE_SRV_FAILED,
TOS_ADD_FILTER_CREATE_SRV_SUCCESS,
TOS_ADD_FILTER_DELETE_SRV_FAILED,
TOS_ADD_FILTER_DELETE_SRV_SUCCESS,
TOS_ADD_PROFILE_DRV_SUCCESS,
TOS_ADD_FILTER_SRV_FAIL_HANDLED,
TOS_ADJUST_PRIVILEGES_FAILES,
TOS_SERVICE_MARKED_FOR_DELETION
};
typedef enum TOS_FIND_FILTER_ERR_NO {
TOS_FIND_FILTER_GENERIC_ERROR = 1,
TOS_FIND_FILTER_REG_FOUND,
TOS_FIND_FILTER_REG_NOT_FOUND,
TOS_FILTER_FILE_FOUND,
TOS_FILTER_FILE_NOT_FOUND,
TOS_64_BIT_OS,
TOS_NOT_64_BIT_OS
};
typedef BOOL(WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
BOOLEAN
AddFilterDriver(
IN HDEVINFO DeviceInfoSet,
IN PSP_DEVINFO_DATA DeviceInfoData,
_In_ IN LPTSTR Filter,
IN BOOLEAN UpperFilter
);
BOOLEAN
RemoveFilterDriver(
IN HDEVINFO DeviceInfoSet,
IN PSP_DEVINFO_DATA DeviceInfoData,
_In_ IN LPTSTR Filter,
IN BOOLEAN UpperFilter
);
BOOLEAN CreateFilterService(IN LPTSTR Filter, WCHAR *filterFilePath);
BOOLEAN DeleteFilterService(IN LPTSTR Filter);
VOID RebootDevice();
INT32 FilterCopyFile(BOOL createService);
void
PrintFilters(
IN HDEVINFO DeviceInfoSet,
IN PSP_DEVINFO_DATA DeviceInfoData,
IN BOOLEAN UpperFilters
);
LPTSTR
GetFilters(
IN HDEVINFO DeviceInfoSet,
IN PSP_DEVINFO_DATA DeviceInfoData,
IN BOOLEAN UpperFilters
);
void PrintDeviceName(
IN HDEVINFO DeviceInfoSet,
IN PSP_DEVINFO_DATA DeviceInfoData
);
BOOLEAN
DeviceNameMatches(
IN HDEVINFO DeviceInfoSet,
IN PSP_DEVINFO_DATA DeviceInfoData,
_In_ IN LPTSTR DeviceName
);
PBYTE
GetDeviceRegistryProperty(
IN
HDEVINFO DeviceInfoSet,
IN
PSP_DEVINFO_DATA DeviceInfoData,
IN
DWORD Property,
OUT PDWORD PropertyRegDataType
);
BOOLEAN
RestartDevice(
IN HDEVINFO DeviceInfoSet,
IN OUT PSP_DEVINFO_DATA DeviceInfoData
);
BOOLEAN
PrependSzToMultiSz(
_In_
LPTSTR
SzToPrepend,
_Inout_ LPTSTR *MultiSz
);
size_t
MultiSzLength(
_In_ IN LPTSTR MultiSz
);
size_t
MultiSzSearchAndDeleteCaseInsensitive(
_In_ IN
LPTSTR
FindThis,
_In_ IN
LPTSTR
FindWithin,
OUT size_t
*NewStringLength
);
void GetFilterVersion(char *Version);
int GetFilterFileStatus();
int Is64BitProcess();
int uninstallFilter();
int installFilter();
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(X) (sizeof(X) / sizeof(*X))
#endif
int CreateServicepassed = 0;
HDEVINFO
devInfoGlobal = INVALID_HANDLE_VALUE;
SP_DEVINFO_DATA
devInfoDataGlobal;
BOOLEAN createServiceFail = FALSE;
BOOLEAN isFilterDriverUnInstallSuccess = FALSE;
BOOLEAN isFilterDriverInstallSuccess = FALSE;
int __cdecl _tmain(int argc, LPTSTR argv[])
{
// structs needed to contain information about devices
HDEVINFO
devInfo = INVALID_HANDLE_VALUE;
SP_DEVINFO_DATA
devInfoData;
// indices for stepping through devices, and device interface guids
int argIndex = 1;
int deviceIndex;
// variables used to deal with the command-line options of this program
BOOLEAN upperFilter = FALSE;
LPTSTR filterToAdd = TOS_BTFILTER_NAME;
LPTSTR filterToRemove = NULL;
LPTSTR filterDrvArg = NULL;
LPTSTR profileDrvArg = NULL;
BOOLEAN keepGoing = TRUE;
BOOLEAN createService = TRUE;
// parse arguments; nothing too exciting here //
if (argc <= 1 || argc >= 5){
return TOS_ADD_FILTER_GENERIC_ERROR;
}
for (argIndex = 1; argIndex < argc; argIndex++) {
#pragma prefast(suppress:6385, "Previously checked argIndex being less than argc. No buffer overflow.")
if ((_tcscmp(argv[argIndex], _T(CMD_REMOVE_FILTER)) == 0) || (_tcscmp(argv[argIndex], _T(CMD_ADD_FILTER)) == 0)
|| (_tcscmp(argv[argIndex], _T(CMD_COPY_FILTER_DRV_FILE)) == 0))
{
filterDrvArg = argv[argIndex];
}
else if ((_tcscmp(argv[argIndex], _T(CMD_ADD_A2DP_SCO_PROFILE)) == 0) || (_tcscmp(argv[argIndex], _T(CMD_ADD_A2DP_PROFILE)) == 0)
|| (_tcscmp(argv[argIndex], _T(CMD_ADD_SCO_PROFILE)) == 0) || (_tcscmp(argv[argIndex], _T(CMD_REMOVE_A2DP_SCO_PROFILE)) == 0)
|| (_tcscmp(argv[argIndex], _T(CMD_REMOVE_A2DP_PROFILE)) == 0) || (_tcscmp(argv[argIndex], _T(CMD_REMOVE_SCO_PROFILE)) == 0))
{
profileDrvArg = argv[argIndex];
}
else if (_tcscmp(argv[argIndex], _T(CMD_FORCE_REBOOT)) == 0) {
RebootDevice();
}
else {
return TOS_ADD_FILTER_GENERIC_ERROR;
}
}
if (NULL != profileDrvArg)
{
if (InstallProfileDriver(profileDrvArg, 6)) {
LOGMESSAGE(("Silent Profile Driver installation success!!! rn"));
}
else {
if (InstallProfileDriver(profileDrvArg, 0)) {
LOGMESSAGE(("Profile Driver installation success!!! rn"));
}
else {
LOGMESSAGE(("Profile Driver installation failed!!! rn"));
return TOS_ADD_FILTER_GENERIC_ERROR;
}
}
}
if (NULL == filterDrvArg)
{
return TOS_ADD_PROFILE_DRV_SUCCESS;
}
if (_tcscmp(filterDrvArg, _T(CMD_REMOVE_FILTER)) == 0) {
createService = FALSE;
LOGMESSAGE(("Deleting Filter!!! rn"));
}
else if (_tcscmp(filterDrvArg, _T(CMD_ADD_FILTER)) == 0) {
createService = TRUE;
LOGMESSAGE(("Adding Filter driver!!! rn"));
}
else if (_tcscmp(filterDrvArg, _T(CMD_COPY_FILTER_DRV_FILE)) == 0) {
int ret = FilterCopyFile(FALSE);
return ret;
}
else {
return (TOS_ADD_FILTER_GENERIC_ERROR);
}
if (createService == FALSE) {
filterToRemove = TOS_BTFILTER_NAME;
filterToAdd = NULL;
}
devInfo = SetupDiGetClassDevs(&GUID_DEVCLASS_MSTOASTER,
NULL,
NULL,
DIGCF_PRESENT);
if (devInfo == INVALID_HANDLE_VALUE) {
LOGMESSAGE(("got INVALID_HANDLE_VALUE!n"));
return (TOS_ADD_FILTER_GENERIC_ERROR);
}
// as per DDK docs on SetupDiEnumDeviceInfo
devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
// step through the list of devices for this handle
// get device info at index deviceIndex, the function returns FALSE
// when there is no device at the given index.
for (deviceIndex = 0;
SetupDiEnumDeviceInfo(devInfo, deviceIndex, &devInfoData);
deviceIndex++) {
// setting this variable to FALSE will cause all of the if
// statements to fall through, cutting off processing for this
// device.
keepGoing = TRUE;
LPTSTR buffer = NULL;
LPTSTR hardWareName = L"{B85B7C50-6A01-11d2-B841-00C04FAD5171}MsToaster";
DWORD buffersize = 0;
DWORD DataT;
SetupDiGetDeviceRegistryProperty(
devInfo,
&devInfoData,
SPDRP_HARDWAREID,
&DataT,
(PBYTE)buffer,
buffersize,
&buffersize);
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
buffer = (LPTSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buffersize * 2);
if (buffer == NULL)
continue;
SetupDiGetDeviceRegistryProperty(
devInfo,
&devInfoData,
SPDRP_HARDWAREID,
&DataT,
(PBYTE)buffer,
buffersize,
&buffersize);
if (!memcmp(buffer, hardWareName, 16))
{
LOGMESSAGE(("hardware USB adapter found !!!!rn"));
HeapFree(GetProcessHeap(), 0, buffer);
}
else {
HeapFree(GetProcessHeap(), 0, buffer);
continue;
}
// print the device name
if (keepGoing) {
PrintDeviceName(devInfo, &devInfoData);
}
devInfoGlobal = devInfo;
devInfoDataGlobal = devInfoData;
// print the drivers, if we are not adding or removing one
if (keepGoing && filterToAdd == NULL && filterToRemove == NULL) {
PrintFilters(devInfo, &devInfoData, upperFilter);
}
int ret;
// add the filter, then try to restart the device
if ((keepGoing && filterToAdd != NULL))
{
ret = installFilter();
if (ret == TOS_SERVICE_MARKED_FOR_DELETION)
{
uninstallFilter();
//Sleep(1000);
uninstallFilter();
//Sleep(1000);
uninstallFilter();
//Sleep(1000);
installFilter();
}
}
// remove the filter, then try to restart the device
if ((keepGoing && filterToRemove != NULL))
{
uninstallFilter();
//Sleep(1000);
uninstallFilter();
//Sleep(1000);
uninstallFilter();
}
}
// clean up the device list
if (devInfo != INVALID_HANDLE_VALUE) {
if (!SetupDiDestroyDeviceInfoList(devInfo)) {
LOGMESSAGE(("unable to delete device info list! error: %un",
GetLastError()));
}
}
if (TRUE == isFilterDriverUnInstallSuccess) {
return TOS_ADD_FILTER_DELETE_SRV_SUCCESS;
}
if (!isFilterDriverInstallSuccess) {
return TOS_ADD_FILTER_GENERIC_ERROR;
}
//Sleep(100000);
return (TOS_ADD_FILTER_CREATE_SRV_SUCCESS);
}
/*
* add the given filter driver to the list of upper filter drivers for the
* device.
*
* After the call, the device must be restarted in order for the new setting to
* take effect. This can be accomplished with a call to RestartDevice(), or by
* rebooting the machine.
*
* returns TRUE if successful, FALSE otherwise
*
* note: The filter is prepended to the list of drivers, which will put it at
* the bottom of the filter driver stack
*
* parameters:
*
DeviceInfoSet
- The device information set which contains DeviceInfoData
*
DeviceInfoData - Information needed to deal with the given device
*
Filter
- the filter to add
*/
BOOLEAN
AddFilterDriver(
IN HDEVINFO DeviceInfoSet,
IN PSP_DEVINFO_DATA DeviceInfoData,
_In_ IN LPTSTR Filter,
IN BOOLEAN UpperFilter
)
{
size_t length = 0; // character length
size_t size
= 0; // buffer size
LPTSTR buffer = GetFilters( DeviceInfoSet, DeviceInfoData, UpperFilter );
ASSERT(DeviceInfoData != NULL);
ASSERT(Filter != NULL);
if( buffer == NULL )
{
// if there is no such value in the registry, then there are no upper
// filter drivers loaded, and we can just put one there
// make room for the string, string null terminator, and multisz null
// terminator
length = _tcslen(Filter)+1;
size
= (length+1)*sizeof(_TCHAR);
buffer = (LPTSTR)malloc(size);
if( buffer == NULL )
{
LOGMESSAGE(("in AddUpperFilterDriver(): unable to allocate memory!n"));
return (FALSE);
}
memset(buffer, 0, size);
// copy the string into the new buffer
memcpy(buffer, Filter, length*sizeof(_TCHAR));
}
else
{
LPTSTR buffer2;
// remove all instances of filter from driver list
MultiSzSearchAndDeleteCaseInsensitive( Filter, buffer, &length );
// allocate a buffer large enough to add the new filter
// MultiSzLength already includes length of terminating NULL
// determing the new length of the string
length = MultiSzLength(buffer) + _tcslen(Filter) + 1;
size
= length*sizeof(_TCHAR);
buffer2 = (LPTSTR)malloc(size);
if (buffer2 == NULL) {
LOGMESSAGE(("Out of memory adding filtern"));
return (0);
}
memset(buffer2, 0, size);
// swap the buffers out
memcpy(buffer2, buffer, MultiSzLength(buffer)*sizeof(_TCHAR));
free(buffer);
buffer = buffer2;
// add the driver to the driver list
PrependSzToMultiSz(Filter, &buffer);
}
// set the new list of filters in place
if( !SetupDiSetDeviceRegistryProperty( DeviceInfoSet,
DeviceInfoData,
(UpperFilter ? SPDRP_UPPERFILTERS : SPDRP_LOWERFILTERS),
(PBYTE)buffer,
(DWORD)(MultiSzLength(buffer)*sizeof(_TCHAR)) )
)
{
LOGMESSAGE(("in AddUpperFilterDriver(): "
"couldn't set registry value! error: %un", GetLastError()));
free( buffer );
return (FALSE);
}
// no need for buffer anymore
free( buffer );
return (TRUE);
}
/*
* remove all instances of the given filter driver from the list of upper
* filter drivers for the device.
*
* After the call, the device must be restarted in order for the new setting to
* take effect. This can be accomplished with a call to RestartDevice(), or by
* rebooting the machine.
*
* returns TRUE if successful, FALSE otherwise
*
* parameters:
*
DeviceInfoSet
- The device information set which contains DeviceInfoData
*
DeviceInfoData - Information needed to deal with the given device
*
Filter - the filter to remove
*/
BOOLEAN
RemoveFilterDriver(
IN HDEVINFO DeviceInfoSet,
IN PSP_DEVINFO_DATA DeviceInfoData,
_In_ IN LPTSTR Filter,
IN BOOLEAN UpperFilter
)
{
size_t length
= 0;
size_t size
= 0;
LPTSTR buffer
= GetFilters( DeviceInfoSet, DeviceInfoData, UpperFilter );
BOOL
success = FALSE;
ASSERT(DeviceInfoData != NULL);
ASSERT(Filter != NULL);
if( buffer == NULL )
{
// if there is no such value in the registry, then there are no upper
// filter drivers loaded, and we are done
return (TRUE);
}
else
{
// remove all instances of filter from driver list
MultiSzSearchAndDeleteCaseInsensitive( Filter, buffer, &length );
}
length = MultiSzLength(buffer);
ASSERT ( length > 0 );
if( length == 1 )
{
// if the length of the list is 1, the return value from
// MultiSzLength() was just accounting for the trailing '