前言
配置文件API包括注册表API和iniAPI.
iniAPI中有读写结构的API, 挺方便.
注册表遍历时, 加入遍历回调函数, 可以方便的实现注册表遍历打印或注册表键的遍历删除
@todo 注册表操作时需要的cbSize, 还没验证, 先按bytes算的. 在unicode下可能有问题,到时再修正.
测试工程
// testIniFileOpt.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <assert.h>
#include "testIniFileOpt.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
typedef struct _tag_RegInfo {
TCHAR szClass[MAXBYTE]; ///< address of buffer for class string
DWORD cbClass; ///< address of size of class string buffer
DWORD cbSubKeys; ///< address of buffer for number of subkeys
DWORD cbMaxSubKeyLen; ///< address of buffer for longest subkey name length
DWORD cbMaxClassLen; ///< address of buffer for longest class string length
DWORD cbValues; ///< address of buffer for number of value entries
DWORD cbMaxValueNameLen; ///< address of buffer for longest value name length
DWORD cbMaxValueLen; ///< address of buffer for longest value data length
DWORD cbSecurityDescriptor; ///< address of buffer for security descriptor length
FILETIME ftLastWriteTime; ///< address of buffer for last write time
void clear() {
::ZeroMemory(this, sizeof(_tag_RegInfo));
cbClass = sizeof(szClass);
}
}TAG_REGINFO;
typedef struct _tag_RegKeyInfo {
TCHAR szName[MAXBYTE]; // address of buffer for subkey name
DWORD cbName; // address for size of subkey buffer
TCHAR szClass[MAXBYTE]; // address of buffer for class string
DWORD cbClass; // address for size of class buffer
FILETIME ftLastWriteTime; // address for time key last written to
void clear() {
::ZeroMemory(this, sizeof(_tag_RegKeyInfo));
cbName = sizeof(szName);
cbClass = sizeof(szClass);
}
}TAG_REGKEYINFO;
/
// The one and only application object
CWinApp theApp;
using namespace std;
void fnTestIniFileOpt_public();
void fnTestIniFileOpt_private();
void fnTestRegister();
void fnTraverseRegister();
typedef void (*PFUN_RegValueEnumProc)(HKEY hKey, TCHAR* pName);
void fnTraverseRegisterByKey(HKEY hKeyNow,
PFUN_RegValueEnumProc ProcKey,
PFUN_RegValueEnumProc ProcValue);
void RegValueEnumProc_PrintSubKey(HKEY hKey, TCHAR* pSubKeyName);
void RegValueEnumProc_PrintValue(HKEY hKey, TCHAR* pValueName);
void RegValueEnumProc_DelSubKey(HKEY hKey, TCHAR* pSubKeyName);
void RegValueEnumProc_DelValue(HKEY hKey, TCHAR* pValueName);
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
int nRetCode = 0;
// initialize MFC and print and error on failure
if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
{
// TODO: change error code to suit your needs
cerr << _T("Fatal Error: MFC initialization failed") << endl;
nRetCode = 1;
}
else
{
// TODO: code your application's behavior here.
CString strHello;
strHello.LoadString(IDS_HELLO);
cout << (LPCTSTR)strHello << endl;
fnTestRegister();
fnTraverseRegister();
}
return nRetCode;
}
void fnTraverseRegister() {
/// 遍历注册表
LONG lRc = 0;
HKEY hKeyNow = NULL;
do {
lRc = RegOpenKeyEx(
HKEY_CURRENT_CONFIG,
TEXT("SOFTWARE\\MyRegisterTest"),
0,
KEY_ALL_ACCESS,
&hKeyNow);
if (!((ERROR_SUCCESS == lRc) && (NULL != hKeyNow))) {
break;
}
fnTraverseRegisterByKey(hKeyNow,
RegValueEnumProc_DelSubKey, RegValueEnumProc_DelValue);
RegCloseKey(hKeyNow);
lRc = RegDeleteKey(HKEY_CURRENT_CONFIG, TEXT("SOFTWARE\\MyRegisterTest"));
assert(ERROR_SUCCESS == lRc);
} while (0);
}
void RegValueEnumProc_DelSubKey(HKEY hKey, TCHAR* pSubKeyName) {
LONG lRc = 0;
if ((NULL != hKey) && (NULL != pSubKeyName)) {
if (_tcslen(pSubKeyName) > 0) { ///< 不删除空名字的键
lRc = RegDeleteKey(hKey, pSubKeyName);
assert(ERROR_SUCCESS == lRc);
}
}
}
void RegValueEnumProc_DelValue(HKEY hKey, TCHAR* pValueName) {
LONG lRc = 0;
if ((NULL != hKey) && (NULL != pValueName)) {
if (_tcslen(pValueName) > 0) { ///< 不删除默认值
lRc = RegDeleteValue(hKey, pValueName);
assert(ERROR_SUCCESS == lRc);
}
}
}
void RegValueEnumProc_PrintSubKey(HKEY hKey, TCHAR* pSubKeyName) {
if ((NULL != hKey) && (NULL != pSubKeyName)) {
TRACE("hKey[0x%p], SubKeyName[%s]\n", hKey, pSubKeyName);
}
}
void RegValueEnumProc_PrintValue(HKEY hKey, TCHAR* pValueName) {
if ((NULL != hKey) && (NULL != pValueName)) {
TRACE("hKey[0x%p], ValueName[%s]\n", hKey, pValueName);
}
}
void fnTraverseRegisterByKey(HKEY hKeyNow,
PFUN_RegValueEnumProc ProcKey,
PFUN_RegValueEnumProc ProcValue) {
LONG lRc = 0;
TAG_REGINFO RegInfo;
DWORD dwIndex = 0;
HKEY hSubKey = NULL;
TAG_REGKEYINFO RegKeyInfo;
TCHAR szValueName[MAXBYTE];
DWORD cbValueName;
RegInfo.clear();
lRc = RegQueryInfoKey(
hKeyNow,
RegInfo.szClass,
&RegInfo.cbClass,
NULL,
&RegInfo.cbSubKeys,
&RegInfo.cbMaxSubKeyLen,
&RegInfo.cbMaxClassLen,
&RegInfo.cbValues,
&RegInfo.cbMaxValueNameLen,
&RegInfo.cbMaxValueLen,
&RegInfo.cbSecurityDescriptor,
&RegInfo.ftLastWriteTime);
if (ERROR_SUCCESS == lRc) {
/// Traverse subKey
for (dwIndex = (RegInfo.cbSubKeys - 1); dwIndex != (DWORD)(-1) ; dwIndex--) {
RegKeyInfo.clear();
lRc = RegEnumKeyEx(
hKeyNow,
dwIndex,
RegKeyInfo.szName,
&RegKeyInfo.cbName,
NULL,
RegKeyInfo.szClass,
&RegKeyInfo.cbClass,
&RegKeyInfo.ftLastWriteTime);
if (ERROR_SUCCESS == lRc) {
lRc = RegOpenKeyEx(
hKeyNow,
RegKeyInfo.szName,
0,
KEY_ALL_ACCESS,
&hSubKey);
if ((ERROR_SUCCESS == lRc) && (NULL != hSubKey)) {
fnTraverseRegisterByKey(hSubKey, ProcKey, ProcValue);
RegCloseKey(hSubKey);
if (NULL != ProcKey) {
ProcKey(hKeyNow, RegKeyInfo.szName);
}
}
}
}
/// Traverse subValue
for (dwIndex = (RegInfo.cbValues - 1); dwIndex != (DWORD)(-1) ; dwIndex--) {
ZeroMemory(szValueName, sizeof(szValueName));
cbValueName = sizeof(szValueName);
lRc = RegEnumValue(
hKeyNow,
dwIndex,
szValueName,
&cbValueName,
NULL,
NULL,
NULL,
NULL);
if (ERROR_SUCCESS == lRc) {
if (NULL != ProcValue) {
ProcValue(hKeyNow, szValueName);
}
}
}
}
}
void fnTestRegister() {
LONG lRc = 0;
HKEY hKeyNow = NULL;
DWORD dwDisposition = 0;
DWORD dwType = 0;
DWORD cbData = 0;
TCHAR cBuf[MAX_PATH] = {TEXT('\0')};
// HKEY_CURRENT_CONFIG\SOFTWARE
/// 注册表API, 优先使用带Ex的API. 不带Ex的API, M$不推荐使用
/// 是否M$不推荐使用, 请参考
/// An application cannot create a key under HKEY_USERS or HKEY_LOCAL_MACHINE.
lRc = RegCreateKeyEx(
HKEY_CURRENT_CONFIG,
TEXT("SOFTWARE\\MyRegisterTest"),
0,
NULL,
REG_OPTION_VOLATILE,
KEY_ALL_ACCESS,
NULL,
&hKeyNow,
&dwDisposition);
assert(ERROR_SUCCESS == lRc);
if (NULL != hKeyNow) {
/// 写默认值内容
_tcscpy(cBuf, TEXT("default content"));
lRc = RegSetValueEx(
hKeyNow,
TEXT(""),
0,
REG_SZ,
(CONST BYTE *)cBuf,
_tcslen(cBuf) + 1);
assert(ERROR_SUCCESS == lRc);
/// 写指定值内容
_tcscpy(cBuf, TEXT("MyValue1's content"));
lRc = RegSetValueEx(
hKeyNow,
TEXT("MyValue1"),
0,
REG_SZ,
(CONST BYTE *)cBuf,
_tcslen(cBuf) + 1);
assert(ERROR_SUCCESS == lRc);
RegCloseKey(hKeyNow);
if (REG_CREATED_NEW_KEY == dwDisposition) {
TRACE(TEXT("REG_CREATED_NEW_KEY\n"));
} else if (REG_OPENED_EXISTING_KEY == dwDisposition) {
TRACE(TEXT("REG_OPENED_EXISTING_KEY\n"));
}
}
lRc = RegCreateKeyEx(
HKEY_CURRENT_CONFIG,
TEXT("SOFTWARE\\MyRegisterTest\\SubKey1"),
0,
NULL,
REG_OPTION_VOLATILE,
KEY_ALL_ACCESS,
NULL,
&hKeyNow,
&dwDisposition);
if ((ERROR_SUCCESS == lRc) && (NULL != hKeyNow)) {
RegCloseKey(hKeyNow);
}
lRc = RegCreateKeyEx(
HKEY_CURRENT_CONFIG,
TEXT("SOFTWARE\\MyRegisterTest\\SubKey2"),
0,
NULL,
REG_OPTION_VOLATILE,
KEY_ALL_ACCESS,
NULL,
&hKeyNow,
&dwDisposition);
if ((ERROR_SUCCESS == lRc) && (NULL != hKeyNow)) {
RegCloseKey(hKeyNow);
}
/// 打开键, 读键值
hKeyNow = NULL;
lRc = RegOpenKeyEx(
HKEY_CURRENT_CONFIG,
TEXT("SOFTWARE\\MyRegisterTest"),
0,
KEY_ALL_ACCESS,
&hKeyNow);
if ((ERROR_SUCCESS == lRc) && (NULL != hKeyNow)) {
cbData = sizeof(cBuf);
lRc = RegQueryValueEx(
hKeyNow,
TEXT("MyValue1"),
NULL,
&dwType,
(UCHAR*)cBuf,
&cbData);
if (ERROR_SUCCESS == lRc) {
assert(REG_SZ == dwType);
TRACE(TEXT("%s\n"), cBuf);
}
RegCloseKey(hKeyNow);
}
}
#define INI_FILE_NAME TEXT("MyIniFileName.ini")
#define INI_APP_NAME TEXT("MyAppName")
#define INI_KEY_NAME TEXT("MyKeyName")
#define INI_KEY_NAME1 TEXT("MyKeyName1")
void fnTestIniFileOpt_private() {
BOOL bRc = FALSE;
DWORD dwRc = 0;
TCHAR cIniPathName[MAX_PATH] = {TEXT('\0')};
TCHAR cBuf[MAXSHORT] = {TEXT('\0')};
TCHAR* pTmp = NULL;
// GetCurrentDirectory 会被API改掉, 不太好
// 还是调用GetModuleFileName
// 如果是在DLL中, ModuleFileName让调用者传进来
dwRc = GetModuleFileName(NULL, cIniPathName,
sizeof(cIniPathName) / sizeof(TCHAR));
assert(dwRc > 0);
pTmp = _tcsrchr(cIniPathName, TEXT('\\'));
assert(NULL != pTmp);
*(pTmp + 1) = TEXT('\0');
_tcscat(cIniPathName, INI_FILE_NAME);
// WritePrivateProfileSection 没大用
bRc = WritePrivateProfileSection(
INI_APP_NAME,
INI_KEY_NAME,
cIniPathName);
assert(bRc);
bRc = WritePrivateProfileString(
INI_APP_NAME,
INI_KEY_NAME,
TEXT("Value1"),
cIniPathName);
assert(bRc);
dwRc = GetPrivateProfileString(
INI_APP_NAME,
INI_KEY_NAME,
TEXT("not found"),
cBuf,
sizeof(cBuf) / sizeof(TCHAR),
cIniPathName);
assert(dwRc > 0);
assert(0 != strcmp(cBuf, TEXT("not found")));
/// ini结构读写API, 方便
/// 存贮格式未知, 如果要做校验, 自己整个算法写入校验和
RECT rt;
::SetRect(&rt, 10, 20, 30, 40);
bRc = WritePrivateProfileStruct(
INI_APP_NAME,
INI_KEY_NAME,
&rt,
sizeof(rt),
cIniPathName);
assert(bRc);
::SetRect(&rt, 0, 0, 0, 0);
bRc = GetPrivateProfileStruct(
INI_APP_NAME,
INI_KEY_NAME,
&rt,
sizeof(rt),
cIniPathName);
assert(bRc);
assert(rt.left == 10);
assert(rt.top == 20);
assert(rt.right == 30);
assert(rt.bottom == 40);
}
void fnTestIniFileOpt_public() {
BOOL bRc = FALSE;
DWORD dwRc = 0;
TCHAR cBuf[MAX_PATH] = {TEXT('\0')};
// WriteProfileSection没大用, 可以被WriteProfileString代替
// WriteProfileString 是向 $OSIDR/win.ini中写内容, 不推荐
// bRc = WriteProfileString(INI_APP_NAME, INI_KEY_NAME, TEXT("MyKeyValue"));
// assert(bRc);
bRc = WriteProfileString(INI_APP_NAME, INI_KEY_NAME1, TEXT("MyKeyValue1"));
assert(bRc);
dwRc = GetProfileSection(INI_APP_NAME, cBuf, sizeof(cBuf) / sizeof(TCHAR));
assert(dwRc > 0); ///< dwRc > 0, 说明INI_APP_NAME扇区下有内容, 没大用
dwRc = GetProfileString(INI_APP_NAME, INI_KEY_NAME1, TEXT("not found"),
cBuf, sizeof(cBuf) / sizeof(TCHAR));
assert(dwRc > 0);
assert(0 != _tcscmp(cBuf, TEXT("not found")));
}