天天看點

windows 裝置管理器中的裝置控制

控制主要功能程式:

控制基本裝置:

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盤