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

登錄表操作封裝類:字串/DWORD/二進制值讀寫、建立/刪除鍵值完整實現

     編輯:關於VC++

設計目標

將繁瑣的 Win32 登錄表 API (RegOpenKeyEx, RegQueryValueEx, RegSetValueEx 等) 封裝為簡潔、型別安全、錯誤處理完善的 C++ 類別,支援字串 (REG_SZ)、DWORD (REG_DWORD)、二進制 (REG_BINARY) 三種常用資料型別。

類別介面設計


class CRegistryUtil {
public:
    // 讀取值 (自動偵測型別或指定型別)
    bool ReadString(HKEY hRoot, LPCTSTR subKey, LPCTSTR valueName, CString& outStr);
    bool ReadDword(HKEY hRoot, LPCTSTR subKey, LPCTSTR valueName, DWORD& outDword);
    bool ReadBinary(HKEY hRoot, LPCTSTR subKey, LPCTSTR valueName, BYTE* pBuffer, DWORD& bufSize);

    // 寫入值
    bool WriteString(HKEY hRoot, LPCTSTR subKey, LPCTSTR valueName, LPCTSTR str);
    bool WriteDword(HKEY hRoot, LPCTSTR subKey, LPCTSTR valueName, DWORD dword);
    bool WriteBinary(HKEY hRoot, LPCTSTR subKey, LPCTSTR valueName, const BYTE* data, DWORD len);

    // 鍵值管理
    bool DeleteValue(HKEY hRoot, LPCTSTR subKey, LPCTSTR valueName);
    bool DeleteKey(HKEY hRoot, LPCTSTR subKey, LPCTSTR keyName); // 刪除子鍵 (WinNT 需遞迴)
    bool CreateKey(HKEY hRoot, LPCTSTR subKey); // 確保鍵存在

    // 列舉
    bool EnumValues(HKEY hRoot, LPCTSTR subKey, std::vector<CString>& names);
    bool EnumKeys(HKEY hRoot, LPCTSTR subKey, std::vector<CString>& names);
};

核心實現細節

通用開啟/關閉輔助函數


HKEY OpenKey(HKEY hRoot, LPCTSTR subKey, REGSAM access = KEY_READ) {
    HKEY hKey = NULL;
    LONG res = RegOpenKeyEx(hRoot, subKey, 0, access, &hKey);
    return (res == ERROR_SUCCESS) ? hKey : NULL;
}

void SafeCloseKey(HKEY& hKey) {
    if (hKey) { RegCloseKey(hKey); hKey = NULL; }
}

讀取字串值


bool CRegistryUtil::ReadString(HKEY hRoot, LPCTSTR subKey, LPCTSTR valueName, CString& outStr) {
    HKEY hKey = OpenKey(hRoot, subKey, KEY_QUERY_VALUE);
    if (!hKey) return false;

    DWORD type = 0, size = 0;
    // 第一次查詢取得大小
    LONG res = RegQueryValueEx(hKey, valueName, NULL, &type, NULL, &size);
    if (res != ERROR_SUCCESS || type != REG_SZ) { SafeCloseKey(hKey); return false; }

    // 分配緩衝區並讀取
    std::vector<TCHAR> buf(size / sizeof(TCHAR));
    res = RegQueryValueEx(hKey, valueName, NULL, &type, (LPBYTE)buf.data(), &size);
    SafeCloseKey(hKey);
    if (res == ERROR_SUCCESS) {
        outStr = buf.data();
        return true;
    }
    return false;
}

寫入 DWORD 值


bool CRegistryUtil::WriteDword(HKEY hRoot, LPCTSTR subKey, LPCTSTR valueName, DWORD dword) {
    HKEY hKey = OpenKey(hRoot, subKey, KEY_SET_VALUE);
    if (!hKey) return false;

    // 若鍵不存在,嘗試建立
    if (!hKey) {
        DWORD disp;
        RegCreateKeyEx(hRoot, subKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hKey, &disp);
        if (!hKey) return false;
    }

    LONG res = RegSetValueEx(hKey, valueName, 0, REG_DWORD, (const BYTE*)&dword, sizeof(DWORD));
    SafeCloseKey(hKey);
    return res == ERROR_SUCCESS;
}

刪除子鍵 (支援遞迴)


bool CRegistryUtil::DeleteKey(HKEY hRoot, LPCTSTR subKey, LPCTSTR keyName) {
    HKEY hParent = OpenKey(hRoot, subKey, KEY_ALL_ACCESS);
    if (!hParent) return false;

    // Windows NT/2000/XP: RegDeleteKey 只能刪空鍵,需遞迴刪除子鍵
    // Windows 9x: RegDeleteKey 會遞迴刪除
    // 統一實現遞迴刪除
    bool success = RecursiveDeleteKey(hParent, keyName);
    SafeCloseKey(hParent);
    return success;
}

bool CRegistryUtil::RecursiveDeleteKey(HKEY hParent, LPCTSTR keyName) {
    HKEY hKey;
    if (RegOpenKeyEx(hParent, keyName, 0, KEY_ALL_ACCESS, &hKey) != ERROR_SUCCESS)
        return false;

    // 列舉並遞迴刪除子鍵
    TCHAR subKeyName[256];
    DWORD index = 0, size;
    while (RegEnumKeyEx(hKey, index, subKeyName, &size, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
        if (!RecursiveDeleteKey(hKey, subKeyName)) {
            RegCloseKey(hKey);
            return false;
        }
        // 註意:刪除後索引不變,因為下一個子鍵會移到當前索引
    }
    RegCloseKey(hKey);

    // 刪除自身
    return RegDeleteKey(hParent, keyName) == ERROR_SUCCESS;
}

使用範例


CRegistryUtil reg;

// 寫入各型別值
reg.WriteString(HKEY_CURRENT_USER, _T("Software\\MyApp"), _T("UserName"), _T("JohnDoe"));
reg.WriteDword(HKEY_CURRENT_USER, _T("Software\\MyApp"), _T("MaxConnections"), 100);
BYTE binData[] = {0x01, 0x02, 0x03, 0x04};
reg.WriteBinary(HKEY_CURRENT_USER, _T("Software\\MyApp"), _T("LicenseKey"), binData, 4);

// 讀取驗證
CString name; DWORD maxConn; BYTE buf[16]; DWORD bufSize = 16;
reg.ReadString(HKEY_CURRENT_USER, _T("Software\\MyApp"), _T("UserName"), name);
reg.ReadDword(HKEY_CURRENT_USER, _T("Software\\MyApp"), _T("MaxConnections"), maxConn);
reg.ReadBinary(HKEY_CURRENT_USER, _T("Software\\MyApp"), _T("LicenseKey"), buf, bufSize);

// 清理
reg.DeleteValue(HKEY_CURRENT_USER, _T("Software\\MyApp"), _T("UserName"));
reg.DeleteKey(HKEY_CURRENT_USER, _T("Software\\MyApp"), _T("Settings")); // 刪除整個子鍵

常見錯誤與最佳實踐

問題原因解決
存取被拒權限不足 (寫入 HKLM 需管理員)檢查 UAC、以管理員身分執行、或改寫 HKCU
資料截斷緩衝區太小先查詢大小再分配緩衝區 (如 ReadString 實現)
型別不符REG_SZ vs REG_EXPAND_SZ讀取時檢查 type,必要時用 ExpandEnvironmentStrings
刪除失敗鍵非空 (NT 系統)使用遞迴刪除函數

擴展建議

  • 加入 REG_MULTI_SZ (多字串) 支援
  • 實作 RAII 風格的 CRegKey 包裝類別
  • 支援 32/64 位元登錄表視圖切換 (KEY_WOW64_64KEY)
  • 加入交易式操作 (Vista+ RegCreateKeyTransacted)
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved