レジストリ関連の Win32API の扱い

x86/x64,char/wchar_t など様々な設定でビルドする場合,レジストリ関連の Win32API は少し注意して扱う必要があるようです.

REG_DWORD

REG_DWORD が一番嵌りました.std::size_t 辺りを使用している場合,(Visual Studio 2008 では) x86 は uint32_t のようですが x64 は uint64_t で定義されているようです.そのため,std::size_t で保持している値を REG_DWORD としてレジストリに保存しようとするとデータが壊れてしまうようです.

std::size_t foo = 1; // この値をレジストリに保存

HKEY subkey;
DWORD disposition;
LONG result = RegCreateKeyEx(HKEY_CURRENT_USER, _T("Software\\example"), 0, _T(""),
    REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &subkey, &disposition);
if (result) return;

// x64 を考慮していったん DWORD にキャストする(元の値は,DWORD の最大値を超えないように注意).
DWORD value = static_cast<DWORD>(foo);
RegSetValueEx(subkey, _T("name"), 0, REG_DWORD, (CONST BYTE*)&value, sizeof(value));

REG_SZ

こちらはイージーミス.RegSetValueEx() の最後に指定する値は「文字列数」ではなく「バイト数」でした.当初,「文字列数」を指定していたため,UNICODE を定義した際に文字列が途中で切れると言うバグを発生させてしまいました.

std::basic_string<TCHAR> foo = _T("foo"); // この値をレジストリに保存

HKEY subkey;
DWORD disposition;
LONG result = RegCreateKeyEx(HKEY_CURRENT_USER, _T("Software\\example"), 0, _T(""),
    REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &subkey, &disposition);
if (result) return;

DWORD byte = (foo.length() + 1) * sizeof(TCHAR);
RegSetValueEx(subkey, _T("name"), 0, REG_DWORD, (CONST BYTE*)foo.c_str(), byte);