2017 年 5 月

第 32 卷,第 5 期

此文章由机器翻译。

C++ - 使用新式 C++ 存取 Windows 登錄

Giovanni Dicanio

Windows 作業系統會公開一系列的 C 介面 Api 可讓開發人員存取登錄。這些 Api 的部分相當低的層級且需要程式設計人員要注意許多詳細資料。從 Windows Vista 開始,一種較高層級的 API 加入至混合︰ RegGetValue 函式 (bit.ly/2jXtfpJ)。引進這個 API 之前,為了從登錄讀取值,您必須先開啟包含呼叫 RegOpenKeyEx 的值所需的登錄機碼。然後,您必須呼叫 RegQueryValueEx API,處理許多複雜的細節。例如,如果您閱讀 RegQueryValueEx 的字串值,傳回的字串不保證是以正確 NUL 結尾,而這可能導致一系列的危險的安全性錯誤,程式碼中。若要防止發生此狀況,您必須注意,若要檢查傳回的字串; 是否沒有 NUL 結束字元如果沒有任何輸入,您必須將它加入。此外,您必須確定您正確關閉開啟的金鑰,呼叫 RegCloseKey。

當然,開啟登錄機碼可能會失敗,因此您需要新增程式碼來處理,以及。RegGetValue API 簡化此工作流程,會自動開啟時所需的登錄機碼、 關閉之後使用,和它正確 NUL 終止的字串傳回給呼叫者之前。儘管這樣的簡化方式 RegGetValue 函式仍是低階 C 介面函式。此外,它可以處理許多不同類型的登錄值 (從 Dword 為二進位資料的字串),讓它進行程式設計複雜的介面。

還好,您可以使用現代 c + + 來正確建置此 RegGetValue Win32 API,提供簡化的介面,從登錄讀取不同類型的值周圍的較高層級抽象。

代表使用例外狀況錯誤

RegGetValue API C 介面 API,因此它會通知呼叫端使用傳回碼的錯誤狀況。特別是,此函數會傳回長時間類型的值︰ 如果是成功和不同的值,如果錯誤是 ERROR_SUCCESS (也就是零)。例如,如果呼叫端所提供的輸出緩衝區不夠大,將無法寫入其資料 api,函數會傳回 ERROR_MORE_DATA。用於建立這個 C API 周圍較高層級的 c + + 介面,您可以定義代表錯誤的 c + + 例外狀況類別。這個類別可以衍生自標準 std::runtime_error 類別,而且您可以嵌入長 RegGetValue 內傳回的錯誤碼︰

class RegistryError
  : public std::runtime_error
{
public:
  ...
private:
  LONG m_errorCode;
};

此外,其他的資訊項目可以內嵌在例外狀況物件。例如,HKEY 和子機碼名稱。這是只是基本的實作。

您可以將建立使用錯誤訊息和失敗的 RegGetValue 呼叫的傳回碼這個例外狀況類別的執行個體的建構函式︰

RegistryError(const char* message, LONG errorCode)
  : std::runtime_error{message}
  , m_errorCode{errorCode}
{}

和錯誤代碼,以便公開給用戶端使用的唯讀存取子 (getter):

LONG ErrorCode() const noexcept
{
  return m_errorCode;
}

既然您已經建置這個例外狀況類別,您可以繼續包裝 RegGetValue C API,在較高層級的 c + + 介面容易使用和較不容易發生錯誤。

從登錄讀取的 DWORD 值

舉個簡單的作業︰ 使用 RegGetValue API 來讀取登錄 DWORD 值。在此情況下使用模式是很簡單。但是首先,讓我們來看看哪一種介面可定義在 c + + 中的管理此情況。

以下是 RegGetValue API 原型︰

LONG WINAPI RegGetValue(
  _In_        HKEY    hkey,
  _In_opt_    LPCTSTR lpSubKey,
  _In_opt_    LPCTSTR lpValue,
  _In_opt_    DWORD   dwFlags,
  _Out_opt_   LPDWORD pdwType,
  _Out_opt_   PVOID   pvData,
  _Inout_opt_ LPDWORD pcbData
);

如您所見,此介面的 C 函式高泛用的資料,如同 void * 輸出緩衝區 (pvData) 和輸出緩衝區的大小參數 (pcbData)。此外,還有識別登錄機碼和特定值的名稱在該機碼下的 C 樣式字串 (lpSubKey 和 lpValue)。您可以處理此 C 函式原型一點,讓較簡單的 c + + 呼叫者。

首先,在您擲回 c + + 例外狀況的訊號錯誤狀況,從登錄讀取的 DWORD 值可以只傳回由 c + + 包裝函式做為傳回值。這會自動就不需要原始 void * 輸出緩衝區參數 (pvData) 和相關聯的大小參數 (pcbData)。

此外,當您使用 c + +,最好是以代表使用 std:: wstring 類別,而不 C 樣式的原始指標 Unicode (utf-16) 字串。因此,您可以定義此更簡單的 c + + 函式可從登錄讀取的 DWORD 值︰

DWORD RegGetDword(
  HKEY hKey,
  const std::wstring& subKey,
  const std::wstring& value
)

如您所見,沒有 PVOID 和 LPDWORD 參數;輸入的字串會傳遞透過 const std:: wstring 物件的參考,並從登錄讀取的值這個 c + + 函式傳回為 DWORD。這絕對是一個更簡單且較高層級介面。

現在讓我們深入了解實作。如前所述,叫用的模式 RegGetValue 在此情況下是相當簡單。您必須宣告 DWORD 變數來儲存從登錄讀取的值︰

DWORD data{};

然後,您需要另一個 DWORD 變數代表 RegGetValue 寫入輸出緩衝區的大小 (以位元組為單位)。請注意,輸出緩衝區,在此簡單的情況下只是先前的 「 資料 」 變數,且其大小是持續的 DWORD 大小︰

DWORD dataSize = sizeof(data);

但請注意,您無法將標示為 「 常數 」 dataSize 因為它是輸入和輸出參數的 RegGetValue。

然後您可以叫用 RegGetValue API:

LONG retCode = ::RegGetValue(
  hKey,
  subKey.c_str(),
  value.c_str(),
  RRF_RT_REG_DWORD,
  nullptr,
  &data,
  &dataSize
);

輸入的 wstring 物件會轉換成使用 wstring::c_str 方法的原始 C 樣式字串指標。RRF_RT_REG_DWORD 旗標會限制 DWORD 登錄值的型別。如果您嘗試讀取登錄值是不同的型別,安全地失敗 RegGetValue 函式呼叫。

最後兩個參數代表的位址 (在此情況下,資料變數的位址) 的輸出緩衝區和輸出緩衝區的大小會儲存變數的位址。事實上,在傳回時,RegGetValue 報告在資料寫入至輸出緩衝區的大小。在此情況下讀取簡單 DWORD,資料的大小永遠是 4 個位元組,也就是 sizeof(DWORD)。不過,這個大小參數是重要的可變大小的值,例如字串。我會在本文稍後討論。

叫用後 RegGetValue 函式,您可以檢查傳回碼,並擲回例外狀況發生錯誤︰

if (retCode != ERROR_SUCCESS)
{
  throw RegistryError{"Cannot read DWORD from registry.", retCode};
}

請注意 RegGetValue 所傳回的錯誤程式碼 (retCode) 例外狀況物件中內嵌的而且可以稍後再擷取將處理的例外狀況的程式碼。

或者,如果成功,DWORD 資料變數可以只傳回給呼叫者︰

return data;

這是它的函式實作。

呼叫端直接叫用此 c + + 包裝函式使用如下的程式碼︰

DWORD data = RegGetDword(HKEY_CURRENT_USER, subkey, L"MyDwordValue");

請注意簡單這段程式碼時,相較於原始 RegGetValue C API 呼叫。只將控制代碼傳遞至開啟的登錄機碼 (在此範例中的 HKEY_CURRENT_USER 預先定義的索引鍵),包含子機碼和值名稱的字串。成功時,會傳回給呼叫者的 DWORD 值。另一方面,錯誤時,自訂型別的 RegistryError 會擲回例外狀況。這種程式碼是較高的層級和叫用 RegGetValue 比簡單多了。事實上,RegGetValue 複雜性已隱藏此自訂 RegGetDword c + + 包裝函式內。

您可以使用相同的模式 QWORD (64 位元資料) 值讀取登錄。在此情況下,您只需要用 DWORD 類型登錄值與 64 位元 ULONGLONG 替代。

從登錄讀取的字串值

讀取 DWORD 登錄值是相當簡單︰ 只要 RegGetValue Win32 API 呼叫已足夠。這主要是因為 DWORD 值是固定的大小,四個位元組,DWORD 的大小。相反地,從登錄讀取字串導入了另一層複雜度因為字串變數大小的資料。這個概念在此情況下是兩次呼叫 RegGetValue API: 在第一次呼叫中,您可以要求此 API,以傳回所需的輸出字串緩衝區的大小。接下來,您以動態方式配置適當大小的緩衝區。最後,您進行第二個呼叫 RegGetValue,以實際撰寫先前配置的緩衝區中的字串資料。(此模式已在前一篇文章中,「 使用 STL 字串在 Win32 API 界限,「 詳加討論在 msdn.com/magazine/mt238407)。

首先,看看 c + + 高階包裝函式的原型︰

std::wstring RegGetString(
  HKEY hKey,
  const std::wstring& subKey,
  const std::wstring& value
)

如同 DWORD 案例中,這更簡化相對於原始複雜 RegGetValue C API 原型。函式傳回的字串值做為 std:: wstring 執行個體。相反地,發生錯誤時,會擲回例外狀況。子機碼名稱和值名稱會當做輸入的 wstring const 參考參數,以及傳遞。

現在我要討論的實作程式碼。

正如我之前,作法是在第一次呼叫 RegGetValue API 來取得儲存的字串值的輸出緩衝區大小︰

DWORD dataSize{};
LONG retCode = ::RegGetValue(
  hKey,
  subKey.c_str(),
  value.c_str(),
  RRF_RT_REG_SZ,
  nullptr,
  nullptr,
  &dataSize
);

您可以看到類似於先前的 DWORD 值大小寫的呼叫語法。Wstring 物件會轉換成 C 樣式字串的指標叫用 wstring::c_str 方法。RRF_RT_REG_SZ 旗標在此情況下會限制字串型別 (REG_SZ) 的有效登錄型別。成功時,RegGetValue API 將撰寫 dataSize 變數中的所需的輸出緩衝區的大小 (以位元組為單位表示)。

在失敗時,您必須擲回例外狀況的自訂 RegistryError 類別︰

if (retCode != ERROR_SUCCESS)
{
  throw RegistryError{"Cannot read string from registry", retCode};
}

既然您知道想要的輸出緩衝區大小,您可以在輸出字串配置所需大小的 wstring 物件︰

std::wstring data;
data.resize(dataSize / sizeof(wchar_t));

請注意,RegGetValue 所傳回的 dataSize 值以位元組為單位來表示,但是 wstring::resize 方法預期大小,以表示 wchar_t 計數。因此,您必須從位元組 wchar_t,前者的位元組大小值除以 sizeof(wchar_t) 至小數位數。

既然您具有足夠的空間配置的字串,您可以將傳遞 RegGetValue API,這次會將實際的字串資料寫所提供的緩衝區其內部緩衝區的指標︰

retCode = ::RegGetValue(
  hKey,
  subKey.c_str(),
  value.c_str(),
  RRF_RT_REG_SZ,
  nullptr,
  &data[0],
  &dataSize
);

(& s) [0] 的資料是可寫入 RegGetValue api wstring 內部緩衝區的位址。

像往常一樣,務必確認 API 呼叫的結果,並擲回例外狀況發生錯誤︰

if (retCode != ERROR_SUCCESS)
{
  throw RegistryError{"Cannot read string from registry", retCode};
}

請注意,如果成功,RegGetValue 撰寫實際的結果字串大小 (以位元組為單位) dataSize 變數中。您必須調整此大小根據 wstring 物件。DataSize 是以位元組為單位來表示,最好是將它轉換成對應的 wchar_t 計數,處理 wstrings 時︰

DWORD stringLengthInWchars = dataSize / sizeof(wchar_t);

此外,dataSize 包括終止 NUL 字元輸出字串。不過,wstring 已 NUL 終止,因此您必須注意若要避免假性和假雙 NUL 終止讀取的字串。您必須截斷 NUL 結束字元 RegGetValue 所撰寫︰

stringLengthInWchars--; // Exclude the NUL written by the Win32 API
data.resize(stringLengthInWchars);

請注意 RegGetValue API 保證 NUL 結束的字串,如果成功,即使原始字串儲存在登錄中沒有 NUL 終止。這是更安全行為比舊的 RegQueryValueEx API 所傳回的字串不保證 NUL 終止。因此,呼叫端必須撰寫額外的程式碼正確考慮這種情況下,增加整體的程式碼複雜度和 bug 表面區域。

現在,資料變數包含從登錄讀取的字串值,您可以呼叫端傳回函式結束時︰

return data;

這個方便的 RegGetString c + + 包裝函式周圍 RegGetValue 低階 C API 之後,您可以如下叫用它︰

wstring s = RegGetString(HKEY_CURRENT_USER, subkey, L"MyStringValue");

如同 DWORD 案例中,您已引發從 RegGetValue Win32 API,提供容易使用和硬誤用 c + + 包裝函數,以便從登錄讀取的字串值的抽象層級。所有詳細資料和處理 RegGetValue API 的複雜性,安全地隱藏此自訂 RegGetString c + + 函式主體內。

從登錄讀取多字串值

登錄值的另一種是所謂的 [多字串]: 基本上,這是一組雙 NUL 終止的字串,封裝於同一個登錄值。此雙 NUL 結束的字串資料結構包含一系列的 C 樣式 NUL 終止字串佔用相鄰的記憶體位置。序列的結尾會標示其他的 NUL 結束字元,因此整個結構由兩個 NULs 終止。如需有關此資料結構的詳細資訊,請參閱部落格文章,"沒有字串雙 Null 結尾字串的格式為何? 」(bit.ly/2jCqg2u)。

在此情況下 RegGetValue Win32 API 的使用模式是非常類似於上一個案例的單一字串。也就是第一次 RegGetValue API 會叫用來取得包含所需的資料 (在此情況下,整個序列的相鄰字串以雙 NUL) 為整個目標緩衝區的大小。然後,這種大小的緩衝區會以動態方式配置。而且,最後,RegGetValue 函式稱為第二次,讓 API 可以寫入該緩衝區的實際的多字串資料的先前配置的緩衝區位址傳遞。

在此情況下,您必須注意雙 NUL 終止的字串儲存的資料結構。事實上,雖然 std:: wstring 可以正確包含內嵌的 NULs,它無法可能用來儲存雙 NUL 結束的字串結構,但我想要引發的抽象層級,並將雙 NUL 終止的字串剖析成較高層級,更方便向量 < wstring >。

因此,從登錄讀取多字串值在 c + + 包裝函式的函式原型可以看起來像這樣︰

std::vector<std::wstring> RegGetMultiString(
  HKEY hKey,
  const std::wstring& subKey,
  const std::wstring& value
)

成功時,多字串將會傳回給呼叫者好向量 < wstring >。另一方面,錯誤時,一般 RegistryError 表單中的例外狀況。

在您的 c + + 包裝函式主體內,第一次您叫用 RegGetValue API 來儲存多字串所需的輸出緩衝區的大小︰

DWORD dataSize{};
LONG retCode = ::RegGetValue(
  hKey,
  subKey.c_str(),
  value.c_str(),
  RRF_RT_REG_MULTI_SZ,
  nullptr,
  nullptr,
  &dataSize
);

請注意,使用 RRF_RT_REG_MULTI_SZ 旗標的目前指定的多字串登錄值型別。

像往常一樣,如果發生錯誤,會擲回例外狀況,RegistryError 物件中內嵌的錯誤碼︰

if (retCode != ERROR_SUCCESS)
{
  throw RegistryError{"Cannot read multi-string from registry", retCode};
}

成功時,您可以配置來儲存整個多字串的適當大小的緩衝區︰

std::vector<wchar_t> data;
data.resize(dataSize / sizeof(wchar_t));

我認為向量 < wchar_t > 來代表多字串原始緩衝區 wstring 比要清楚得多。請注意,它必須適當地轉換為 wchar_t 計數再將其傳遞至 vector:: resize 方法,以位元組為單位,表示 RegGetValue API 所傳回的大小值。

然後,RegGetValue API 可以叫用第二次,將實際的多字串資料寫入先前配置的緩衝區︰

retCode = ::RegGetValue(
  hKey,
  subKey.c_str(),
  value.c_str(),
  RRF_RT_REG_MULTI_SZ,
  nullptr,
  &data[0],
  &dataSize
);

(& s) [0] 的資料引數是指向輸出緩衝區的開頭。

同樣地,您必須檢查 API 傳回碼,表示擲回 c + + 例外狀況的錯誤︰

if (retCode != ERROR_SUCCESS)
{
  throw RegistryError{"Cannot read multi-string"
    from registry", retCode};
}

您也最好能適當地調整資料緩衝區大小 RegGetValue API 做為輸出參數傳回的 dataSize 值︰

data.resize( dataSize / sizeof(wchar_t) );

此時,資料變數 (也就是向量 < wchar_t >) 會儲存雙 NUL 結束字串序列。最後一個步驟是剖析此資料結構,並將它轉換成較高層級,更方便向量 < wstring >:

// Parse the double-NUL-terminated string into a vector<wstring>
std::vector<std::wstring> result;
const wchar_t* currStringPtr = &data[0];
while (*currStringPtr != L'\0')
{
  // Current string is NUL-terminated, so get its length with wcslen
  const size_t currStringLength = wcslen(currStringPtr);
  // Add current string to result vector
  result.push_back(std::wstring{ currStringPtr, currStringLength });
  // Move to the next string
  currStringPtr += currStringLength + 1;
}

最後,結果向量 < wstring > 物件可能會傳回給呼叫者︰

return result;

這個 RegGetMultiString c + + 包裝函式可以直接叫用,像這樣︰

vector<wstring> multiString = RegGetMultiString(
  HKEY_CURRENT_USER,
  subkey,
  L"MyMultiSz"
);

同樣地,所有的 Win32 RegGetValue API 的複雜性已隱藏背後的高層級方便的 c + + 介面。

列舉值的登錄機碼下

另一個常見的 Windows 登錄作業是指定的登錄機碼值的列舉。Windows 提供 RegEnumValue API (bit.ly/2jB4kaV) 針對此目的。在這裡,我將示範如何使用此 API 來取得一份名稱並位於指定的登錄機碼底下的值型別包裝在方便的較高層級 c + + 函式的列舉程序。自訂的 c + + 函式會做為有效的 HKEY 處理至您想要列舉的索引鍵相關聯的輸入。成功時,此自訂 c + + 包裝函式會傳回向量的配對︰ 配對中的第一個項目會包含值的名稱和第二個項目代表實值型別 DWORD wstring。因此,此 c + + 包裝函式原型會看起來像這樣︰

std:: vector < std:: initializer_list < 都 DWORD >> RegEnumValues (HKEY hKey)

現在我將討論列舉程序的詳細資料。其概念是要先呼叫 RegQueryInfoKey (bit.ly/2jraw2H) API 來取得一些實用的前列舉型別資訊,例如總計值計數和指定的登錄機碼下的值名稱的最大長度,如所示**[圖 1**。

[圖 1 的叫用 RegQueryInfoKey API

DWORD valueCount{};
DWORD maxValueNameLen{};
LONG retCode = ::RegQueryInfoKey(
  hKey,
  nullptr,    // No user-defined class
  nullptr,    // No user-defined class size
  nullptr,    // Reserved
  nullptr,    // No subkey count
  nullptr,    // No subkey max length
  nullptr,    // No subkey class length
  &valueCount,
  &maxValueNameLen,
  nullptr,    // No max value length
  nullptr,    // No security descriptor
  nullptr     // No last write time
);

請注意,我會傳遞 nullptr 輸入項中我不想要的資訊。當然,您必須檢查傳回值,並呼叫上述的 API 時,發生問題時,會擲回例外狀況︰

if (retCode != ERROR_SUCCESS)
{
  throw RegistryError{"Cannot query key info from"
    the registry", retCode};
}

根據 Windows 開發人員中心 RegQueryInfoKey 函式頁 (bit.ly/2lctUDt),傳回的值名稱 (儲存在先前的程式碼中的 maxValueNameLen 變數) 的最大長度不包含結束的 NUL; 的大小,讓我們來調整此值,請加入一個終止 NUL 列入考量,當您配置緩衝區以讀取值的名稱︰

maxValueNameLen++;

然後您可以將讀取的值名稱,在每個列舉步驟; 適當大小的緩衝區配置效率低額外負荷 std:: unique_ptr < wchar_t [] > 可用於此用途︰

auto nameBuffer = std::make_unique<wchar_t[]>(maxValueNameLen);

Std:: vector 可以儲存結果的列舉型別,成對的值名稱和值類型的形式︰

std::vector<std::pair<std::wstring, DWORD>> values;

您將會逐漸將內容加入這個向量列舉程序期間,然後 「 值 」 時,會傳回給呼叫者列舉已完成。

然後您可以使用 for 迴圈中,呼叫 RegEnumValue API 重複和列舉新的值在每個反覆項目的步驟︰

for (DWORD index = 0; index < valueCount; index++)
{
  // Call RegEnumValue to get data of current value ...
}

請注意,您會取得 valueCount 初始前列舉 RegQueryInfoKey 呼叫。

主體內的 for 迴圈中,可以呼叫 RegEnumValue API 來取得目前的值所需的資訊。在此情況下,您想要知道值的名稱和值的型別。將先前配置; nameBuffer 中讀取的值名稱實值型別會儲存在一個簡單的 DWORD。如此,主體內的 for 迴圈中,您可以撰寫如下的程式碼︰

DWORD valueNameLen = maxValueNameLen;
DWORD valueType{};
retCode = ::RegEnumValue(
  hKey,
  index,
  nameBuffer.get(),
  &valueNameLen,
  nullptr,    // Reserved
  &valueType,
  nullptr,    // Not interested in data
  nullptr     // Not interested in data size

像往常一樣,最好檢查 API 傳回值,並在錯誤上擲回例外狀況︰

if (retCode != ERROR_SUCCESS)
{
  throw RegistryError{"Cannot get value info from the registry", retCode};
}

成功時,RegEnumValue API 會提供的 nameBuffer,並在 valueType 變數的值的型別中撰寫值的名稱。因此,您可以建置這兩項資訊與一對 < wstring DWORD >,並將此資訊組加入至列舉結果向量︰

values.push_back(std::make_pair(
  std::wstring{ nameBuffer.get(), valueNameLen },
  valueType
));

之後 for 迴圈中,結果 「 值 」 向量可以傳回給呼叫者︰

return values;

然後呼叫端可以列舉登錄機碼下的所有值不能只呼叫 c + + 包裝函式如下︰

auto values = RegEnumValues(hKey);
// For each value
for (const auto& v : values)
{
  // Process v.first (value's name) and v.second (value's type)
  // ...
}

類似的程式碼撰寫模式可以用來列舉子機碼底下指定的登錄機碼。在此情況下,Win32 RegEnumKeyEx (bit.ly/2k3VEX8) 必須使用 API,而不是先前所述的 RegEnumValue。與本文相關的下載中提供的這類子機碼的列舉型別函式的程式碼。

原始 HKEY 控制代碼的安全資源管理員

原始的 HKEY Win32 控制代碼類型所代表的登錄機碼可安全且便捷地包裝在 c + + 資源管理員類別。類別解構函式會正確呼叫 RegCloseKey API 包裝原始的控制代碼,以自動關閉控點上。此外,移動語意 (semantics) 作業,例如移動建構函式和移動指派運算子可定義成有效的 c + + 資源管理員類別的不同執行個體之間傳送的已包裝的控制代碼的擁有權。為了提高效率,不擲回例外狀況的所有類別方法會都標示為 noexcept,讓 c + + 編譯器發出更最佳化的程式碼。這個方便的關鍵資源管理員 c + + 類別,名為登錄機碼,被實作本文所附的 Registry.hpp 檔案中。在此可重複使用僅限標頭檔中,您也可以找到一些 helper 函式的實作︰ RegOpenKey 和 RegCreateKey 分別包裝 Win32 Api RegOpenKeyEx 和 RegCreateKeyEx,傳回 HKEY 處理安全地包裝在先前提及的 c + + 資源管理員類別。發生錯誤時,這些 c + + 函式會擲回 RegistryError 例外狀況,包裝原始的 C 介面 Win32 Api 所傳回的錯誤碼。

總結

RegGetValue Win32 API 提供相對較高層級的介面,從 Windows 登錄,相較於較低層級 Api,例如 RegQueryValueEx 讀取值。RegGetValue 也提供更安全的介面,例如,可確保所傳回的字串會正確地 NUL 結束。然而,RegGetValue 仍需要程式設計人員請注意,許多詳細資料,並對它進行程式設計可能容易發生錯誤的複雜的程式碼的 C 介面低階 API。這篇文章說明如何建立便於、 容易使用且硬碟誤用現代的 c + + 介面隱藏 RegGetValue API 的複雜性,同時簡化 Windows 登錄的存取權。此外,已包裝 RegEnumValue API,方便較高層級 c + + 函式中指定的登錄機碼下的所有值的列舉。包含的功能與本文所討論的類別的實作的原始程式碼位於可重複使用僅限標頭中的表單 (Registry.hpp 檔案) 的文件下載中。


Giovanni Dicanio是電腦程式設計人員專精於 c + + 和 Windows 作業系統、 Pluralsight 作者 (bit.ly/GioDPS) 和 Visual c + + MVP。除了程式設計和撰寫課程,他喜歡在論壇和社群致力於 c + + 幫助其他人。透過電子郵件存取他 giovanni.dicanio@gmail.com。他的部落格上 msmvps.com/gdicanio

感謝閱本篇文章的下列技術專家︰ David Cravey 和 Marc Gregoire
David Cravey GlobalSCAPE 企業架構,會導致數個 c + + 使用者的群組,但四個階段 Visual c + + MVP。

Marc Gregoire 是從比利時、 比利時 c + + 使用者的群組,這作者"Professional c + + 」 (Wiley),「 c + + 標準程式庫快速參考 」 (Apress),技術編輯共同作者的書籍,而由於 2007年的創辦人的資深軟體工程師,收到每年的 MVP 獎勵的他 VC + + 專業知識。連絡 Marc marc.gregoire@nuonsoft.com