想要实现类似设备管理器的功能,其实也不是很难,无非就是调用一些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。 从设备管理器中,可以验证我们的做法。
|
Code
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 );
}
Code
#include <SetupAPI.h>
#include <cfgmgr32.h> // cfgmgr32.h 在Microsoft Windows 2000 DDK 中.
#pragma comment(lib,"setupapi.lib")
BOOL IsDisableable(DWORD dwDevID, HDEVINFO hDevInfo) ;
BOOL IsDisabled(DWORD dwDevID, HDEVINFO hDevInfo) ;
BOOL StateChange( DWORD dwNewState, DWORD dwDevID, HDEVINFO hDevInfo) ;
//////////////////////////////////////////////////////////////////////////
// 获得设备注册表中的内容
//////////////////////////////////////////////////////////////////////////
BOOL GetRegistryProperty( HDEVINFO DeviceInfoSet,
PSP_DEVINFO_DATA DeviceInfoData,
ULONG Property,
PVOID Buffer,
PULONG Length )
{
while ( !SetupDiGetDeviceRegistryProperty( DeviceInfoSet,
DeviceInfoData,
Property,
NULL,
(BYTE *)*(TCHAR **)Buffer,
*Length,
Length))
{
// 长度不够则重新分配缓冲区
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
if (*(LPTSTR *)Buffer)
LocalFree(*(LPTSTR *)Buffer);
*(LPTSTR *)Buffer = (PCHAR)LocalAlloc(LPTR,*Length);
}
else
{
return false;
}
}
return (BOOL)(*(LPTSTR *)Buffer)[0];
}
BOOL EnableDevice(DWORD dwDevID, HDEVINFO hDevInfo)
{
return StateChange(DICS_ENABLE,dwDevID,hDevInfo);
}
BOOL DisableDevice(DWORD dwDevID, HDEVINFO hDevInfo)
{
return StateChange(DICS_DISABLE,dwDevID,hDevInfo);
}
BOOL ControlDevice(DWORD dwDevID, HDEVINFO hDevInfo)
{
BOOL bCanDisable;
bCanDisable = (IsDisableable(dwDevID,hDevInfo) && (!IsDisabled(dwDevID,hDevInfo)));
if(bCanDisable)
return DisableDevice(dwDevID,hDevInfo);
else
return EnableDevice(dwDevID,hDevInfo);
}
void EnumNetCards()
{
DWORD Status, Problem;
LPTSTR Buffer = NULL;
DWORD BufSize = 0;
// 返回所有设备信息
HDEVINFO hDevInfo = SetupDiGetClassDevs(NULL,NULL,0,DIGCF_PRESENT|DIGCF_ALLCLASSES) ;
if (INVALID_HANDLE_VALUE == hDevInfo )
return;
SP_DEVINFO_DATA DeviceInfoData = {sizeof(SP_DEVINFO_DATA)};
//////////////////////////////////////////////////////////////////////////
// 枚举设备
//////////////////////////////////////////////////////////////////////////
for ( DWORD DeviceId=0;
SetupDiEnumDeviceInfo( hDevInfo,DeviceId,&DeviceInfoData);
DeviceId++)
{
// 获得设备的状态
if (CM_Get_DevNode_Status(&Status, &Problem, DeviceInfoData.DevInst ,0) != CR_SUCCESS)
continue;
// 获取设备类名
TCHAR szDevName [MAX_PATH] = _T("") ;
if (GetRegistryProperty(hDevInfo, &DeviceInfoData, SPDRP_CLASS , &Buffer, (PULONG)&BufSize))
{
lstrcpyn( szDevName, Buffer, MAX_PATH ) ;
}
if ( lstrcmp( szDevName, _T("Net") ) == 0 )
{
TCHAR szName [MAX_PATH] = _T("") ;
if (GetRegistryProperty(hDevInfo, &DeviceInfoData, SPDRP_ENUMERATOR_NAME , &Buffer, (PULONG)&BufSize))
{
lstrcpyn( szName, Buffer, MAX_PATH ) ;
}
if ( lstrcmp( szName, _T("ROOT") ) != 0 )
{
if (GetRegistryProperty(hDevInfo, &DeviceInfoData, SPDRP_DRIVER , &Buffer, (PULONG)&BufSize))
{
lstrcpyn( szName, Buffer, MAX_PATH ) ;
// 获取设备描述
if (GetRegistryProperty(hDevInfo, &DeviceInfoData, SPDRP_DEVICEDESC , &Buffer, (PULONG)&BufSize))
{
lstrcpyn( szName, Buffer, MAX_PATH ) ;
if(ControlDevice(DeviceId,hDevInfo))
{
printf("Successful\n");
}
else
{
printf("FAILED\n");
}
}
}
}
}
}
SetupDiDestroyDeviceInfoList(hDevInfo);
}
BOOL StateChange( DWORD dwNewState, DWORD dwDevID, HDEVINFO hDevInfo)
{
SP_PROPCHANGE_PARAMS PropChangeParams;
SP_DEVINFO_DATA DevInfoData = {sizeof(SP_DEVINFO_DATA)};
SP_DEVINSTALL_PARAMS devParams;
//查询设备信息
if (!SetupDiEnumDeviceInfo( hDevInfo, dwDevID, &DevInfoData))
{
OutputDebugString("SetupDiEnumDeviceInfo FAILED");
return FALSE;
}
//设置设备属性变化参数
PropChangeParams.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
PropChangeParams.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
PropChangeParams.Scope = DICS_FLAG_GLOBAL; //使修改的属性保存在所有的硬件属性文件
PropChangeParams.StateChange = dwNewState;
PropChangeParams.HwProfile = 0;
//改变设备属性
if (!SetupDiSetClassInstallParams( hDevInfo,
&DevInfoData,
(SP_CLASSINSTALL_HEADER *)&PropChangeParams,
sizeof(PropChangeParams)))
{
OutputDebugString("SetupDiSetClassInstallParams FAILED");
return FALSE;
}
PropChangeParams.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
PropChangeParams.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
PropChangeParams.Scope = DICS_FLAG_CONFIGSPECIFIC;//使修改的属性保存在指定的属性文件
PropChangeParams.StateChange = dwNewState;
PropChangeParams.HwProfile = 0;
//改变设备属性并调用安装服务
if (!SetupDiSetClassInstallParams( hDevInfo,
&DevInfoData,
(SP_CLASSINSTALL_HEADER *)&PropChangeParams,
sizeof(PropChangeParams)) ||
!SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, hDevInfo, &DevInfoData))
{
OutputDebugString("SetupDiSetClassInstallParams or SetupDiCallClassInstaller FAILED");
return TRUE;
}
else
{
//判断是否需要重新启动
devParams.cbSize = sizeof(devParams);
if (!SetupDiGetDeviceInstallParams( hDevInfo, &DevInfoData, &devParams))
{
OutputDebugString("SetupDiGetDeviceInstallParams FAILED");
return FALSE;
}
if (devParams.Flags & (DI_NEEDRESTART|DI_NEEDREBOOT))
{
OutputDebugString("Need Restart Computer");
return TRUE;
}
return TRUE;
}
}
BOOL IsDisableable(DWORD dwDevID, HDEVINFO hDevInfo)
{
SP_DEVINFO_DATA DevInfoData = {sizeof(SP_DEVINFO_DATA)};
DWORD dwDevStatus,dwProblem;
if(!SetupDiEnumDeviceInfo(hDevInfo,dwDevID,&DevInfoData))
{
OutputDebugString("SetupDiEnumDeviceInfo FAILED");
return FALSE;
}
//查询设备状态
if(CM_Get_DevNode_Status(&dwDevStatus,&dwProblem,DevInfoData.DevInst,0)!=CR_SUCCESS)
{
OutputDebugString("CM_GET_DevNode_Status FAILED");
return FALSE;
}
return ((dwDevStatus & DN_DISABLEABLE) && (dwProblem != CM_PROB_HARDWARE_DISABLED));
}
BOOL IsDisabled(DWORD dwDevID, HDEVINFO hDevInfo)
{
SP_DEVINFO_DATA DevInfoData = {sizeof(SP_DEVINFO_DATA)};
DWORD dwDevStatus,dwProblem;
if(!SetupDiEnumDeviceInfo(hDevInfo,dwDevID,&DevInfoData))
{
OutputDebugString("SetupDiEnumDeviceInfo FAILED");
return FALSE;
}
//查询设备状态
if(CM_Get_DevNode_Status(&dwDevStatus,&dwProblem,DevInfoData.DevInst,0)!=CR_SUCCESS)
{
OutputDebugString("CM_GET_DevNode_Status FAILED");
return FALSE;
}
return ((dwDevStatus & DN_HAS_PROBLEM) && (dwProblem == CM_PROB_DISABLED));
}
int main(int argc, char* argv[])
{
EnumNetCards() ;
return 0 ;
}
source: http://yushui213.blogcn.com/diary,11184830.shtml