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

分类: CPP2009-09-25 00:16 3914人阅读 评论(5) 收藏 举报
windowsservicedatabasefilterapplicationfunction

目录(?)[+]

懒人也动笔了;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 theControlService 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 ).

IIcThe 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 theDeviceIoControl .

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 usingCloseServiceHandle .� 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;

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

  1. linux设备驱动——bus、device、driver加载顺序与匹配流程

    文章目录 1. 前言 2. 概念 2.1. 数据结构 2.2. probe函数 3. bus.device.driver加载顺序 3.1. 加载方式 3.2. 加载顺序 4. device.drive ...

  2. 设备驱动模型:device, bus, driver之间的联系

    对于驱动工程师而言,在移植porting对应设备的driver时,要在devicetree中增加对应的设备节点,其中有一个compatible属性,这个属性的字符串要和driver里面的of_devi ...

  3. Windows CE设备驱动开发之电源管理

    4.7电源管理 电源管理模块管理设备电源,从而全面改进操作系统的电源使用效率:它所有设备的电源使用,同时能与不支持电源管理的应用程序及驱动程序共存. 使用电源管理可以有效的减少目标设备的电源消耗,同时 ...

  4. Linux和Windows设备驱动架构比较

    毕业后一直在学操作系统, 有时候觉得什么都懂了,有时候又觉得好像什么都不懂,但总体来说自认为对操作系统实现机制的了解比周围的人还是要多一些.去年曾花了几个星期的晚上时间断断续续翻译了这篇对Linux和 ...

  5. usb设备驱动之uvc设备

    usb设备驱动之uvc设备 声明:涉及相关内容包括v4l2框架/drivers/media/v4l2-core/,usb设备控制器驱动/drivers/usb/dwc3/,usb composite驱 ...

  6. RT-Thread pin设备驱动代码结构剖析

    硬件测试平台:正点原子潘多拉STM32L4开发板 OS内核版本:4.0.0 注意:下面的示例代码是从原子提供的例程中摘录,因此可能与最新的RT-Thread源码有出入(因为RT-Thread源码在不断 ...

  7. linux系统怎样写单片机程序,单片机知识是Linux驱动开发的基础之一以及如何学单片机...

    这是arm裸机1期加强版第1课第2.3节课程的wiki文字版. 为什么没前途也要学习单片机? 因为它是个很好的入口. 学习单片机可以让我们抛开复杂的软件结构,先掌握硬件操作,如:看原理图.芯片手册.写 ...

  8. linux内核模块编程(六)----字符设备驱动中断开发

    先给自己打个广告,本人的微信公众号正式上线了,搜索:张笑生的地盘,主要关注嵌入式软件开发,足球等等,希望大家多多关注,有问题可以直接留言给我,一定尽心尽力回答大家的问题 一 why 字符设备驱动在我们 ...

  9. 驱动程序开发:SPI设备驱动

    目录 Linux下SPI驱动简介 SPI架构概述 SPI适配器(控制器) SPI设备驱动 spi_driver注册示例 SPI 设备和驱动匹配过程 编写imc20608六轴传感器SPI驱动 设备树编写 ...

最新文章

  1. OpenCV-Python:实现人脸、人眼、嘴巴识别
  2. 在一个成熟的分布式系统中 如何下手做高可用?
  3. 特别实用的 6 款 Python 特殊文本格式处理库推荐
  4. Vue 项目上线优化
  5. Python之操作HBASE数据库
  6. paip.文件读写api php java python总结.txt
  7. 常用关系型数据库管理系统
  8. Coverity 代码静态安全扫描工具 : 认识Coverity
  9. USB总线-USB协议简介(一)
  10. 坚持分享的魅力,我超越了当年的榜样
  11. android wifi连接优先级,gogo平台靠谱吗-官方网站
  12. python normalize函数_opencv归一化函数normalize详解
  13. 读《卧底经济学(珍藏版)》- 专家是一致对外的
  14. Update....FROM...
  15. 【Python】随机漫步
  16. ChinaSkills全国职业院校技能大赛Debian样题六||本专栏基于此试题,订阅前必读!!!
  17. Ps cs6/cs5安装提示错误(37)的解决方法
  18. 【ISAR成像定标方法(2)—平动目标ISAR成像的运动补偿方法MATLAB仿真】
  19. EMO-DB 数据集的 Speech 特征提取
  20. 温控器手动模式与自动模式c语言编写,智能温控器在智能家居中的应用及实现(本科毕业论文).doc...

热门文章

  1. 适合初学Altium Designer的教学视频
  2. 二阶振荡环节的谐振频率_典型环节的频率特性二阶振荡环节-西安电子科技大学.PPT...
  3. OpenCV 分割斜体文字(包括旋转,垂直投影,水平投影,透视变换等)
  4. Django 使用QSL server数据库
  5. 使用jquery做一个简单的当月日历插件
  6. 修改banner和端口号
  7. 红帽第四季度订阅的强劲增长 整体表现超预期
  8. 脱贫帮扶绩效评价MATLAB,关于对中牟县2019年脱贫成效考核和扶贫绩效评价奖励资金项目计划安排情况公告公示...
  9. 计算机网络【标准化工作及其组织】
  10. GPRS模块为什么会低至十几元?我所经历的物联网模块国产化过程