如何用C++卸载远程Windows机器上的USB设备?已尝试多方案遇阻
解决方案:远程Windows机器USB设备卸载(C++实现)
核心思路:结合WMI+命令行解决自动挂载与挂载点问题
针对你遇到的WMI自动挂载回装、挂载点删除失败,以及旧API版本兼容等问题,以下是无需过多远程配置的可行方案:
步骤1:调整WMI流程,先卸载卷再禁用自动挂载
之前修改自动挂载返回"mountpoint is available"错误,是因为挂载点仍被占用。先通过WMI卸载目标卷,再禁用自动挂载:
HRESULT DisableAutoMountAndDismount(IWbemServices* pSvc) { IEnumWbemClassObject* pEnumerator = NULL; BSTR query = SysAllocString(L"SELECT * FROM Win32_Volume WHERE DriveType=2"); // USB卷类型标记为2 HRESULT hr = pSvc->ExecQuery( SysAllocString(L"WQL"), query, WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumerator); if (SUCCEEDED(hr)) { IWbemClassObject* pclsObj = NULL; ULONG uReturn = 0; while (pEnumerator) { hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn); if (uReturn == 0) break; // 先执行卷卸载,释放挂载点 VARIANT dismountResult; hr = pclsObj->ExecMethod(L"Dismount", 0, NULL, NULL, &dismountResult); // 禁用自动挂载,防止重新挂载 VARIANT autoMountVal; autoMountVal.vt = VT_BOOL; autoMountVal.boolVal = FALSE; hr = pclsObj->Put(L"AutoMount", 0, &autoMountVal, 0); VariantClear(&dismountResult); pclsObj->Release(); } pEnumerator->Release(); } SysFreeString(query); return hr; }
步骤2:通过WMI执行USB设备弹出
使用Win32_DiskDrive类的EjectMedia()方法,精准定位USB存储设备并执行弹出:
HRESULT EjectTargetUSBDevice(IWbemServices* pSvc) { IEnumWbemClassObject* pEnumerator = NULL; BSTR query = SysAllocString(L"SELECT * FROM Win32_DiskDrive WHERE InterfaceType='USB'"); HRESULT hr = pSvc->ExecQuery( SysAllocString(L"WQL"), query, WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumerator); if (SUCCEEDED(hr)) { IWbemClassObject* pclsObj = NULL; ULONG uReturn = 0; while (pEnumerator) { hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn); if (uReturn == 0) break; VARIANT ejectResult; hr = pclsObj->ExecMethod(L"EjectMedia", 0, NULL, NULL, &ejectResult); // 验证弹出结果 if (ejectResult.vt == VT_BOOL && ejectResult.boolVal == TRUE) { // 弹出成功,可添加日志或后续逻辑 } VariantClear(&ejectResult); pclsObj->Release(); } pEnumerator->Release(); } SysFreeString(query); return hr; }
步骤3:强制清理挂载点(解决占用错误)
若仍出现挂载点占用问题,可通过WMI远程调用diskpart命令删除挂载点:
- 本地生成临时脚本
clean_mount.txt:select volume <目标卷号> remove all - 通过WMI的
Win32_Process类启动远程进程执行命令:HRESULT RunRemoteDiskpart(IWbemServices* pSvc, const wchar_t* scriptPath) { IWbemClassObject* pProcessClass = NULL; HRESULT hr = pSvc->GetObject(SysAllocString(L"Win32_Process"), 0, NULL, &pProcessClass, NULL); if (SUCCEEDED(hr)) { IWbemClassObject* pInParamsDefinition = NULL; hr = pProcessClass->GetMethod(L"Create", 0, &pInParamsDefinition, NULL); IWbemClassObject* pInParams = NULL; hr = pInParamsDefinition->SpawnInstance(0, &pInParams); VARIANT cmdLine; cmdLine.vt = VT_BSTR; std::wstring cmd = L"diskpart /s "; cmd += scriptPath; cmdLine.bstrVal = SysAllocString(cmd.c_str()); hr = pInParams->Put(L"CommandLine", 0, &cmdLine, 0); VARIANT vtResult; hr = pSvc->ExecMethod(SysAllocString(L"Win32_Process"), L"Create", 0, NULL, pInParams, &vtResult, NULL); VariantClear(&cmdLine); VariantClear(&vtResult); pInParams->Release(); pInParamsDefinition->Release(); pProcessClass->Release(); } return hr; }
替代方案:C++封装PowerShell远程调用
针对Windows 8+版本,可绕过旧API限制,在C++中调用PowerShell远程命令卸载设备:
HRESULT ExecuteRemotePSScript(const wchar_t* remoteMachine) { std::wstring psCmd = L"Invoke-Command -ComputerName "; psCmd += remoteMachine; psCmd += L" -ScriptBlock { Get-PnpDevice -Class 'DiskDrive' | Where-Object { $_.InstanceId -like 'USB*' } | Remove-PnpDevice -Confirm:$false }"; STARTUPINFOW si = { sizeof(si) }; PROCESS_INFORMATION pi; BOOL success = CreateProcessW( L"C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe", const_cast<wchar_t*>(psCmd.c_str()), NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); if (success) { WaitForSingleObject(pi.hProcess, INFINITE); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); return S_OK; } return HRESULT_FROM_WIN32(GetLastError()); }
注:此方案需远程机器开启PowerShell远程管理,可通过WMI提前执行
Enable-PSRemoting -Force完成轻度配置。
关键注意事项
- 所有远程操作需管理员权限,且本地与远程机器需在同一域或已建立信任关系。
- 执行弹出前需确保远程机器无进程占用USB设备文件,否则会弹出失败。
- 优先选择WMI或PowerShell方案,避免使用
CM_Connect_MachineA这类Windows 8+废弃API。
内容的提问来源于stack exchange,提问作者Naveen CS
相关产品推荐
相关产品推荐

