VC++实现启用与停用设备

前些日子在研究USB设备,就顺便研究了一些如何在应用程序实现USB设备的启用与停用,然后稍微深入,于是有了本文。

想要实现类似设备管理器的功能,其实也不是很难,无非就是调用一些API函数,就像本文描述的,采用的API函数就是SetupDi系列的函数。不过这类函数有很多,具体的请参见MSDN,而实现设备启用、停用仅需要用到的就只有5个函数:
       SetupDiGetClassDevs                   // 获取设备信息集
       SetupDiEnumDeviceInfo                 // 从设备信息集中枚举每个设备的具体信息
       SetupDiGetDeviceRegistryProperty      // 从注册表中读取PnP设备的属性
       SetupDiSetClassInstallParams          // 设置(包括取消)设备类的安装参数
       SetupDiCallClassInstaller             // 安装指定设备
以上函数均在setupapi.h头文件中声明,该头文件包含在setupapi.lib函数库中(使用以上函数前需要声明这个头文件)。

接下来就是如何实现设备的启用与停用。
从原理上讲,设备的启用与停用其实就是对该设备进行重安装。

首先,我们需要声明两个变量用来保存指定设备类的属性信息:
    HDEVINFO        m_hDevInfo;              // 类似设备句柄,以下暂且称为设备句柄
    SP_DEVINFO_DATA m_DeviceInfoData;        // 设备详细属性信息

然后调用SetupDiGetClassDevs函数获取设备句柄的值。(在这个函数中,需要指定设备类的GUID,如果不清楚这个GUID,可以在相应的安装文件.inf中查找。注意:是设备类的GUID,不是设备的GUID!)

接着循环使用SetupDiEnumDeviceInfo函数枚举对应设备类中的设备,并使用SetupDiGetDeviceRegistryProperty函数获取得到的设备的详细信息,进行判断是否为所需的设备(判断的方式有多种,具体参考MSDN,本文采用设备描述进行判断)。
一旦枚举结束(即枚举不成功,而且用GetLastError()可以得到错误码259)即可退出循环。当然如果找到设备,即可break退出。

如果找到对应的设备,就调用SetupDiSetClassInstallParams函数设置安装的属性。这里有个注意的地方需要详细说明一下:
SetupDiSetClassInstallParams的函数原型如下:
WINSETUPAPI BOOL WINAPI
  SetupDiSetClassInstallParams(
    IN HDEVINFO  DeviceInfoSet,
    IN PSP_DEVINFO_DATA  DeviceInfoData,  OPTIONAL
    IN PSP_CLASSINSTALL_HEADER  ClassInstallParams,  OPTIONAL
    IN DWORD  ClassInstallParamsSize
    );
注意第三个参数PSP_CLASSINSTALL_HEADER  ClassInstallParams,
这里我们不采用这个结构,而是采用另外一个结构:SP_PROPCHANGE_PARAMS
并在这个结构中,
设置ClassInstallHeader字段中(我们发现这个字段也是一个结构,就是PSP_CLASSINSTALL_HEADER结构)的InstallFunction字段值为DIF_PROPERTYCHANGE,
设置StateChange值为DICS_ENABLE(该值为启用,若是停用则为DICS_DISABLE)
然后采用强行转换将其转为PSP_CLASSINSTALL_HEADER结构。

最后,调用SetupDiCallClassInstaller函数执行设备的安装(即:启用或者停用),注意该函数第一个参数值应为DIF_PROPERTYCHANGE。
从设备管理器中,可以验证我们的做法。

以下贴出我程序中的主要源码。

  BOOL               rlt            = FALSE;
  CString            csFriendlyName = myDevcieName;                           // 请修改该值
  GUID               devGUID        = {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}; // 这个值不用我再说了吧?!
  HDEVINFO           m_hDevInfo     = INVALID_HANDLE_VALUE;
  SP_DEVINFO_DATA    m_DeviceInfoData;

  RtlZeroMemory(&m_DeviceInfoData, sizeof(SP_DEVINFO_DATA));                  // 初始化m_DeviceInfoData,当然这只是范例,
  m_DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);                          // 有其他初始化的方法,大家见仁见智

  m_hDevInfo = SetupDiGetClassDevs(&devGUID,0,0,DIGCF_PRESENT );
 
  for (DWORD i = 0; SetupDiEnumDeviceInfo ( m_hDevInfo, i, &m_DeviceInfoData ); i++ )
  {
         DWORD DataT;
         LPTSTR buffer  = NULL;
         DWORD buffersize = 0;
        
         while ( !SetupDiGetDeviceRegistryProperty
              (
                   m_hDevInfo,
                   &m_DeviceInfoData,
                   SPDRP_DEVICEDESC,
                   &DataT,
                   (PBYTE)buffer,
                   buffersize,
                   &buffersize
         ) )
        {
            if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
            {
                 // Change the buffer size.
                 if (buffer) 
                 {
                       LocalFree(buffer);
                 }
                 buffer = (char*)LocalAlloc(LPTR,buffersize);
            }
            else
            {
                 break;
            }
        }

        if ( ( buffer != NULL ) && ( csFriendlyName.Find ( buffer, 0 ) != ( -1 ) ) )
        {
            if (buffer) 
            {
                 LocalFree(buffer);
            }
            break;
        }
                
        if (buffer) 
        {
            LocalFree(buffer);
        }
  }

  SP_PROPCHANGE_PARAMS propChange = { sizeof ( SP_CLASSINSTALL_HEADER ) };
  propChange.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
  propChange.Scope = DICS_FLAG_GLOBAL;
  propChange.StateChange = DICS_ENABLE;   // 启用,或是停用,请使用DICS_DISABLE

  if (m_DeviceInfoData.DevInst != NULL)
  {
        rlt = SetupDiSetClassInstallParams
        (      
                m_hDevInfo, 
                &m_DeviceInfoData, 
                ( SP_CLASSINSTALL_HEADER * ) &propChange, 
                sizeof ( propChange ) 
        );
  }

  if ( rlt )
  {
        rlt = SetupDiCallClassInstaller ( DIF_PROPERTYCHANGE, m_hDevInfo, &m_DeviceInfoData );
  }

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值