You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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命令删除挂载点:

  1. 本地生成临时脚本clean_mount.txt:
    select volume <目标卷号>
    remove all
    
  2. 通过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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 06:05:37