整理SetupDixxx函数

    前几天写了两篇关于Pnp管理器的博文,在继续写相关博文前我想整理一下Pnp管理器在用户态导出的功能,也就是我们熟悉的windows设备管理器。为什么说windows设备管理器是Pnp管理器导出在用户态的功能?因为当系统中加入设备时,Pnp管理器会在系统中搜索已有驱动能否匹配该设备(通过Inf文件的硬件列表和兼容列表)。如果匹配到一个驱动,那就执行服务端安装;如果很不幸,没有匹配到合适的驱动,就会执行客户端安装。客户端安装就是xp下的新硬件向导。这些动作也可以手动触发,本文整理实现这些动作的程序。实现这些功能依赖于MS提供的SetupDI系列API,这类接口有百来个,一一列举不大可能,只能归纳出一些常用用法。

    1.先来看下实现设备管理器的"扫描检测硬件改动"的功能

#include <windows.h>
#include <cfgmgr32.h>
#include <setupapi.h>
#pragma comment(lib,"cfgmgr32.lib")

int main(int argc, char* argv[])
{
    char LocalComputer[MAX_PATH];
    DWORD Size = MAX_PATH - 1;
    GetComputerName(LocalComputer + 2, &Size);
    LocalComputer[0] = '\\';
    LocalComputer[1] = '\\';


    CONFIGRET cr;
    HMACHINE m_hMachine;
    cr = CM_Connect_Machine(LocalComputer, &m_hMachine);
    
    if (cr != CR_SUCCESS)
        return -1;


    DEVNODE dnRoot;
    CONFIGRET status;
    status = CM_Locate_DevNode_Ex(&dnRoot, NULL, 0, m_hMachine);
    if(status != CR_SUCCESS)
        return -1;
    
    status = CM_Reenumerate_DevNode(dnRoot,
    CM_REENUMERATE_RETRY_INSTALLATION|CM_REENUMERATE_NORMAL);
    if(status != CR_SUCCESS)
        return -1;

    CM_Disconnect_Machine(m_hMachine);
        return 0;
}

    这段代码用ddk自带的编译环境编译,要不然会提示找不到CM_Connect_Machine等函数。编译完成后以管理员运行。为了能在设备管理器里看到明显的现象,我编译ddk例子中自带的蓝牙设备驱动,然后把它加入到设备管理器中(具体操作参考ddk/src/bthecho下的Readme),安装后把设备的驱动卸载掉,然后运行程序,就可以看到设备管理器刷新动作


    2.以USB类为例,调用SetupDixxx函数,枚举属于USB类设备下所有设备。

DEFINE_GUID(GUID_DEVINTERFACE_USB_DEVICE,
			0x36fc9e60,0xc465,0x11cf,0x80,0x56,0x44,0x45,0x53,0x54,0x00,0x00);
			
int main(int argc, char* argv[])
{
	HDEVINFO   hDevInfo;
	SP_DEVINFO_DATA   DeviceInfoData;
	DWORD idx;
        //通过设备类guid 获得设备接口类句柄 系统以Device Information Sets的形式管理一类设备
        //具体信息参考msdn:https://msdn.microsoft.com/en-us/library/ff541247
	hDevInfo = SetupDiGetClassDevs(
						(LPGUID)&GUID_DEVINTERFACE_USB_DEVICE,
						0,0,
						DIGCF_PRESENT);
	if(hDevInfo == INVALID_HANDLE_VALUE)
		return -1;
	//用设备类句柄枚举设备
	DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
	for(idx=0;
	    SetupDiEnumDeviceInfo(hDevInfo, idx, &DeviceInfoData);
	    idx++)
	{
		LPTSTR buffer = NULL;  
                DWORD   buffersize = 0;     
                ULONG   len;       
		//获得设备在注册表中的信息,分两步走,第一次获得承载设备信息的缓存区大小 第二次获得设备描述信息
    DWORD regType;
    while (!SetupDiGetDeviceRegistryProperty(
            hDevInfo,
            &DeviceInfoData,
            SPDRP_HARDWAREID,
            &regType,
            (PBYTE)buffer,
            buffersize,
            &buffersize))
    {
        if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
        {
            // Change the buffer size.
            if (buffer) LocalFree(buffer);
            buffer = (LPTSTR)LocalAlloc(LPTR,buffersize);
        }
        else
        {
            // Insert error handling here.
            break;
        }
    }
		
		printf("%s\n",buffer);
    //获得设备实例名		
    while (!SetupDiGetDeviceRegistryProperty(
            hDevInfo,
            &DeviceInfoData,
            SPDRP_DEVICEDESC,
            &regType,
            (PBYTE)buffer,
            buffersize,
            &buffersize))
    {
        if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
        {
            // Change the buffer size.
            if (buffer) LocalFree(buffer);
            buffer = (LPTSTR)LocalAlloc(LPTR,buffersize);
        }
        else
        {
            // Insert error handling here.
            break;
        }
    }
    
    printf("%s\n",buffer);
    }
}
这段代码不是很难,最麻烦的是查找设备类的classguid,最简单的办法是通过设备管理器查找。对于这段程序通过设备管理器-通用串行总线控制器-USB Root Hub-属性-详细信息-设备类GUID的方式来获取。下面截图是程序输出:


3.既然能找到USB设备,能不能把指定设备弹出?比如U盘?可以把这段代码加到刚才的循环中

    cr = CM_Get_DevNode_Status(&ulStatus,     
                              &ulProblemNumber,     
                              DeviceInfoData.DevInst,     
                              0);	
		
		if(CR_SUCCESS != cr)
		    continue;
	   
	  //   DN_DISABLEABLE   or   DN_REMOVABLE     
	  if((DN_DISABLEABLE&ulStatus) != 0)   
	  	printf("HAS   -   DN_DISABLEABLE()[%x]/n",   DN_DISABLEABLE   &   ulStatus);     
	  else  
	        continue;       
	  if((DN_REMOVABLE&ulStatus) != 0)    
	  	printf("HAS   -   DN_REMOVABLE()[%x]/n",   DN_REMOVABLE   &   ulStatus);     
	  else    
	  	continue;      
	  	
	  len   =   MAX_PATH;     
    //移除设备      
    cr   =   CM_Request_Device_Eject(     
                    DeviceInfoData.DevInst,     
                    &pnpvietotype,     
                    vetoname,     
                    len,     
                    0     
                    );     
    if(CR_SUCCESS == cr)    
    	printf("OK   -   CM_Request_Device_Eject()[%d]/n",   cr);     
    else  
    	printf("ERROR   -   CM_Request_Device_Eject()[%d]/n",   cr);   


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值