#include <Windows.h>
#include <tchar.h>
#include <string>
#include <Shlwapi.h>
#include <cassert>
#if defined _UNICODE || defined UNICODE
typedef std::wstring String;
#else
typedef std::string String;
#endif
#pragma comment(lib,"Shlwapi.lib")
class Reg
{
public:
Reg() : m_handle_(NULL){}
~Reg(){ this->Close(); }
// Open/Close
/*
HKEY_CLASSES_ROOT
HKEY_CURRENT_CONFIG
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS
*/
inline bool Open(HKEY hKey, const String& path)
{
return OpenImp(hKey, path, KEY_READ);
}
inline bool OpenWrite(HKEY hKey, const String& path)
{
return OpenImp(hKey, path, KEY_WRITE);
}
inline bool OpenReadWrite(HKEY hKey, const String& path)
{
return OpenImp(hKey, path, KEY_READ | KEY_WRITE);
}
inline void Close()
{
if (m_handle_)
{
RegCloseKey(m_handle_);
m_handle_ = NULL;
}
}
// CreateDir/DeleteDir
inline bool CreateDir(const String& path)
{
HKEY hKey_;
LONG ret_ = RegCreateKey(m_handle_,
path.c_str(),
&hKey_);
if (!ret_)
{
RegCloseKey(hKey_);
return true;
}
_tprintf(_T("[%s] error [%u]\n"), _T("CreateDir"), ret_);
return false;
}
inline bool DeleteDir(const String& path)
{
#if 0
LONG ret_ = RegDeleteKey(m_handle_, path.c_str());
if (!ret_)
{
return true;
}
_tprintf(_T("[%s] error [%u]\n"), _T("DeleteDir"), ret_);
return false;
#else
LSTATUS ret_ = SHDeleteKey(m_handle_, path.c_str());
if (ret_ == ERROR_SUCCESS)
{
return true;
}
_tprintf(_T("[%s] error [%u]\n"), _T("SHDeleteKey"), ret_);
return false;
#endif
}
bool CopyDir(const String& str, Reg& reg)
{
LSTATUS ret_ = SHCopyKey(m_handle_,
str.c_str(),
reg.m_handle_,
0);
if (ret_ == ERROR_SUCCESS)
{
return true;
}
_tprintf(_T("[%s] error [%u]\n"), _T("SHCopyKey"), ret_);
return false;
}
bool StatDir(DWORD* dircnt,DWORD* filecnt,
DWORD* dirmaxlen, DWORD* filemaxlen)
{
DWORD dircnt_ = 0, filecnt_ = 0;
DWORD dirmaxlen_ = 0, filemaxlen_ = 0;
LSTATUS ret_ = RegQueryInfoKey(
m_handle_,
NULL, NULL, NULL,
&dircnt_,
&dirmaxlen_,
NULL,
&filecnt_,
&filemaxlen_,
NULL, NULL, NULL);
if( ret_ == ERROR_SUCCESS)
{
if (dircnt) *dircnt = dircnt_;
if (filecnt) *filecnt = filecnt_;
if (dirmaxlen) *dirmaxlen = dirmaxlen_;
if (filemaxlen) *filemaxlen = filemaxlen_;
return true;
}
_tprintf(_T("[%s] error [%u]\n"), _T("RegQueryInfoKey"), ret_);
return false;
}
bool GetSubDir(DWORD index,DWORD len,String* str)
{
assert(str);
TCHAR* buf_ = new TCHAR[len + 1];
LONG ret_ = RegEnumKey(
this->m_handle_,
index,
buf_,
(len + 1)*sizeof(TCHAR));
if (!ret_)
{
*str = buf_;
delete[] buf_;
return true;
}
delete[] buf_;
assert(ret_ != ERROR_MORE_DATA);
_tprintf(_T("[%s] error [%u]\n"), _T("RegEnumKey"), ret_);
return false;
}
bool GetSubFile(DWORD index, DWORD len, String* str,DWORD* type)
{
assert(str && type);
DWORD len_ = (len + 1)*sizeof(TCHAR);
TCHAR* buf_ = new TCHAR[len + 1];
LONG ret_ = RegEnumValue(
this->m_handle_,
index,
buf_,
&len_,
0,
type,
NULL,
NULL);
if (!ret_)
{
*str = buf_;
delete[] buf_;
return true;
}
delete[] buf_;
assert(ret_ != ERROR_MORE_DATA);
_tprintf(_T("[%s] error [%u]\n"), _T("RegEnumKey"), ret_);
return false;
}
// pwd/cd
inline const String& Pwd() const
{
return this->m_path_;
}
bool Goto(const String& path)
{
if (String::npos != path.find(_T('\\')))
{
_tprintf(_T("[%s] error path %s\n"), _T("Goto"),path.c_str());
return false;
}
HKEY hKey_;
LONG ret_ = RegOpenKeyEx(
m_handle_,
path.c_str(),
0,
this->m_desired_,
&hKey_);
if (!ret_)
{
this->Close();
this->m_handle_ = hKey_;
if (this->m_path_[this->m_path_.length() - 1] != _T('\\'))
{
this->m_path_ += _T('\\');
}
this->m_path_ += path;
return true;
}
_tprintf(_T("[%s] error [%u]\n"), _T("RegOpenKeyEx"), ret_);
return false;
}
bool GotoParent()
{
size_t pos_ = this->m_path_.rfind(_T('\\'));
if (pos_ == String::npos)
{
_tprintf(_T("[%s] error path %s\n"),
_T("GotoParent"),
m_path_.c_str());
return false;
}
String newpath_ = m_path_.substr(0, pos_);
return OpenImp(m_root_, newpath_, m_desired_);
}
// create/edit
bool Write(const String& key, DWORD value)
{
LONG ret_ = RegSetValueEx(
this->m_handle_,
key.c_str(),
0,
REG_DWORD,
(const BYTE*)&value,
sizeof(value));
if (!ret_)
{
return true;
}
_tprintf(_T("[%s] error [%u]\n"), _T("RegSetValue"), ret_);
return false;
}
bool Write(const String& key, const String& str)
{
LONG ret_ = RegSetValueEx(
this->m_handle_,
key.c_str(),
0,
REG_SZ,
(const BYTE*)str.c_str(),
(str.size() + 1)*sizeof(TCHAR));
if (!ret_)
{
return true;
}
_tprintf(_T("[%s] error [%u]\n"), _T("RegSetValue"), ret_);
return false;
}
bool Read(const String& key, DWORD* value)
{
assert(value);
DWORD type_ = 0;
DWORD len_ = sizeof(*value);
LONG ret_ = RegQueryValueEx(
this->m_handle_,
key.c_str(),
0,
&type_,
(LPBYTE)value,
&len_);
if (!ret_ && len_ == sizeof(*value) && type_ == REG_DWORD)
{
return true;
}
_tprintf(_T("[%s] error [%u|%u|%u]\n"),
_T("RegQueryValueEx"), ret_,len_,type_);
return false;
}
bool Read(const String& key, String* value)
{
assert(value);
DWORD type_ = 0;
DWORD len_ = 0;
LONG ret_ = RegQueryValueEx(
this->m_handle_,
key.c_str(),
0,
&type_,
NULL,
&len_);
if (!ret_ && type_ == REG_SZ)
{
assert(len_%sizeof(TCHAR) == 0);
TCHAR* ptr_ = new TCHAR[len_ / sizeof(TCHAR)];
ret_ = RegQueryValueEx(
this->m_handle_,
key.c_str(),
0,
&type_,
(LPBYTE)ptr_,
&len_);
if (!ret_)
{
*value = ptr_;
delete[] ptr_;
return true;
}
delete[] ptr_;
}
_tprintf(_T("[%s] error [%u|%u|%u]\n"),
_T("RegQueryValueEx"), ret_, len_, type_);
return false;
}
bool Stat(const String& key,DWORD* type,DWORD* len)
{
assert(type && len);
LONG ret_ = RegQueryValueEx(
this->m_handle_,
key.c_str(),
0,
type,
NULL,
len);
if (!ret_)
{
return true;
}
_tprintf(_T("[%s] error [%u|%u|%u]\n"),
_T("RegQueryValueEx"), ret_, *len, *type);
return false;
}
// delete
bool Delete(const String& key)
{
size_t pos_ = key.rfind(_T('\\'));
if (pos_ != String::npos)
{
_tprintf(_T("[%s] error path %s\n"),
_T("Delete"),
m_path_.c_str());
return false;
}
LONG ret_ = RegDeleteValue(
this->m_handle_,
key.c_str());
if (!ret_)
{
return true;
}
_tprintf(_T("[%s] error [%u]\n"), _T("RegDeleteKey"), ret_);
return false;
}
private:
bool OpenImp(HKEY hKey, const String& path, REGSAM desired)
{
LONG ret_ = RegOpenKeyEx(
hKey,
path.c_str(),
0,
desired,
&m_handle_);
if (!ret_)
{
this->m_path_ = path;
this->m_desired_ = desired;
this->m_root_ = hKey;
return true;
}
m_handle_ = NULL;
_tprintf(_T("[%s] error [%u]\n"), _T("RegOpenKeyEx"), ret_);
return false;
}
private:
HKEY m_root_;
HKEY m_handle_;
REGSAM m_desired_;
String m_path_;
};
int _tmain(int argc, _TCHAR* argv[])
{
Reg reg_;
if (!reg_.OpenReadWrite(HKEY_CURRENT_USER, _T("Software\\Tiled")))
return -1;
assert(reg_.CreateDir(_T("fuck")));
_tprintf(_T("[%s] [%s]\n"), _T("PWD"), reg_.Pwd().c_str());
assert(reg_.Write(_T("fuck"), 1234));
assert(reg_.Goto(_T("fuck")));
assert(reg_.Write(_T("fuck"), 12345));
assert(reg_.Write(_T("fuck"), 123456));
DWORD ret_;
assert(reg_.Read(_T("fuck"), &ret_));
_tprintf(_T("Read [%u]\n"), ret_);
assert(reg_.Write(_T("str"), _T("FUCK")));
String str_;
assert(reg_.Read(_T("str"), &str_));
_tprintf(_T("[%s] [%s]\n"), _T("Read"), str_.c_str());
assert(reg_.Delete(_T("fuck")));
assert(reg_.Delete(_T("str")));
assert(reg_.GotoParent());
assert(reg_.Delete(_T("fuck")));
_tprintf(_T("[%s] [%s]\n"), _T("PWD"), reg_.Pwd().c_str());
assert(reg_.DeleteDir(_T("fuck")));
Reg reg2_;
if (!reg2_.OpenReadWrite(HKEY_CURRENT_USER, _T("Software\\Thunder Network")))
return -1;
assert(reg_.CreateDir(_T("fuck\\fuck1")));
assert(reg_.Goto(_T("fuck")));
assert(reg_.Goto(_T("fuck1")));
assert(reg_.Write(_T("str"), _T("FUCK")));
assert(reg_.Write(_T("fuck"), 123456));
assert(reg_.GotoParent());
assert(reg_.GotoParent());
assert(reg_.CopyDir(_T("fuck"), reg2_));
assert(reg_.DeleteDir(_T("fuck")));
DWORD dircnt_, filecnt_, dirmaxlen_, filemaxlen_;
assert(reg2_.StatDir(&dircnt_, &filecnt_, &dirmaxlen_, &filemaxlen_));
for (DWORD i = 0; i < dircnt_; i++)
{
String dirname_;
assert(reg2_.GetSubDir(i, dirmaxlen_, &dirname_));
_tprintf(_T("dirname %s\n"), dirname_.c_str());
}
for (DWORD i = 0; i < filecnt_; i++)
{
String filename_;
DWORD type_;
assert(reg2_.GetSubFile(i, filemaxlen_, &filename_, &type_));
_tprintf(_T("filename %s %d\n"), filename_.c_str(),type_);
}
assert(reg2_.DeleteDir(_T("fuck1")));
return 0;
}