首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

Windows 裝置管理:以 SetupAPI 啟用/禁用光碟機、軟碟機、USB 裝置

     編輯:關於C++

核心 API 流程

  1. SetupDiGetClassDevs:取得裝置資訊集合 (依類別 GUID)。
  2. SetupDiEnumDeviceInfo:列舉集合中每個裝置。
  3. SetupDiSetClassInstallParams + SetupDiCallClassInstaller:發送 DIF_PROPERTYCHANGE 啟用/禁用。

關鍵 GUID 常數

裝置類別GUID
軟碟機控制器{4D36E980-E325-11CE-BFC1-08002BE10318}
光碟機{4D36E965-E325-11CE-BFC1-08002BE10318}
USB 控制器{36FC9E60-C465-11CF-8056-444553540000}

更多 GUID 見 devguid.h 或登錄表 HKLM\SYSTEM\CurrentControlSet\Control\Class\。

完整實作程式碼


#include <windows.h>
#include <setupapi.h>
#include <shlwapi.h>
#pragma comment(lib, "setupapi.lib")
#pragma comment(lib, "shlwapi.lib")

void FormatMsg(DWORD err, LPTSTR* msg) {
    FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,
        NULL, err, MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED), (LPTSTR)msg, 0, NULL);
    if (!*msg) { // 嘗試 netmsg.dll
        HMODULE h = LoadLibraryEx(_T("netmsg.dll"), NULL, DONT_RESOLVE_DLL_REFERENCES);
        if (h) {
            FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_FROM_SYSTEM,
                h, err, MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED), (LPTSTR)msg, 0, NULL);
            FreeLibrary(h);
        }
    }
}

BOOL ChangeStatus(DWORD newState, DWORD index, HDEVINFO hDevInfo) {
    SP_PROPCHANGE_PARAMS pcp = { sizeof(SP_CLASSINSTALL_HEADER) };
    SP_DEVINFO_DATA did = { sizeof(SP_DEVINFO_DATA) };
    HCURSOR hCur = SetCursor(LoadCursor(NULL, IDC_WAIT));

    if (!SetupDiEnumDeviceInfo(hDevInfo, index, &did)) { FormatMsg(GetLastError(), msg); throw msg; }

    pcp.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
    pcp.Scope = DICS_FLAG_GLOBAL;
    pcp.StateChange = newState; // DICS_ENABLE / DICS_DISABLE

    if (!SetupDiSetClassInstallParams(hDevInfo, &did, (SP_CLASSINSTALL_HEADER*)&pcp, sizeof(pcp))) { FormatMsg(GetLastError(), msg); throw msg; }
    if (!SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, hDevInfo, &did)) { FormatMsg(GetLastError(), msg); throw msg; }

    SetCursor(hCur);
    return TRUE;
}

bool ControlDisk(int action, int devType) {
    // action: 1=啟用, 0=禁用, -1=不處理
    // devType: 0=軟碟機, 1=光碟機, 2=USB
    if (action == -1) return false;

    const TCHAR* guids[] = {
        _T("4D36E980-E325-11CE-BFC1-08002BE10318"), // FDC
        _T("4D36E965-E325-11CE-BFC1-08002BE10318"), // CDROM
        _T("36FC9E60-C465-11CF-8056-444553540000")  // USB
    };
    if (devType < 0 || devType > 2) return false;

    GUID guid; UuidFromString((RPC_CSTR)guids[devType], &guid);
    HDEVINFO hDevInfo = SetupDiGetClassDevs(&guid, NULL, NULL, DIGCF_PRESENT);
    if (hDevInfo == INVALID_HANDLE_VALUE) return false;

    SP_DEVINFO_DATA did = { sizeof(SP_DEVINFO_DATA) };
    for (DWORD i = 0; SetupDiEnumDeviceInfo(hDevInfo, i, &did); ++i) {
        ChangeStatus(action ? DICS_ENABLE : DICS_DISABLE, i, hDevInfo);
    }
    SetupDiDestroyDeviceInfoList(hDevInfo);
    return true;
}

實測注意事項

  • 光碟機、軟碟機:禁用/啟用單次呼叫即可生效。
  • USB 裝置:禁用後需呼叫 兩次 ControlDisk(1, 2) 才能成功啟用 (原因未深究,可能需重新列舉)。
  • 需管理員權限執行。
  • 錯誤訊息透過 FormatMessage 取得系統中文化說明。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved