控制主要功能程式:
控制基本裝置:
GUID guid;
BOOL StateChange(HDEVINFO hDevInfo,DWORD dwNewState, DWORD dwDevID)
{
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))
{
int nErr = GetLastError();
OutputDebugString("SetupDiSetClassInstallParams or SetupDiCallClassInstaller FAILED");
return FALSE;
}
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;
}
}
注意事項:
1.32位系統和64位系統對應要編譯不同的程式。Setup..序列函數區分系統的
2. win7以後的系統開發時,一些API函數需要程式有管理者權限 如Setup..族,編譯時 項目-屬性-連接配接器-清單檔案-UAC執行級别 選擇:requireAdministrator (/level='requireAdministrator') ,程式就會以管理者權限運作。
3.裝置句柄在程式中被占用時,會出現禁用函數成功傳回。需要重新開機電腦生效的情況。實際是禁用不成功,目前沒有找到問題,采用函數setup_remove移除了禁用失敗的裝置(setup_remove在裝置被占用時移除也會失敗)。
2018年7月11日14:15:21 BEGIN
找到新的方法了:使用DeviceIoControl彈出U盤儲存設備
#define LOCK_TIMEOUT 10000 // 10 Seconds
#define LOCK_RETRIES 20
int CDeviceMng::UninstallUsb(char *discId)
{
DWORD accessMode = GENERIC_WRITE | GENERIC_READ;
DWORD shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
HANDLE hDevice;
DWORD retu = 0;
DWORD dwError;
DWORD dwBytesReturned;
DWORD dwSleepAmount;
int nTryCount;
char szDriv[10];
bool bResult;
if(discId == NULL){
return 0;
}
dwSleepAmount = LOCK_TIMEOUT/LOCK_RETRIES;
sprintf(szDriv,"\\\\.\\%s:",discId);
hDevice = CreateFile(szDriv,accessMode,shareMode,NULL,OPEN_EXISTING,0,NULL);
if(hDevice == INVALID_HANDLE_VALUE){
//printf("uninstallusb createfile failed error:%d\n",GetLastError());
return -1;
}
#if 0
//此循環是用于鎖定要彈出的U盤裝置,如果U盤在使用,則循環等待
// Do this in a loop until a timeout period has expired
for(nTryCount = 0;nTryCount < LOCK_RETRIES;nTryCount++){
if(DeviceIoControl(hDevice,FSCTL_LOCK_VOLUME,NULL,0,NULL,0,&dwBytesReturned,NULL)){
break;
}
}
//解除安裝U盤卷,不論是否在使用
dwBytesReturned = 0;
if(!DeviceIoControl(hDevice,FSCTL_DISMOUNT_VOLUME,NULL,0,NULL,0,&dwBytesReturned,NULL)){
printf("deviceIoConrol FSCTL_DISMOUNT_VOLUME failed\n");
}
#endif
dwBytesReturned = 0;
PREVENT_MEDIA_REMOVAL PMRBuffer;
PMRBuffer.PreventMediaRemoval = FALSE;
if(!DeviceIoControl(hDevice,IOCTL_STORAGE_MEDIA_REMOVAL,&PMRBuffer,sizeof(PREVENT_MEDIA_REMOVAL),NULL,0,&dwBytesReturned,NULL)){
//DEBUG_LOG("DeviceIoControl IOCTL_STORAGE_MEDIA_REMOVAL failed:%d\n",GetLastError());
}
bResult = DeviceIoControl(hDevice,IOCTL_STORAGE_EJECT_MEDIA,NULL,0,NULL,0,&retu,NULL);
if(!bResult){
CloseHandle(hDevice);
//DEBUG_LOG("uninstallusb DeviceIoControl failed error:%d\n",GetLastError());
return -1;
}
CloseHandle(hDevice);
return 0;
}
2018年7月11日14:15:21 END
指定U盤裝置禁用
代碼:
BOOL CEnableUsbDeviceApp::CtrlDevice( const TCHAR* lpszInterfaceGuid,const TCHAR* lpszDevicePath,const TCHAR* lpszAction )
{
GUID guid;
HDEVINFO info;
DWORD devindex;
SP_INTERFACE_DEVICE_DATA ifdata;
BOOL bRet=FALSE;
if (!lpszInterfaceGuid || !lpszDevicePath || !lpszAction)
{
return FALSE;
}
#ifdef _UNICODE
RPC_STATUS status=UuidFromString((RPC_WSTR)lpszInterfaceGuid,&guid);
#else
RPC_STATUS status=UuidFromString((RPC_CSTR)lpszInterfaceGuid,&guid);
#endif
if(status!=RPC_S_OK) return FALSE;
info = SetupDiGetClassDevs(&guid,NULL,NULL,DIGCF_ALLCLASSES|DIGCF_INTERFACEDEVICE);
if(INVALID_HANDLE_VALUE==info)
{
return FALSE;
}
ifdata.cbSize = sizeof(ifdata);
for(devindex = 0 ; SetupDiEnumDeviceInterfaces(info,NULL,&guid,devindex,&ifdata) ; ++devindex)
{
DWORD needed=0;
PSP_INTERFACE_DEVICE_DETAIL_DATA detail=NULL;
SP_DEVINFO_DATA did;
SetupDiGetDeviceInterfaceDetail(info,&ifdata,NULL,0,&needed,NULL);
if(!needed)
{
continue;
}
detail = (PSP_INTERFACE_DEVICE_DETAIL_DATA)new char[needed+2];
if(detail==NULL)
{
continue;
}
detail->cbSize=sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA);
memset(&did,0x00,sizeof(SP_DEVINFO_DATA));
did.cbSize = sizeof(SP_DEVINFO_DATA);
if(!SetupDiGetDeviceInterfaceDetail(info,&ifdata,detail,needed,&needed,&did))
{
delete[](char*)detail;
detail=NULL;
continue;
}
if (_tcsicmp(detail->DevicePath,lpszDevicePath)==0)
{
DWORD Status, Problem;
if (CR_SUCCESS == CM_Get_DevNode_Status(&Status, &Problem,did.DevInst,0))
{
if (_tcsicmp(lpszAction,_T("eject"))==0)
{
//if (Status & DN_REMOVABLE)
{
PNP_VETO_TYPE VetoType = PNP_VetoTypeUnknown;
TCHAR VetoName[MAX_PATH];
VetoName[0] = 0;
// get drives's parent, e.g. the USB bridge, the SATA port, an IDE channel with two drives!
DEVINST DevInstParent = 0;
CONFIGRET res = CM_Get_Parent(&DevInstParent, did.DevInst, 0);
for ( long tries=1; tries<=3; tries++ ) // sometimes we need some tries...
{
VetoName[0] = 0;
res = CM_Request_Device_Eject(DevInstParent, &VetoType, VetoName, MAX_PATH, 0);
if(res!=CR_SUCCESS)
{
MyoutputDebugString(_T("CM_Request_Device_Eject call fail disable"));
res = CM_Query_And_Remove_SubTree(DevInstParent, &VetoType, VetoName, MAX_PATH, CM_REMOVE_NO_RESTART); // CM_Query_And_Remove_SubTreeA is not implemented under W2K!
}
//MyoutputDebugString(_T("CM_Query_And_Remove_SubTree call fail disable"));
if (res==CR_SUCCESS && VetoType==PNP_VetoTypeUnknown)
{
MyoutputDebugString(_T("禁用成功"));
bRet=TRUE;
break;
}
MyoutputDebugString(_T("禁用3次循環"));
Sleep(500); // required to give the next tries a chance!
}
//如果退出仍然失敗,那麼禁用
if (!bRet)
{
MyoutputDebugString(_T("如果退出仍然失敗,那麼禁用"));
SP_PROPCHANGE_PARAMS PropChangeParams;
PropChangeParams.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
PropChangeParams.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
PropChangeParams.StateChange =DICS_DISABLE;
PropChangeParams.Scope = DICS_FLAG_CONFIGSPECIFIC;
PropChangeParams.HwProfile = 0;
if(SetupDiSetClassInstallParams(info,&did,(SP_CLASSINSTALL_HEADER *)&PropChangeParams,sizeof(PropChangeParams)))
{
MyoutputDebugString(_T("SetupDiSetClassInstallParams call successful disable"));
if (SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,info,&did))
{
MyoutputDebugString(_T("SetupDiCallClassInstaller call successful disable"));
bRet=TRUE;
}
}
}
}
}
else if (_tcsicmp(lpszAction,_T("enable"))==0)
{
if ((Status & DN_HAS_PROBLEM) && (Problem==CM_PROB_DISABLED))
{
SP_PROPCHANGE_PARAMS PropChangeParams;
PropChangeParams.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
PropChangeParams.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
PropChangeParams.StateChange =DICS_ENABLE;
PropChangeParams.Scope = DICS_FLAG_CONFIGSPECIFIC;
PropChangeParams.HwProfile = 0;
if(SetupDiSetClassInstallParams(info,&did,(SP_CLASSINSTALL_HEADER *)&PropChangeParams,sizeof(PropChangeParams)))
{
MyoutputDebugString(_T("SetupDiSetClassInstallParams call successful enable"));
if (SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,info,&did))
{
MyoutputDebugString(_T("SetupDiCallClassInstaller call successful enable"));
bRet=TRUE;
}
}
}
}
else if (_tcsicmp(lpszAction,_T("disable"))==0)
{
if (!((Status & DN_HAS_PROBLEM) && (Problem==CM_PROB_DISABLED)))
{
SP_PROPCHANGE_PARAMS PropChangeParams;
//test
設定裝置屬性變化參數
PropChangeParams.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
PropChangeParams.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
PropChangeParams.Scope = DICS_FLAG_GLOBAL; //使修改所有的硬體屬性檔案
PropChangeParams.StateChange = DICS_DISABLE;
PropChangeParams.HwProfile = 0;
//改變裝置屬性
if (SetupDiSetClassInstallParams( info,
&did,
(SP_CLASSINSTALL_HEADER *)&PropChangeParams,
sizeof(PropChangeParams)))
{
MyoutputDebugString(_T("SetupDiSetClassInstallParams DICS_FLAG_GLOBAL successful"));
//return FALSE;
}
//test end
PropChangeParams.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
PropChangeParams.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
PropChangeParams.StateChange =DICS_DISABLE;
PropChangeParams.Scope = DICS_FLAG_CONFIGSPECIFIC;
PropChangeParams.HwProfile = 0;
if(SetupDiSetClassInstallParams(info,&did,(SP_CLASSINSTALL_HEADER *)&PropChangeParams,sizeof(PropChangeParams)))
{
MyoutputDebugString(_T("SetupDiSetClassInstallParams call successful disable"));
if (SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,info,&did))
{
MyoutputDebugString(_T("SetupDiCallClassInstaller call successful disable"));
bRet=TRUE;
}
}
//test
SP_DEVINSTALL_PARAMS devParams;
devParams.cbSize = sizeof(devParams);
if (!SetupDiGetDeviceInstallParams( info, &did, &devParams))
{
MyoutputDebugString(_T("SetupDiGetDeviceInstallParams FAILED"));
continue;
}
if (devParams.Flags & (DI_NEEDRESTART|DI_NEEDREBOOT))
{
OutputDebugString(_T("Need Restart Computer"));
if(SetupDiRemoveDevice(info,&did)) //禁用不成功就移除U盤
{
OutputDebugString(_T("SetupDiRemoveDevice successful"));
}
}
//test end
}
}
}
delete[](char*)detail;
detail=NULL;
needed=0;
break;
}
else
{
delete[](char*)detail;
detail=NULL;
continue;
}
}
SetupDiDestroyDeviceInfoList(info);
return bRet;
}
U盤禁用與裝置禁用是一樣的 ,這裡用裝置執行個體路徑來區分指定U盤