// ------------------------------------------------------------------------------------------------------------------------------------------------------
// - This file are split up in two parts: -
// - -
// - 1. CLASSES/FUNCTIONS ETC. NEEDED FOR THE TEST PROJ'S ONLY. -
// - 2. CLASSES/FUNCTIONS ETC. NEEDED FOR THE LOCAL-MACHINE-REG. TO WORK AS DESCRIBED IN THE CP ARTICLE. -
// - -
// - Michael Mogensen, Copenhagen DK january 2009, michael-mogensen-danmark@hotmail.com. -
// ------------------------------------------------------------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------------------------------------------------------------
// - Miscellaneous. -
// ------------------------------------------------------------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------------------------------------------------------------
// - Header(s). -
// ------------------------------------------------------------------------------------------------------------------------------------------------------
#include "stdafx.h"
#include "mfcutil2.h"
// ------------------------------------------------------------------------------------------------------------------------------------------------------
// - Miscellaneous. -
// ------------------------------------------------------------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------------------------------------------------------------
// - -
// - -
// - 1. CLASSES/FUNCTIONS ETC. NEEDED FOR THE TEST PROJ'S ONLY. -
// - -
// - -
// ------------------------------------------------------------------------------------------------------------------------------------------------------
// ...all inlined...
// ------------------------------------------------------------------------------------------------------------------------------------------------------
// - -
// - -
// - 2. CLASSES/FUNCTIONS ETC. NEEDED FOR THE REG. -
// - -
// - -
// ------------------------------------------------------------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------------------------------------------------------------
// - CNTPTime. -
// ------------------------------------------------------------------------------------------------------------------------------------------------------
const long CNTPTime::sm_lJan1St_1900 = 2415021;
// 1. Constructors. (alphabetical).
CNTPTime::CNTPTime() :
m_Time(0)
// Default constructor.
{}
CNTPTime::CNTPTime(const CNTPTime& time)
// Copy constructor.
{
*this = time;
}
CNTPTime::CNTPTime(SNTPTimePacket& packet)
// Ex. constructor.
{
DWORD dwLow = ::ntohl(packet.m_dwFractional);
DWORD dwHigh = ::ntohl(packet.m_dwInteger);
m_Time = ((unsigned __int64) dwHigh) << 32;
m_Time += dwLow;
}
// 3. Methods. (alphabetical).
CNTPTime& CNTPTime::operator=(const CNTPTime& time)
// Assignment.
{
m_Time = time.m_Time;
return *this;
}
CNTPTime::operator SYSTEMTIME() const
// SYSTEMTIME cast operator. This operator only operates correctly in the 1900 - 2036 primary epoch defined by NTP.
{
SYSTEMTIME st;
DWORD s = Seconds();
st.wSecond = (WORD)(s % 60);
s /= 60;
st.wMinute = (WORD)(s % 60);
s /= 60;
st.wHour = (WORD)(s % 24);
s /= 24;
long JD = s + sm_lJan1St_1900;
st.wDayOfWeek = (WORD)((JD + 1) % 7);
GetGregorianDate(JD, st.wYear, st.wMonth, st.wDay);
return st;
}
CNTPTime::operator SNTPTimePacket() const
// SNTPTimePacket cast operator.
{
SNTPTimePacket ntp;
ntp.m_dwInteger = ::htonl(Seconds());
ntp.m_dwFractional = ::htonl(Fraction());
return ntp;
}
void CNTPTime::GetGregorianDate(long lJD, WORD& dwYear, WORD& dwMonth, WORD& dwDay) // Is static.
// Convert long JD into year, month and day.
{
long j = lJD - 1721119;
long y = (4 * j - 1) / 146097;
j = 4 * j - 1 - 146097 * y;
long d = j / 4;
j = (4 * d + 3) / 1461;
d = 4 * d + 3 - 1461 * j;
d = (d + 4) / 4;
long m = (5 * d - 3) / 153;
d = 5 * d - 3 - 153 * m;
d = (d + 5) / 5;
y = 100 * y + j;
if (m < 10)
m = m + 3;
else
{
m = m - 9;
y = y + 1;
}
// Set.
dwYear = (WORD)y;
dwMonth = (WORD)m;
dwDay = (WORD)d;
}
// ------------------------------------------------------------------------------------------------------------------------------------------------------
// - CRegistryAccess. -
// ------------------------------------------------------------------------------------------------------------------------------------------------------
// 1. Constructors. (alphabetical).
//
//
// HKEY_CURRENT_USER
// +--- AppEvents <--- This is a main key.
// +--- Console
// +--- ControlPanel
// +--- Enviroment
// +--- ...
// +--- Software
// +--- MyProgram <--- This is a sub key.
// +--- ...
//
CRegistryAccess::CRegistryAccess(const CString &cstrMainKey, const CString &cstrSubKey, const bool bHiddenName) :
m_hKey(NULL),
m_bHiddenName(bHiddenName),
m_cstrMainKey(cstrMainKey),
m_cstrSubKey(cstrSubKey)
// Create.
{
// To use RegSaveKey(...), the current user must have the SE_BACKUP_NAME privilege
// and your program must enable that privilege before executing RegSaveKey(...).
// RegRestoreKey(...) requires that the SE_RESTORE_NAME be held and enabled.
EnableProcessPrivilege(SE_BACKUP_NAME, TRUE);
// Open or create main key.
const CString cstrKey(FormatKey(m_cstrMainKey, m_cstrSubKey)); // Like "Software\MyProgram".
m_hKey = OpenKey(cstrKey);
if(!m_hKey)
m_hKey = CreateKey(cstrKey);
VERIFY(m_hKey);
}
CRegistryAccess::~CRegistryAccess()
// Destroy.
{
// Close main key.
CloseKey(m_hKey);
}
// 3. Methods. (alphabetical).
const bool CRegistryAccess::CloseKey(HKEY hKey)
// Return key on created and NULL if not.
//
// Principle.
//
// HKEY_CURRENT_USER
// +--- AppEvents
// +--- Console
// +--- ControlPanel
// +--- Enviroment
// +--- ...
// +--- Software
// +--- MyProgram <--- Close this.
// +----------+----------+---------+
// | Name | Type | Data |
// +----------+----------+---------+
// | VAL0 | TYPE0 | 10 |
// | VAL1 | TYPE1 | 20 |
// | VAL2 | TYPE2 | 30 |
// +----------+----------+---------+
//
// Result of CloseKey("MyProgram").
//
{
TRY
{
LONG lResult = ::RegCloseKey(hKey);
if(lResult == ERROR_SUCCESS)
return true;
return false;
}
CATCH_ALL(e)
{
WNDTRACEEXCEPTION_USERDLG("CRegistryAccess", "CloseKey", "", e);
THROW_LAST();
}
END_CATCH_ALL
return false;
}
HKEY CRegistryAccess::CreateKey(const CString &cstrKey)
// Return key on created and NULL if not.
//
// Principle.
//
// HKEY_CURRENT_USER
// +--- AppEvents
// +--- Console
// +--- ControlPanel
// +--- Enviroment
// +--- ...
// +--- Software
// +--- MyProgram <--- Create this.
// +----------+----------+---------+
// | Name | Type | Data |
// +----------+----------+---------+
// | VAL0 | TYPE0 | 10 |
// | VAL1 | TYPE1 | 20 |
// | VAL2 | TYPE2 | 30 |
// +----------+----------+---------+
//
// Result of CreateKey("MyProgram").
//
{
TRY
{
HKEY hKeyNew = (HKEY)NULL;
TCHAR szName[MAX_KEY_LENGTH] = _T("");
::wsprintf(szName, TEXT("%s"), (LPCTSTR)cstrKey);
DWORD dwDisp = 0;
LONG lResult = ::RegCreateKeyEx(
HKEY_CURRENT_USER,
szName,
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_FULL_ACCESS,
NULL,
&hKeyNew,
&dwDisp);
if(lResult == ERROR_SUCCESS)
return hKeyNew;
return NULL;
}
CATCH_ALL(e)
{
WNDTRACEEXCEPTION_USERDLG("CRegistryAccess", "CreateKey", "", e);
THROW_LAST();
}
END_CATCH_ALL
}
const bool CRegistryAccess::DataExist(const CString &cstrName)
// Return T if data exist and F if not.
//
// Principle.
//
// HKEY_CURRENT_USER
// +--- AppEvents
// +--- Console
// +--- ControlPanel
// +--- Enviroment
// +--- ...
// +--- Software
// +--- MyProgram
// +----------+----------+---------+
// | Name | Type | Data |
// +----------+----------+---------+
// | VAL0 | TYPE0 | 10 | <--- Check existence of "VAL0".
// | VAL1 | TYPE1 | 20 |
// | VAL2 | TYPE2 | 30 |
// +----------+----------+---------+
//
// Result of DataExist("VAL0") = { T, F }.
//
{
TRY
{
const CString cstrNameEx(m_bHiddenName ? GetLongName(cstrName) : cstrName); // Make name long if hidden.
CString cstrNameFound(_T(""));
TCHAR szName[MAX_NAME_LENGTH] = _T("");
DWORD dwSize = MAX_NAME_LENGTH;
DWORD dwIndex = 0;
while(::RegEnumValue(
m_hKey,
dwIndex++,
szName,
&dwSize,
NULL,
NULL,
NULL,
NULL) != ERROR_NO_MORE_ITEMS)
{
cstrNameFound.Format(TEXT("%s"), szName);
if(cstrNameFound.CompareNoCase(cstrNameEx) == 0)
return true;
dwSize = MAX_NAME_LENGTH;
}
return false;
}
CATCH_ALL(e)
{
WNDTRACEEXCEPTION_USERDLG("CRegistryAccess", "DataExist", "", e);
THROW_LAST();
}
END_CATCH_ALL
return false;
}
const bool CRegistryAccess::DeleteData(const CString &cstrName)
// Return T on deleted data and F if not.
//
// Principle.
//
// HKEY_CURRENT_USER
// +--- AppEvents
// +--- Console
// +--- ControlPanel
// +--- Enviroment
// +--- ...
// +--- Software
// +--- MyProgram
// | +----------+----------+---------+
// | | Name | Type | Data |
// | +----------+----------+---------+
// | | VAL0 | TYPE0 | 10 |
// | | VAL1 | TYPE1 | 20 | <--- Like delete this.
// | | VAL2 | TYPE2 | 30 |
// | +----------+----------+---------+
//
{
TRY
{
// Delete data.
LONG lResult = ::RegDeleteValue(
m_hKey,
m_bHiddenName ? GetLongName(cstrName) : cstrName); // Make name long if hidden.
if(lResult == ERROR_SUCCESS)
return true;
return false;
}
CATCH_ALL(e)
{
WNDTRACEEXCEPTION_USERDLG("CRegistryAccess", "DeleteData", "", e);
THROW_LAST();
}
END_CATCH_ALL
}
const bool CRegistryAccess::DeleteData()
// Return T on deleted data and F if not.
//
// Principle.
//
// HKEY_CURRENT_USER
// +--- AppEvents
// +--- Console
// +--- ControlPanel
// +--- Enviroment
// +--- ...
// +--- Software
// +--- MyProgram
// | +----------+----------+---------+ <--- Delete this table.
// | | Name | Type | Data |
// | +----------+----------+---------+
// | | VAL0 | TYPE0 | 10 |
// | | VAL1 | TYPE1 | 20 |
// | | VAL2 | TYPE2 | 30 |
// | +----------+----------+---------+
//
{
TRY
{
// Delete all data.
bool bResult = true;
CString cstrName(_T(""));
TCHAR szName[MAX_NAME_LENGTH] = _T("");
DWORD dwSize = MAX_NAME_LENGTH;
while(::RegEnumValue(
m_hKey,
0, // Remove only from top because we delete while we enum.
szName,
&dwSize,
NULL,
NULL,
NULL,
NULL) != ERROR_NO_MORE_ITEMS)
{
cstrName.Format(TEXT("%s"), szName);
bResult = bResult & DeleteData(cstrName);
dwSize = MAX_NAME_LENGTH;
}
return bResult;
}
CATCH_ALL(e)
{
WNDTRACEEXCEPTION_USERDLG("CRegistryAccess", "DeleteData", "", e);
THROW_LAST();
}
END_CATCH_ALL
}
const bool CRegistryAccess::DeleteKey()
// Return T on deleted data and F if not. Key must have no subkeys. Calling this is harakiri.
//
// Principle.
//
// HKEY_CURRENT_USER
// +--- AppEvents
// +--- Console
// +--- ControlPanel
// +--- Enviroment
// +--- ...
// +--- Software
// +--- MyProgram <--- Delete this.
// +----------+----------+---------+
// | Name | Type | Data |
// +----------+----------+---------+
// | VAL0 | TYPE0 | 10 |
// | VAL1 | TYPE1 | 20 |
// | VAL2 | TYPE2 | 30 |
// +----------+----------+---------+
//
// Usage: DeleteKey("MyProgram").
//
{
TRY
{
// Delete key itself.
LONG lResult = 0;
if(CloseKey(m_hKey))
{
m_hKey = OpenKey(m_cstrMainKey);
if(m_hKey)
lResult = ::RegDeleteKey(m_hKey, m_cstrSubKey);
}
if(lResult == ERROR_SUCCESS)
return true;
return false;
}
CATCH_ALL(e)
{
WNDTRACEEXCEPTION_USERDLG("CRegistryAccess", "DeleteKey", "", e);
THROW_LAST();
}
END_CATCH_ALL
}
BOOL WINAPI CRegistryAccess::EnableProcessPrivilege(LPCTSTR lpPrivilege, BOOL bEnable)
// This static method enables or disables a privilege for the current process. Common privileges include SE_SHUTDOWN_NAME, SE_BACKUP_NAME,
// SE_SYSTEMTIME_NAME, etc. and are found in winnt.h. This function dynamically loads the required functions so as not to cause load
// problems on 9x where these functions may not be available.
{
TRY
{
typedef BOOL (WINAPI * fnptr_openprocesstoken)(HANDLE,DWORD,PHANDLE);
typedef BOOL (WINAPI * fnptr_adjusttokenprivileges)(HANDLE,BOOL,PTOKEN_PRIVILEGES,DWORD,PTOKEN_PRIVILEGES,PDWORD);
typedef BOOL (WINAPI * fnptr_lookupprivilegevalue)(LPCTSTR,LPCTSTR,PLUID);
TOKEN_PRIVILEGES tp = { 0 };
HMODULE hAdvapi = NULL;
HANDLE hToken = NULL;
BOOL bResult = FALSE;
fnptr_openprocesstoken openprocesstoken;
fnptr_adjusttokenprivileges adjusttokenprivileges;
fnptr_lookupprivilegevalue lookupprivilegevalue;
// Load the required functions.
if (!(hAdvapi = LoadLibrary(TEXT("Advapi32.dll"))) ||
!(openprocesstoken = (fnptr_openprocesstoken)GetProcAddress(hAdvapi, "OpenProcessToken")) ||
!(adjusttokenprivileges = (fnptr_adjusttokenprivileges)GetProcAddress(hAdvapi, "AdjustTokenPrivileges")) ||
#ifndef UNICODE
!(lookupprivilegevalue = (fnptr_lookupprivilegevalue)GetProcAddress(hAdvapi, "LookupPrivilegeValueA")))
#else
!(lookupprivilegevalue = (fnptr_lookupprivilegevalue)GetProcAddress(hAdvapi, "LookupPrivilegeValueW")))
#endif
{
goto cleanup;
}
// Get the local id of our desired privilege.
if(!lookupprivilegevalue(NULL, lpPrivilege, &tp.Privileges[0].Luid))
goto cleanup;
tp.PrivilegeCount = 1;
tp.Privileges[0].Attributes = (bEnable ? SE_PRIVILEGE_ENABLED : 0);
// Get the access token for the current process.
if(!openprocesstoken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
goto cleanup;
// Enable the privilege.
if(!adjusttokenprivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL))
goto cleanup;
bResult = TRUE;
// Always do this.
cleanup:
if(hAdvapi)
::FreeLibrary(hAdvapi);
if(hToken)
::CloseHandle(hToken);
// Success.
return bResult;
}
CATCH_ALL(e)
{
WNDTRACEEXCEPTION_USERDLG("CRegistryAccess", "EnableProcessPrivilege", "", e);
THROW_LAST();
}
END_CATCH_ALL
// Failure.
return false;
}
const CString CRegistryAccess::FormatKey(const CString &cstrMainKey, const CString &cstrSubKey)
// Return sub key to main key - like "Software\MyProgram" or "Consol\MyProgram".
{
TRY
{
CString cstrFullKey(_T(""));
if(cstrSubKey.IsEmpty())
cstrFullKey.Format(TEXT("%s"), cstrMainKey);
else
cstrFullKey.Format(TEXT("%s\\%s"), cstrMainKey, cstrSubKey);
return cstrFullKey;
}
CATCH_ALL(e)
{
WNDTRACEEXCEPTION_USERDLG("CRegistryAccess", "FormatKey", "", e);
THROW_LAST();
}
END_CATCH_ALL
}
const void CRegistryAccess::GetAll(CArray<SNameTypeData, SNameTypeData> &arrNameTypeData)
// Return array of name, type and data under a key (not its subkeys).
//
// Principle.
//
// HKEY_CURRENT_USER
// +--- AppEvents
// +--- Console
// +--- ControlPanel
// +--- Enviroment
// +--- ...
// +--- Software
// +--- MyProgram
// +----------+----------+---------+
// | Name | Type | Data |
// +----------+----------+---------+
// | VAL0 | TYPE0 | 10 | <--- Read this table.
// | VAL1 | TYPE1 | 20 |
// | VAL2 | TYPE2 | 30 |
// +----------+----------+---------+
//
// Usage: GetAll("MyProgram") = { ( VAL0, TYPE0, DATA0 ), ( VAL1, TYPE1, DATA1 ), ( VAL2, TYPE2, DATA2 ) }.
//
{
TRY
{
LONG lResult = 0;
CString cstrNameFound(_T(""));
TCHAR szName[MAX_NAME_LENGTH] = _T("");
DWORD dwcbName= MAX_NAME_LENGTH;
DWORD dwIndex = 0;
DWORD dwType = MAX_PATH;
BYTE btData[MAX_PATH];
DWORD dwcbData = MAX_PATH;
arrNameTypeData.SetSize(0, 1);
arrNameTypeData.RemoveAll();
while((lResult = ::RegEnumValue(
m_hKey,
dwIndex++,
szName,
&dwcbName,
NULL,
&dwType,
btData,
&dwcbData) != ERROR_NO_MORE_ITEMS))
{
// Add name, type and data.
SNameTypeData ntd;
// The name.
ntd.m_cstrName.Format(TEXT("%s"), szName);
// The type and data.
switch(dwType)
{
case REG_NONE: // No value type.
ntd.m_cstrType = _T("REG_NONE");
ntd.m_cstrData.Format(TEXT("%s"), _T("?"));
break;
case REG_SZ: // Unicode nul terminated string.
ntd.m_cstrType = _T("REG_SZ");
ntd.m_cstrData.Format(TEXT("%s"), (LPSTR)btData);
break;
case REG_EXPAND_SZ: // Unicode nul terminated string (with environment variable references).
ntd.m_cstrType = _T("REG_EXPAND_SZ");
ntd.m_cstrData.Format(TEXT("%s"), _T("?"));
break;
case REG_BINARY: // Free form binary.
ntd.m_cstrType = _T("REG_BINARY");
ntd.m_cstrData.Format(TEXT("%s"), _T("?"));
break;
case REG_DWORD: // 32-bit number (same as REG_DWORD_LITTLE_ENDIAN):
ntd.m_cstrType = _T("REG_DWORD");
ntd.m_cstrData.Format(TEXT("%d"), (int)*btData);
break;
case REG_DWORD_BIG_ENDIAN: // 32-bit number.
ntd.m_cstrType = _T("REG_DWORD_BIG_ENDIAN");
ntd.m_cstrData.Format(TEXT("%s"), _T("?"));
break;
case REG_LINK: // Symbolic Link (unicode).
ntd.m_cstrType = _T("REG_LINK");
ntd.m_cstrData.Format(TEXT("%s"), _T("?"));
break;
case REG_MULTI_SZ: // Multiple Unicode strings.
ntd.m_cstrType = _T("REG_MULTI_SZ");
ntd.m_cstrData.Format(TEXT("%s"), _T("?"));
break;
case REG_RESOURCE_LIST: // Resource list in the resource map.
ntd.m_cstrType = _T("REG_RESOURCE_LIST");
ntd.m_cstrData.Format(TEXT("%s"), _T("?"));
break;
case REG_FULL_RESOURCE_DESCRIPTOR: // Resource list in the hardware description.
ntd.m_cstrType = _T("REG_FULL_RESOURCE_DESCRIPTOR");
ntd.m_cstrData.Format(TEXT("%s"), _T("?"));
break;
case REG_RESOURCE_REQUIREMENTS_LIST:
ntd.m_cstrType = _T("REG_RESOURCE_REQUIREMENTS_LIST");
ntd.m_cstrData.Format(TEXT("%s"), _T("?"));
break;
case REG_QWORD: // 64-bit number (same as REG_QWORD_LITTLE_ENDIAN).
ntd.m_cstrType = _T("REG_QWORD");
ntd.m_cstrData.Format(TEXT("%s"), _T("?"));
break;
default:
ntd.m_cstrType = _T("REG_UNKNOWN");
ntd.m_cstrData.Format(TEXT("%s"), _T("?"));
break;
}
// Append.
arrNameTypeData.Add(ntd);
// Next.
dwcbName = MAX_NAME_LENGTH;
dwType = MAX_PATH;
dwcbData = MAX_PATH;
}
}
CATCH_ALL(e)
{
WNDTRACEEXCEPTION_USERDLG("CRegistryAccess", "GetAll", "", e);
THROW_LAST();
}
END_CATCH_ALL
}
const void CRegistryAccess::GetAllNames(CStringArray &arrNames)
// Return array of names. See also GetAll(...).
//
// Principle.
//
// HKEY_CURRENT_USER
// +--- AppEvents
// +--- Console
// +--- ControlPanel
// +--- Enviroment
// +--- ...
// +--- Software
// +--- MyProgram
// +----------+----------+---------+
// | Name | Type | Data |
// +----------+----------+---------+
// | VAL0 | TYPE0 | 10 |
// | VAL1 | TYPE1 | 20 |
// | VAL2 | TYPE2 | 30 |
// +----------+----------+---------+
//
// Usage: GetAllNames("MyProgram") = { VAL0, VAL1, VAL2 }.
//
{
TRY
{
CArray<CRegistryAccess::SNameTypeData, CRegistryAccess::SNameTypeData> arrNameTypeData;
GetAll(arrNameTypeData);
arrNames.SetSize(0, 1);
arrNames.RemoveAll();
for(int iId = 0; iId < arrNameTypeData.GetSize(); iId++)
{
CRegistryAccess::SNameTypeData ntd = arrNameTypeData.GetAt(iId);
arrNames.Add(ntd.m_cstrName);
}
}
CATCH_ALL(e)
{
WNDTRACEEXCEPTION_USERDLG("CRegistryAccess", "GetAllNames", "", e);
THROW_LAST();
}
END_CATCH_ALL
}
const void CRegistryAccess::GetAllTypes(CStringArray &arrTypes)
// Return array of types. See also GetAll(...).Names
//
// Principle.
//
// HKEY_CURRENT_USER
// +--- AppEvents
// +--- Console
// +--- ControlPanel
// +--- Enviroment
// +--- ...
// +--- Software
// +--- MyProgram
// +----------+----------+---------+
// | Name | Type | Data |
// +----------+----------+---------+
// | VAL0 | TYPE0 | 10 |
// | VAL1 | TYPE1 | 20 |
// | VAL2 | TYPE2 | 30 |
// +----------+----------+---------+
//
// Usage: GetAllTypes("MyProgram") = { TYPE0, TYPE1, TYPE2 }.
//
{
TRY
{
CArray<CRegistryAccess::SNameTypeData, CRegistryAccess::SNameTypeData> arrNameTypeData;
GetAll(arrNameTypeData);
arrTypes.SetSize(0, 1);
arrTypes.RemoveAll();
for(int iId = 0; iId < arrNameTypeData.GetSize(); iId++)
{
CRegistryAccess::SNameTypeData ntd = arrNameTypeData.GetAt(iId);
arrTypes.Add(ntd.m_cstrType);
}
}
CATCH_ALL(e)
{
WNDTRACEEXCEPTION_USERDLG("CRegistryAccess", "GetAllTypes", "", e);
THROW_LAST();
}
END_CATCH_ALL
}
const void CRegistryAccess::GetAllDatas(CStringArray &arrDatas)
// Return array of names. See also GetAll(...).
//
// Principle.
//
// HKEY_CURRENT_USER
// +--- AppEvents
// +--- Console
// +--- ControlPanel
// +--- Enviroment
// +--- ...
// +--- Software
// +--- MyProgram
// +----------+----------+---------+
// | Data | Type | Data |
// +----------+----------+---------+
// | VAL0 | TYPE0 | 10 |
// | VAL1 | TYPE1 | 20 |
// | VAL2 | TYPE2 | 30 |
// +----------+----------+---------+
//
// Usage: GetAllDatas("MyProgram") = { 10, 20, 30 }.
//
{
TRY
{
CArray<CRegistryAccess::SNameTypeData, CRegistryAccess::SNameTypeData> arrNameTypeData;
GetAll(arrNameTypeData);
arrDatas.SetSize(0, 1);
arrDatas.RemoveAll();
for(int iId = 0; iId < arrNameTypeData.GetSize(); iId++)
{
CRegistryAccess::SNameTypeData ntd = arrNameTypeData.GetAt(iId);
arrDatas.Add(ntd.m_cstrData);
}
}
CATCH_ALL(e)
{
WNDTRACEEXCEPTION_USERDLG("CRegistryAccess", "GetAllDatas", "", e);
THROW_LAST();
}
END_CATCH_ALL
}
const bool CRegistryAccess::GetData(const CString &cstrName, DWORD &dwValue) // Ends up as a REG_DWORD.
// Return T on success and F if not.
{
TRY
{
return GetDataDWORD(cstrName, dwValue);
}
CATCH_ALL(e)
{
WNDTRACEEXCEPTION_USERDLG("CRegistryAccess", "GetData", "", e);
THROW_LAST();
}
END_CATCH_ALL
}
const bool CRegistryAccess::GetData(const CString &cstrName, CString& cstrValue) // Ends up as a REG_SZ.
// Return T on success and F if not.
{
TRY
{
return GetDataSZ(cstrName, cstrValue);
}
CATCH_ALL(e)
{
WNDTRACEEXCEPTION_USERDLG("CRegistryAccess", "GetData", "", e);
THROW_LAST();
}
END_CATCH_ALL
}
const bool CRegistryAccess::GetData(const CString &cstrName, int &iValue) // Ends up as a REG_DWORD.
// Return T on success and F if not.
{
TRY
{
DWORD dwValue = 0;
const bool bResult = GetData(cstrName, dwValue);
if(bResult)
iValue = (int)dwValue;
else
iValue = 0;
return bResult;
}
CATCH_ALL(e)
{
WNDTRACEEXCEPTION_USERDLG("CRegistryAccess", "GetData", "", e);
THROW_LAST();
}
END_CATCH_ALL
}
const bool CRegistryAccess::GetData(const CString &cstrName, bool &bValue) // Ends up as a REG_DWORD.
// Return T on success and F if not.
{
TRY
{
int iValue = 0;
const bool bResult = GetData(cstrName, iValue);
if(bResult)
bValue = (iValue != 0);
else
bValue = false;
return bResult;
}
CATCH_ALL(e)
{
WNDTRACEEXCEPTION_USERDLG("CRegistryAccess", "GetData", "", e);
THROW_LAST();
}
END_CATCH_ALL
}
const bool CRegistryAccess::GetDataDWORD(const CString &cstrName, DWORD &dwValue)
// Return T on success and F if not.
{
TRY
{
HKEY hKey = (HKEY)NULL;
DWORD dwQueryType = REG_DWORD;
DWORD dwQuerySize = sizeof(DWORD);
dwValue = 0;
LONG lResult = ::RegQueryValueEx(
m_hKey,
m_bHiddenName ? GetLongName(cstrName) : cstrName, // Make name long if hidden.
NULL,
&dwQueryType,
(LPBYTE)&dwValue,
&dwQuerySize);
return(lResult == ERROR_SUCCESS);
}
CATCH_ALL(e)
{
WNDTRACEEXCEPTION_USERDLG("CRegistryAccess", "GetDataDWORD", "", e);
THROW_LAST();
}
END_CATCH_ALL
}
const bool CRegistryAccess::GetDataSZ(const CString &cstrName, CString &cstrValue)
// Return T on success and F if not.
{
TRY
{
HKEY hKey = (HKEY)NULL;
DWORD dwQueryType = REG_SZ;
TCHAR szName[MAX_VALUE_LENGTH] = _T("");
DWORD dwQuerySize = MAX_VALUE_LENGTH - 1;
cstrValue.Empty();
LONG lResult = ::RegQueryValueEx(
m_hKey,
m_bHiddenName ? GetLongName(cstrName) : cstrName, // Make name long if hidden.
NULL,
&dwQueryType,
(LPBYTE)szName,
&dwQuerySize);
if(lResult == ERROR_SUCCESS)
{
cstrValue.Format(TEXT("%s"), szName);
return true;
}
return false;
}
CATCH_ALL(e)
{
WNDTRACEEXCEPTION_USERDLG("CRegistryAccess", "GetDataSZ", "", e);
THROW_LAST();
}
END_CATCH_ALL
}
const CString CRegistryAccess::GetLongName(const CString &cstrName)
// Return long name (for invisible entries).
{
TRY
{
// 0 0 0 0 = 40
// 0123456789012345678901234567890123456789
// MAGGIEBARTLISAMARGEHOMERSIMPSONSPIDERPIG
static const CString s_cstr255Chars(
_T("MAGGIEBARTLISAMARGEHOMERSIMPSONSPIDERPIG")
_T("MAGGIEBARTLISAMARGEHOMERSIMPSONSPIDERPIG")
_T("MAGGIEBARTLISAMARGEHOMERSIMPSONSPIDERPIG")
_T("MAGGIEBARTLISAMARGEHOMERSIMPSONSPIDERPIG")
_T("MAGGIEBARTLISAMARGEHOMERSIMPSONSPIDERPIG")
_T("MAGGIEBARTLISAMARGEHOMERSIMPSONSPIDERPIG")
_T("ITCHYORSCRATCHY"));
CString cstrNameLong(s_cstr255Chars + cstrName);
return cstrNameLong;
}
CATCH_ALL(e)
{
WNDTRACEEXCEPTION_USERDLG("CRegistryAccess", "GetLongName", "", e);
THROW_LAST();
}
END_CATCH_ALL
}
HKEY CRegistryAccess::OpenKey(const CString &cstrKey)
// Return opned key handle on success and NULL if not
//
// Principle.
//
// HKEY_CURRENT_USER
// +--- AppEvents
// +--- Console
// +--- ControlPanel
// +--- Enviroment
// +--- ...
// +--- Software
// +--- MyProgram <--- Open this.
// +----------+----------+---------+
// | Name | Type | Data |
// +----------+----------+---------+
// | VAL0 | TYPE0 | 10 |
// | VAL1 | TYPE1 | 20 |
// | VAL2 | TYPE2 | 30 |
// +----------+----------+---------+
//
// Usage: OpenKey("MyProgram").
//
{
TRY
{
HKEY hKeyNew = (HKEY)NULL;
LONG lResult = ::RegOpenKeyEx(
HKEY_CURRENT_USER,
cstrKey,
0,
KEY_FULL_ACCESS,
&hKeyNew);
if(lResult == ERROR_SUCCESS)
return hKeyNew;
return NULL;
}
CATCH_ALL(e)
{
WNDTRACEEXCEPTION_USERDLG("CRegistryAccess", "OpenKey", "", e);
THROW_LAST();
}
END_CATCH_ALL
}
const bool CRegistryAccess::SetData(const CString &cstrName, CONST DWORD &dwValue) // Ends up as a REG_DWORD.
// Return T on deleted data and F if not.
{
TRY
{
return SetDataDWORD(cstrName, dwValue);
}
CATCH_ALL(e)
{
WNDTRACEEXCEPTION_USERDLG("CRegistryAccess", "SetData", "", e);
THROW_LAST();
}
END_CATCH_ALL
}
const bool CRegistryAccess::SetData(const CString &cstrName, const CString &cstrValue) // Ends up as a REG_SZ.
// Return T on deleted data and F if not.
{
TRY
{
return SetDataSZ(cstrName, cstrValue);
}
CATCH_ALL(e)
{
WNDTRACEEXCEPTION_USERDLG("CRegistryAccess", "SetData", "", e);
THROW_LAST();
}
END_CATCH_ALL
}
const bool CRegistryAccess::SetData(const CString &cstrName, const int &iValue) // Ends up as a REG_DWORD.
// Return T on deleted data and F if not.
{
TRY
{
return(SetData(cstrName, (DWORD)iValue));
}
CATCH_ALL(e)
{
WNDTRACEEXCEPTION_USERDLG("CRegistryAccess", "SetData", "", e);
THROW_LAST();
}
END_CATCH_ALL
}
const bool CRegistryAccess::SetData(const CString &cstrName, const bool &bValue) // Ends up as a REG_DWORD.
// Return T on deleted data and F if not.
{
TRY
{
const int iValue = (bValue ? 1 : 0);
return(SetData(cstrName, iValue));
}
CATCH_ALL(e)
{
WNDTRACEEXCEPTION_USERDLG("CRegistryAccess", "SetData", "", e);
THROW_LAST();
}
END_CATCH_ALL
}
const bool CRegistryAccess::SetDataDWORD(const CString &cstrName, CONST DWORD &dwValue)
// Return T on success and F if not.
//
// Principle.
//
// HKEY_CURRENT_USER
// +--- AppEvents
// +--- Console
// +--- ControlPanel
// +--- Enviroment
// +--- ...
// +--- Software
// +--- MyProgram
// +----------+----------+---------+
// | Name | Type | Data |
// +----------+----------+---------+
// | VAL0 | DWORD | 10 | <--- Set this.
// | VAL1 | SZ | "Hey" |
// | VAL2 | TYPE2 | 30 |
// +----------+----------+---------+
//
// Usage: SetDataDWORD("VAL0", 10);
//
{
TRY
{
LONG lResult = ::RegSetValueEx(
m_hKey,
m_bHiddenName ? GetLongName(cstrName) : cstrName, // Make name long if hidden.
0,
REG_DWORD,
(BYTE*)&dwValue,
sizeof(PDWORD));
return(lResult == ERROR_SUCCESS);
}
CATCH_ALL(e)
{
WNDTRACEEXCEPTION_USERDLG("CRegistryAccess", "SetDataDWORD", "", e);
THROW_LAST();
}
END_CATCH_ALL
}
const bool CRegistryAccess::SetDataSZ(const CString &cstrName, const CString &cstrValue)
// Return T on success and F if not.
//
// Principle.
//
// HKEY_CURRENT_USER
// +--- AppEvents
// +--- Console
// +--- ControlPanel
// +--- Enviroment
// +--- ...
// +--- Software
// +--- MyProgram
// +----------+----------+---------+
// | Name | Type | Data |
// +----------+----------+---------+
// | VAL0 | DWORD | 10 |
// | VAL1 | SZ | "Hey" | <--- Set this.
// | VAL2 | TYPE2 | 30 |
// +----------+----------+---------+
//
// Usage: SetDataSZ("VAL1", "Hey");
//
{
TRY
{
CString cstrValueEx(*const_cast<CString*>(&cstrValue));
LONG lResult = ::RegSetValueEx(
m_hKey,
m_bHiddenName ? GetLongName(cstrName) : cstrName, // Make name long if hidden.
0,
REG_SZ,
(BYTE*)cstrValueEx.GetBuffer(),
(DWORD)(sizeof(TCHAR) * (cstrValueEx.GetLength() + 1)));
return(lResult == ERROR_SUCCESS);
}
CATCH_ALL(e)
{
WNDTRACEEXCEPTION_USERDLG("CRegistryAccess", "SetDataSZ", "", e);
THROW_LAST();
}
END_CATCH_ALL
}
// ------------------------------------------------------------------------------------------------------------------------------------------------------
// - CNTPClient. -
// ------------------------------------------------------------------------------------------------------------------------------------------------------
// 1. Constructors. (alphabetical).
CNTPClient::CNTPClient() :
m_dwTimeout(5000)
// Create.
{}
// 3. Methods. (alphabetical).
const bool CNTPClient::GetServerTime(const CString &cstrHostName, SNTPServerResponse& sntpResponse, const int iPort)
{
// Create.
CNTPSocket* pSocket = new CNTPSocket();
if(!pSocket->Create())
{
DELETE_AND_DESTROY(pSocket);
return false;
}
// Connect to SNTP server.
if(!pSocket->Connect(cstrHostName, iPort))
{
DELETE_AND_DESTROY(pSocket);
return false;
}
// Initialise the SNTPBasicInfo packet.
SNTPBasicInfo sntpBasicInfo;
int nSendSize = sizeof(SNTPBasicInfo);
ZeroMemory(&sntpBasicInfo, nSendSize);
// Encoded representation which represents NTP Client Request & NTP version 3.0.
sntpBasicInfo.m_LiVnMode = 27;
// Send.
if(!pSocket->Send((LPCSTR)&sntpBasicInfo, nSendSize))
{
DELETE_AND_DESTROY(pSocket);
return false;
}
// Need to determine readibilty of socket.
if(!pSocket->IsReadable(m_dwTimeout))
{
DELETE_AND_DESTROY(pSocket);
return false;
}
// Read back the response into the SNTPFullPacket.
SNTPFullPacket sntpFullPacket;
const int iReceiveSize = sizeof(SNTPFullPacket);
::ZeroMemory(&sntpFullPacket, iReceiveSize);
if(!pSocket->Receive((LPSTR)&sntpFullPacket, iReceiveSize))
{
DELETE_AND_DESTROY(pSocket);
return false;
}
// Set result.
sntpResponse.m_ReceiveTime = sntpFullPacket.m_Basic.m_ReceiveTimestamp;
// Normal exit.
DELETE_AND_DESTROY(pSocket);
return true;
}
// ------------------------------------------------------------------------------------------------------------------------------------------------------
// - CNTPSocket. -
// ------------------------------------------------------------------------------------------------------------------------------------------------------
// 1. Constructors. (alphabetical).
CNTPSocket::CNTPSocket() :
m_hSocket(INVALID_SOCKET)
// Create.
{}
CNTPSocket::~CNTPSocket()
// Destroy.
{ Close(); }
// 3. Methods. (alphabetical).
const void CNTPSocket::Close()
// Close socket.
{
if(m_hSocket != INVALID_SOCKET)
{
VERIFY(SOCKET_ERROR != ::closesocket(m_hSocket));
m_hSocket = INVALID_SOCKET;
}
}
const bool CNTPSocket::Create()
// Create the socket. NTP uses UDP instead of the usual TCP.
{
m_hSocket = socket(AF_INET, SOCK_DGRAM, 0);
return(m_hSocket != INVALID_SOCKET);
}
const bool CNTPSocket::Connect(const CString &cstrHostAddress, const int iPort)
// Connect socket.
{
ASSERT(m_hSocket != INVALID_SOCKET);
USES_CONVERSION;
LPSTR lpszHostAddress = T2A((LPTSTR)(LPCTSTR)cstrHostAddress);
//Determine if the address is in dotted notation.
SOCKADDR_IN sockAddr;
::ZeroMemory(&sockAddr, sizeof(sockAddr));
sockAddr.sin_family = AF_INET;
sockAddr.sin_port = htons((u_short)iPort);
sockAddr.sin_addr.s_addr = inet_addr(lpszHostAddress);
//If the address is not dotted notation, then do a DNS lookup of it.
if (sockAddr.sin_addr.s_addr == INADDR_NONE)
{
LPHOSTENT lphost;
lphost = ::gethostbyname(lpszHostAddress);
if (lphost != NULL)
sockAddr.sin_addr.s_addr = ((LPIN_ADDR)lphost->h_addr)->s_addr;
else
return false;
}
// Call the protected version which takes an address in the form of a standard C style struct.
return(Connect((SOCKADDR*)&sockAddr, sizeof(sockAddr)));
}
const bool CNTPSocket::Connect(const SOCKADDR* lpSockAddr, const int iSockAddrLen)
// Connect socket.
{
ASSERT(m_hSocket != INVALID_SOCKET);
int nConnect = connect(m_hSocket, lpSockAddr, iSockAddrLen);
return(nConnect == 0);
}
const bool CNTPSocket::IsReadable(const DWORD dwTimeout)
// Return T if readable and F if not.
{
timeval timeout;
timeout.tv_sec = dwTimeout / 1000;
timeout.tv_usec = dwTimeout % 1000;
fd_set fds;
FD_ZERO(&fds);
FD_SET(m_hSocket, &fds);
int iStatus = select(0, &fds, NULL, NULL, &timeout);
if(iStatus == SOCKET_ERROR)
return false;
else
return(iStatus != 0);
}
const int CNTPSocket::Receive(LPSTR pszBuffer, const int iLength)
// Read recieved data on socket. Return number of bytes received on success.
{
ASSERT(m_hSocket != INVALID_SOCKET);
return(::recv(m_hSocket, pszBuffer, iLength, 0));
}
const bool CNTPSocket::Send(LPCSTR pszBuffer, const int iLength)
// Send data to socket.
{
ASSERT(m_hSocket != INVALID_SOCKET);
return(::send(m_hSocket, pszBuffer, iLength, 0) != SOCKET_ERROR);
}
// ------------------------------------------------------------------------------------------------------------------------------------------------------
// - CProgramRegistration. -
// ------------------------------------------------------------------------------------------------------------------------------------------------------
const CString CProgramRegistration::sm_cstrSNDummy = _T("00000-00000-00000-00000-00000-00000");
const CString CProgramRegistration::sm_cstrFirstRunRegKeyPostfix = _T("_FIRST_RUN");
const CString CProgramRegistration::sm_cstrSNRegKeyPostfix = _T("_SN");
// 1. Constructors. (alphabetical).
CProgramRegistration::CProgramRegistration(const CString &cstrAppName, const int iDaysToUseFreeOfCharge, const bool bHidden) :
m_cstrAppName(cstrAppName),
m_iDays2UseFreeOfCharge(iDaysToUseFreeOfCharge),
m_pregAccess(NULL)
// Create.
{
try
{
// Get official UTC-time.
if(!::GetInternetTime(m_dtNow))
{
// Abort.
AfxThrowUserException();
}
// From now on m_dtNow are the official UTC time!
m_pregAccess = new CRegistryAccess(_T("Console"), _T(""), bHidden);
VERIFY(m_pregAccess);
m_cstrAppName.MakeUpper();
// If first-time-run are present we read it back and if not we write it as m_dtNow.
if(!GetFirstRunDate(m_dtFirstRun))
{
m_dtFirstRun = m_dtNow;
SetFirstRunDate(m_dtFirstRun);
UnRegister();
}
// Calc. expire date.
m_dtExpire = m_dtFirstRun + COleDateTimeSpan(m_iDays2UseFreeOfCharge, 0, 0, 0);
}
catch(CUserException *pe)
{
pe->ReportError();
pe->Delete();
}
catch(CException *pe)
{
pe->ReportError();
}
}
CProgramRegistration::~CProgramRegistration()
// Destroy.
{
DELETE_AND_DESTROY(m_pregAccess);
}
// 3. Methods. (alphabetical).
const int CProgramRegistration::GetDaysLeft()
// Return number of days left in the trial period.
{
int iDaysLeft = 0;
if(m_dtNow < m_dtExpire)
iDaysLeft = ::GetTimeDiffInDays(m_dtNow, m_dtExpire);
return iDaysLeft;
}
const bool CProgramRegistration::GetFirstRunDate(COleDateTime &dtFirstRun)
// Return date of first run.
{
CString cstrTime(_T(""));
if(m_pregAccess->GetData(GetFirstRunRegName(), cstrTime))
{
if(cstrTime.GetLength() == 6)
{
// Format is expected to be "YYMMDD".
const CString cstrYY(cstrTime.Left(2));
const CString cstrMM(cstrTime.Mid(2, 2));
const CString cstrDD(cstrTime.Right(2));
int iYear = ::_wtoi((LPCTSTR)cstrYY) + 2000;
int iMonth = ::_wtoi((LPCTSTR)cstrMM);
int iDay = ::_wtoi((LPCTSTR)cstrDD);
dtFirstRun = COleDateTime(iYear, iMonth, iDay, 0, 0, 0);
return true;
}
}
return false;
}
const bool CProgramRegistration::GetSerialNumber(CString &cstrSN)
// Return SN.
{
cstrSN.Empty();
return(m_pregAccess->GetData(GetSNRegName(), cstrSN));
}
const bool CProgramRegistration::IsLegalCopy()
// Return T if program is a legal copy and F if not.
{
if(IsRegistred() || GetDaysLeft() > 0)
return true;
return false;
}
const bool CProgramRegistration::IsRegistred()
// Return T if program is registred and F if not.
{
CString cstrSN(_T(""));
GetSerialNumber(cstrSN);
return(cstrSN.CompareNoCase(sm_cstrSNDummy) != 0);
}
const void CProgramRegistration::RemoveRegistration()
// Remove all program registration.
{
m_pregAccess->DeleteData(GetFirstRunRegName());
m_pregAccess->DeleteData(GetSNRegName());
}
const bool CProgramRegistration::Register(const CString &cstrSN)
// Write SN.
{ return(m_pregAccess->SetData(GetSNRegName(), cstrSN)); }
const bool CProgramRegistration::SetFirstRunDate(const COleDateTime &dtFirstRun)
// Set time of first run.
{
CString cstrTime(_T(""));
m_dtFirstRun = dtFirstRun;
cstrTime = ::GetDateAsNiceHumanReadableString(m_dtFirstRun, true);
return(m_pregAccess->SetData(GetFirstRunRegName(), cstrTime));
}
const bool CProgramRegistration::UnRegister()
// Write dummy SN.
{ return(m_pregAccess->SetData(GetSNRegName(), sm_cstrSNDummy)); }