您的位置:首页 > 其它

程序实现启用/禁用设备(驱动)enable/disable device with windows api

2009-09-25 00:16 1141 查看
懒人也动笔了;2009-09-25

程序实现启用/禁用设备(驱动)

—— enable/disable device (driver) with windows api

需求:

用程序实现类似设备管理器对设备驱动的控制(启用/禁用);

起初的尝试(失败):

一开始使用的是service api 重启驱动对应的,即使用”ControlService“向服务发送SERVICE_CONTROL_STOP消息停止服务,

再用“StartService"重新启动服务即可;

服务的启动、停止源代码可搜索 ”service control program“或"svccontrol.cpp" 找到微软的msdn sample;

如果链接地址没变的话是:http://msdn.microsoft.com/en-us/library/bb540474(VS.85).aspx

对于一些普通的驱动,该方法可以奏效,但是对于我们的设备驱动却失败了;

于是先使用命令行 sc 手动停止驱动服务,

不想同样失败,得到的提示信息是:

ControlService Failed 1052:

The request is not valid for this service

上网搜索后找到解释为:

You cannot stop the WDM drivers using ControlService
, even on 32bit [http://www.codecomments.com/archive421-2006-5-938507.html]

我们的设备是用wdf写的;

另外还发现了为什么ControlServcie可以控制驱动:http://www.reverse-engineering.info/SystemCoding/SkeletonKMD_Tutorial.htm Kernel Mode Driver Tutorial中讲到:



��

The DriverUnload routine is pretty self
explanatory.�
It will be called when the
loader invokes the ControlService
API with a
SERVICE_CONTROL_STOP message. DriverUnload basically unwinds the actions taken by
the DriverEntry function.�
It will
perform any driver specific cleanup and is at a minimum required to delete the
device object (IoDeleteDevice
) and the
symbolic link (IoDeleteSymbolicLink
).�
Failure to perform either of these actions
will corrupt the internal service database entry for the driver preventing it
from being loaded again (until you reboot

L

).

IIc.


The



Loader



If you have Driver Studio, you can use the handy little
utitlity �Driver Monitor� to load, start, stop, and unload drivers for testing
purposes. However, if your driver must provide services to a ring 3 application
will, the ring 3 application will will manually
have to install the driver as a service in order to be able to communicate with
it.�
The procedure for loading a driver
is as follows:

1. Obtain a handle to the service manager using OpenSCManager
.

2. Define the driver using CreateService
. This creates an entry in the
service database for the driver.�
Note, that
this information is kept in the registry
under...HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services/"My Driver's
Name".�
Realize, that CreateService
does not
*load*
the driver.�
It simply
creates an entry in the service database so that it can be recognized.

3. Open the driver using OpenService
.�
This call loads the driver, but realize that
this call does not
*start*
the driver.

4. Finally start the driver using the StartService
function.�
Note that this function is what finally calls
the DriverEntry routine.�
If there are
errors in your DriverEntry routine, expect StartService to fail.

5. Now you can open a handle to the driver in a
ring 3 application using CreateFile
and send
requests via the DeviceIoControl
.

6. Stop the driver by sending a
SERVICE_CONTROL_STOP via ControlService
.�
Note that this function calls the
DriverUnload routine.�
If there are
errors in your DriverUnload routine, expect this function to fail and expect to
be unable to load the driver again unless you reboot.�
This is because if this call fails, or the
driver crashes before executing this call, the service database entry for the
driver will be corrupted until you reboot.

7. Finally delete the service using DeleteService
and release the handle to the
service control database using CloseServiceHandle
.�
DeleteService is the function responsible for
deleting the actual entry in the service database and the corresponding key in
the registry.

上诉讲到了整个驱动的加载过程;但是为什么service不能卸载wdm驱动? 尽管翻找了半天 msdn上的WDK和service都没有找到相关解释,无奈作罢;

进展——使用SetupDi×××API:

使用ControlService失败,遂寻找其他办法;

后发现使用devcon 可以 enable/disable驱动程序,其效果和 Device Manager的一样,

而devcon在ddk中有源码,遂参照devcon中代码实现了程序 enable/disable驱动;

关键函数代码如下:

// EnumAndControlDevice:

// enum the device whose device id matched the path_filter and control the device with control_code;

// path_filter: the filter string to enum the device

// control_code: can be DICS_ENABLE/DICS_DISABLE/DICS_PROPCHANGE/DICS_START/DICS_STOP which indicating a change in a device's state

// here use DICS_ENABLE to enable, DICS_DISABLE to disable and DICS_PROPCHANGE to restart the device;

int EnumAndControlDevice(const TCHAR * path_filter, int control_code)

{

int ret = 0;

GUID Guid;// = GUID_DEVCLASS_HIDCLASS;

DWORD size = 0;

::SetupDiClassGuidsFromNameEx
(_T("hidclass"), &Guid, 1, &size, NULL, NULL); //这里我们的设备是”hidclass"设备

HDEVINFO info;

info=SetupDiGetClassDevs
(&Guid, NULL, NULL, DIGCF_PRESENT); // 枚举已存在(DIGCF_PRESENT)的hidclass类型设备

if (info!=INVALID_HANDLE_VALUE)

{

DWORD devIndex = 0;

SP_DEVINFO_DATA did;

did.cbSize = sizeof(SP_DEVINFO_DATA);

for (devIndex=0;SetupDiEnumDeviceInfo
(info,devIndex, &did);++devIndex) //枚举设备信息

{

TCHAR deviceId[1024] = {0};

DWORD requiredSize = 0;

if(SetupDiGetDeviceInstanceId
(info, &did,deviceId, sizeof(deviceId), &requiredSize))

{

LOG_INFO((debuginfo, "device:%s/n", TString::to_string(deviceId).c_str()));

// Add the link to the list of all DFU devices

if( (_tcsstr(deviceId, path_filter) != NULL) )

{

LOG_INFO((debuginfo, "find the device with path:%s/n", TString::to_string(path_filter).c_str()));

int tmp_ret = ControlDevice

(info,&did, control_code);

if(tmp_ret != 0){

ret = tmp_ret;

}

}

}

}

SetupDiDestroyDeviceInfoList
(info);

}

return ret;

}

ControlDevice:改自devcon-》cmds.cpp [ControlCallback]

int ControlDevice(HDEVINFO Devs, PSP_DEVINFO_DATA DevInfo,int controlCode)

/*++

Routine Description:

Callback for use by Enable/Disable/Restart

Invokes DIF_PROPERTYCHANGE with correct parameters

uses SetupDiCallClassInstaller so cannot be done for remote devices

Don't use CM_xxx API's, they bypass class/co-installers and this is bad.

In Enable case, we try global first, and if still disabled, enable local

Arguments:

Devs )_ uniquely identify the device

DevInfo )

controlcode:

Return Value:

EXIT_xxxx

--*/

{

int ret = 0;

SP_PROPCHANGE_PARAMS pcp;

SP_DEVINSTALL_PARAMS devParams;

switch(controlCode) {

case DICS_ENABLE:

//

// enable both on global and config-specific profile

// do global first and see if that succeeded in enabling the device

// (global enable doesn't mark reboot required if device is still

// disabled on current config whereas vice-versa isn't true)

//

pcp.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);

pcp.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;

pcp.StateChange = controlCode;

pcp.Scope = DICS_FLAG_GLOBAL;

pcp.HwProfile = 0;

//

// don't worry if this fails, we'll get an error when we try config-

// specific.

if(SetupDiSetClassInstallParams
(Devs,DevInfo,&pcp.ClassInstallHeader,sizeof(pcp))) {

SetupDiCallClassInstaller
(DIF_PROPERTYCHANGE,Devs,DevInfo);

}

//

// now enable on config-specific

//

pcp.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);

pcp.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;

pcp.StateChange = controlCode;

pcp.Scope = DICS_FLAG_CONFIGSPECIFIC;

pcp.HwProfile = 0;

break;

default:

//

// operate on config-specific profile

//

pcp.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);

pcp.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;

pcp.StateChange = controlCode;

pcp.Scope = DICS_FLAG_CONFIGSPECIFIC;

pcp.HwProfile = 0;

break;

}

if(!SetupDiSetClassInstallParams
(Devs,DevInfo,&pcp.ClassInstallHeader,sizeof(pcp)) ||

!SetupDiCallClassInstaller
(DIF_PROPERTYCHANGE
,Devs,DevInfo)) {

//

// failed to invoke DIF_PROPERTYCHANGE

//

ret = ::GetLastError();

LOG_INFO((debuginfo, " fail to invoke DIF_PROPERTYCHANGE:%d/n", ret));

} else {

//

// see if device needs reboot

//

devParams.cbSize = sizeof(devParams);

if(SetupDiGetDeviceInstallParams
(Devs,DevInfo,&devParams) && (devParams.Flags & (DI_NEEDRESTART|DI_NEEDREBOOT))) {

// need to reboot

LOG_INFO((debuginfo, " need to reboot/n"));

} else {

//

// appears to have succeeded

//

LOG_INFO((debuginfo, " restart driver succeed/n"));

}

}

return ret;

}

补充:

关于hardware profiles: 参考 http://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/hardware_profiles_overview.mspx?mfr=true
另外参考WDK——》Device Installation: SP_PROPCHANGE_PARAMS

Flags that specify the scope of a device property change. Can be one of the following:

DICS_FLAG_GLOBAL
Make the change in all hardware profiles.
DICS_FLAG_CONFIGSPECIFIC
Make the change in the specified profile only.

结果:

成功实现功能;



遗憾:不明白为什么service不能控制wdm driver service;

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐