STATREG.CPP
// This is a part of the Active Template Library. 
// Copyright (C) 1996-1997 Microsoft Corporation 
// All rights reserved. 
// 
// This source code is only intended as a supplement to the 
// Active Template Library Reference and related 
// electronic documentation provided with the library. 
// See these sources for detailed information regarding the 
// Active Template Library product. 
 
/////////////////////////////////////// 
#define RET_ON_ERROR(x) \ 
if (FAILED(hr = x))\ 
return hr; 
/////////////////////////////////////// 
#define BREAK_ON_ERROR(x) \ 
if (FAILED(hr = x))\ 
break; 
/////////////////////////////////////// 
#ifdef _DEBUG 
#define REPORT_ERROR(name, func) \ 
if (func != ERROR_SUCCESS)\ 
ATLTRACE(_T("NON CRITICAL ERROR : %s failed\n"), name); 
#define REG_TRACE_RECOVER() \ 
if (!bRecover) \ 
ATLTRACE(_T("Opened Key %s\n"), szToken); \ 
else \ 
ATLTRACE(_T("Ignoring Open key on %s : In Recovery mode\n"), szToken); 
#else //!_DEBUG 
#define REG_TRACE_RECOVER() 
#define REPORT_ERROR(name, func) \ 
func; 
#endif //_DEBUG 
 
/////////////////////////////////////// 
#define MAX_TYPE            MAX_VALUE 
#define MAX_VALUE           4096 
 
#ifndef ATL_NO_NAMESPACE 
namespace ATL 
{ 
#endif 
 
class CParseBuffer 
{ 
public: 
int nPos; 
int nSize; 
LPTSTR p; 
CParseBuffer(int nInitial); 
~CParseBuffer() {CoTaskMemFree(p);} 
BOOL AddChar(TCHAR ch); 
BOOL AddString(LPCOLESTR lpsz); 
LPTSTR Detach(); 
 
}; 
 
LPCTSTR   rgszNeverDelete[] = //Component Catagories 
{ 
_T("CLSID"), _T("TYPELIB") 
}; 
 
const int   cbNeverDelete = sizeof(rgszNeverDelete) / sizeof(LPCTSTR*); 
 
static LPTSTR StrChr(LPTSTR lpsz, TCHAR ch) 
{ 
LPTSTR p = NULL; 
while (*lpsz) 
{ 
if (*lpsz == ch) 
{ 
p = lpsz; 
break; 
} 
lpsz = CharNext(lpsz); 
} 
return p; 
} 
 
static HKEY WINAPI HKeyFromString(LPTSTR szToken) 
{ 
struct keymap 
{ 
LPCTSTR lpsz; 
HKEY hkey; 
}; 
static const keymap map[] = { 
{_T("HKCR"), HKEY_CLASSES_ROOT}, 
{_T("HKCU"), HKEY_CURRENT_USER}, 
{_T("HKLM"), HKEY_LOCAL_MACHINE}, 
{_T("HKU"),  HKEY_USERS}, 
{_T("HKPD"), HKEY_PERFORMANCE_DATA}, 
{_T("HKDD"), HKEY_DYN_DATA}, 
{_T("HKCC"), HKEY_CURRENT_CONFIG}, 
{_T("HKEY_CLASSES_ROOT"), HKEY_CLASSES_ROOT}, 
{_T("HKEY_CURRENT_USER"), HKEY_CURRENT_USER}, 
{_T("HKEY_LOCAL_MACHINE"), HKEY_LOCAL_MACHINE}, 
{_T("HKEY_USERS"), HKEY_USERS}, 
{_T("HKEY_PERFORMANCE_DATA"), HKEY_PERFORMANCE_DATA}, 
{_T("HKEY_DYN_DATA"), HKEY_DYN_DATA}, 
{_T("HKEY_CURRENT_CONFIG"), HKEY_CURRENT_CONFIG} 
}; 
 
for (int i=0;i<sizeof(map)/sizeof(keymap);i++) 
{ 
if (!lstrcmpi(szToken, map[i].lpsz)) 
return map[i].hkey; 
} 
return NULL; 
} 
 
static HKEY HKeyFromCompoundString(LPTSTR szToken, LPTSTR& szTail) 
{ 
if (NULL == szToken) 
return NULL; 
 
LPTSTR lpsz = StrChr(szToken, chDirSep); 
 
if (NULL == lpsz) 
return NULL; 
 
szTail = CharNext(lpsz); 
*lpsz = chEOS; 
HKEY hKey = HKeyFromString(szToken); 
*lpsz = chDirSep; 
return hKey; 
} 
 
static LPVOID QueryValue(HKEY hKey, LPCTSTR szValName, DWORD& dwType) 
{ 
DWORD dwCount = 0; 
 
if (RegQueryValueEx(hKey, szValName, NULL, &dwType, NULL, &dwCount) != ERROR_SUCCESS) 
{ 
ATLTRACE(_T("RegQueryValueEx failed for Value %s\n"), szValName); 
return NULL; 
} 
 
if (!dwCount) 
{ 
ATLTRACE(_T("RegQueryValueEx returned 0 bytes\n")); 
return NULL; 
} 
 
// Not going to Check for fail on CoTaskMemAlloc & RegQueryValueEx as NULL 
// will be returned regardless if anything failed 
 
LPVOID pData = CoTaskMemAlloc(dwCount); 
RegQueryValueEx(hKey, szValName, NULL, &dwType, (LPBYTE) pData, &dwCount); 
return pData; 
} 
 
///////////////////////////////////////////////////////////////////////////// 
// 
 
HRESULT CRegParser::GenerateError(UINT nID) 
{ 
//  m_re.m_nID   = nID; 
//  m_re.m_cLines = m_cLines; 
return DISP_E_EXCEPTION; 
} 
 
 
CRegParser::CRegParser(CRegObject* pRegObj) 
{ 
m_pRegObj           = pRegObj; 
m_pchCur            = NULL; 
m_cLines            = 1; 
} 
 
BOOL CRegParser::IsSpace(TCHAR ch) 
{ 
switch (ch) 
{ 
case chSpace: 
case chTab: 
case chCR: 
case chLF: 
return TRUE; 
} 
 
return FALSE; 
} 
 
void CRegParser::IncrementLinePos() 
{ 
m_pchCur = CharNext(m_pchCur); 
if (chLF == *m_pchCur) 
IncrementLineCount(); 
} 
 
void CRegParser::SkipWhiteSpace() 
{ 
while(IsSpace(*m_pchCur)) 
IncrementLinePos(); 
} 
 
HRESULT CRegParser::NextToken(LPTSTR szToken) 
{ 
USES_CONVERSION; 
 
UINT ichToken = 0; 
 
SkipWhiteSpace(); 
 
// NextToken cannot be called at EOS 
if (chEOS == *m_pchCur) 
return GenerateError(E_ATL_UNEXPECTED_EOS); 
 
// handle quoted value / key 
if (chQuote == *m_pchCur) 
{ 
LPCTSTR szOrig = szToken; 
 
IncrementLinePos(); // Skip Quote 
 
while (chEOS != *m_pchCur && !EndOfVar()) 
{ 
if (chQuote == *m_pchCur) // If it is a quote that means we must skip it 
IncrementLinePos();   // as it has been escaped 
 
LPTSTR pchPrev = m_pchCur; 
IncrementLinePos(); 
 
if (szToken + sizeof(WORD) >= MAX_VALUE + szOrig) 
return GenerateError(E_ATL_VALUE_TOO_LARGE); 
for (int i = 0; pchPrev+i < m_pchCur; i++, szToken++) 
*szToken = *(pchPrev+i); 
} 
 
if (chEOS == *m_pchCur) 
{ 
ATLTRACE(_T("NextToken : Unexpected End of File\n")); 
return GenerateError(E_ATL_UNEXPECTED_EOS); 
} 
 
*szToken = chEOS; 
IncrementLinePos(); // Skip end quote 
} 
 
else 
{   // Handle non-quoted ie parse up till first "White Space" 
while (chEOS != *m_pchCur && !IsSpace(*m_pchCur)) 
{ 
LPTSTR pchPrev = m_pchCur; 
IncrementLinePos(); 
for (int i = 0; pchPrev+i < m_pchCur; i++, szToken++) 
*szToken = *(pchPrev+i); 
} 
 
*szToken = chEOS; 
} 
return S_OK; 
} 
 
static BOOL VTFromRegType(LPCTSTR szValueType, VARTYPE& vt) 
{ 
struct typemap 
{ 
LPCTSTR lpsz; 
VARTYPE vt; 
}; 
static const typemap map[] = { 
{szStringVal, VT_BSTR}, 
{szDwordVal,  VT_I4} 
}; 
 
for (int i=0;i<sizeof(map)/sizeof(typemap);i++) 
{ 
if (!lstrcmpi(szValueType, map[i].lpsz)) 
{ 
vt = map[i].vt; 
return TRUE; 
} 
} 
 
return FALSE; 
 
} 
 
HRESULT CRegParser::AddValue(CRegKey& rkParent,LPCTSTR szValueName, LPTSTR szToken) 
{ 
USES_CONVERSION; 
HRESULT hr; 
 
TCHAR       szTypeToken[MAX_TYPE]; 
VARTYPE     vt; 
LONG        lRes = ERROR_SUCCESS; 
UINT        nIDRes = 0; 
 
RET_ON_ERROR(NextToken(szTypeToken)) 
if (!VTFromRegType(szTypeToken, vt)) 
{ 
ATLTRACE(_T("%s Type not supported\n"), szTypeToken); 
return GenerateError(E_ATL_TYPE_NOT_SUPPORTED); 
} 
 
TCHAR szValue[MAX_VALUE]; 
SkipWhiteSpace(); 
RET_ON_ERROR(NextToken(szValue)); 
long lVal; 
 
switch (vt) 
{ 
case VT_BSTR: 
lRes = rkParent.SetValue(szValue, szValueName); 
ATLTRACE(_T("Setting Value %s at %s\n"), szValue, !szValueName ? _T("default") : szValueName); 
break; 
case VT_I4: 
VarI4FromStr(T2OLE(szValue), 0, 0, &lVal); 
lRes = rkParent.SetValue(lVal, szValueName); 
ATLTRACE(_T("Setting Value %d at %s\n"), lVal, !szValueName ? _T("default") : szValueName); 
break; 
} 
 
if (ERROR_SUCCESS != lRes) 
{ 
nIDRes = E_ATL_VALUE_SET_FAILED; 
hr = HRESULT_FROM_WIN32(lRes); 
} 
 
RET_ON_ERROR(NextToken(szToken)) 
 
return S_OK; 
} 
 
BOOL CRegParser::CanForceRemoveKey(LPCTSTR szKey) 
{ 
for (int iNoDel = 0; iNoDel < cbNeverDelete; iNoDel++) 
if (!lstrcmpi(szKey, rgszNeverDelete[iNoDel])) 
 return FALSE;                       // We cannot delete it 
 
return TRUE; 
} 
 
BOOL CRegParser::HasSubKeys(HKEY hkey) 
{ 
DWORD       cbSubKeys = 0; 
 
if (FAILED(RegQueryInfoKey(hkey, NULL, NULL, NULL, 
   &cbSubKeys, NULL, NULL, 
   NULL, NULL, NULL, NULL, NULL))) 
{ 
ATLTRACE(_T("Should not be here!!\n")); 
_ASSERTE(FALSE); 
return FALSE; 
} 
 
return cbSubKeys > 0; 
} 
 
BOOL CRegParser::HasValues(HKEY hkey) 
{ 
DWORD       cbValues = 0; 
 
LONG lResult = RegQueryInfoKey(hkey, NULL, NULL, NULL, 
  NULL, NULL, NULL, 
  &cbValues, NULL, NULL, NULL, NULL); 
if (ERROR_SUCCESS != lResult) 
{ 
ATLTRACE(_T("RegQueryInfoKey Failed ")); 
_ASSERTE(FALSE); 
return FALSE; 
} 
 
if (1 == cbValues) 
{ 
DWORD cbData = 0; 
lResult = RegQueryValueEx(hkey, NULL, NULL, NULL, NULL, &cbData); 
 
if (ERROR_SUCCESS == lResult) 
return !cbData; 
else 
return TRUE; 
} 
 
return cbValues > 0; 
} 
 
HRESULT CRegParser::SkipAssignment(LPTSTR szToken) 
{ 
HRESULT hr; 
TCHAR szValue[MAX_VALUE]; 
 
if (*szToken == chEquals) 
{ 
RET_ON_ERROR(NextToken(szToken)) 
// Skip assignment 
SkipWhiteSpace(); 
RET_ON_ERROR(NextToken(szValue)); 
RET_ON_ERROR(NextToken(szToken)) 
} 
 
return S_OK; 
} 
 
 
HRESULT CRegParser::RegisterSubkeys(HKEY hkParent, BOOL bRegister, BOOL bRecover) 
{ 
CRegKey keyCur; 
TCHAR   szToken[MAX_VALUE]; 
LONG    lRes; 
TCHAR   szKey[MAX_VALUE]; 
BOOL    bDelete = TRUE; 
BOOL    bInRecovery = bRecover; 
HRESULT hr = S_OK; 
 
ATLTRACE(_T("Num Els = %d\n"), cbNeverDelete); 
RET_ON_ERROR(NextToken(szToken))  // Should be key name 
 
 
while (*szToken != chRightBracket) // Continue till we see a } 
{ 
BOOL bTokenDelete = !lstrcmpi(szToken, szDelete); 
 
if (!lstrcmpi(szToken, szForceRemove) || bTokenDelete) 
{ 
BREAK_ON_ERROR(NextToken(szToken)) 
 
if (bRegister) 
{ 
CRegKey rkForceRemove; 
 
if (StrChr(szToken, chDirSep) != NULL) 
return GenerateError(E_ATL_COMPOUND_KEY); 
 
if (CanForceRemoveKey(szToken)) 
{ 
rkForceRemove.Attach(hkParent); 
rkForceRemove.RecurseDeleteKey(szToken); 
rkForceRemove.Detach(); 
} 
if (bTokenDelete) 
{ 
BREAK_ON_ERROR(NextToken(szToken)) 
BREAK_ON_ERROR(SkipAssignment(szToken)) 
goto EndCheck; 
} 
} 
 
} 
 
if (!lstrcmpi(szToken, szNoRemove)) 
{ 
bDelete = FALSE;    // set even for register 
BREAK_ON_ERROR(NextToken(szToken)) 
} 
 
if (!lstrcmpi(szToken, szValToken)) // need to add a value to hkParent 
{ 
TCHAR  szValueName[_MAX_PATH]; 
 
BREAK_ON_ERROR(NextToken(szValueName)) 
BREAK_ON_ERROR(NextToken(szToken)) 
 
if (*szToken != chEquals) 
return GenerateError(E_ATL_EXPECTING_EQUAL); 
 
if (bRegister) 
{ 
CRegKey rk; 
 
rk.Attach(hkParent); 
hr = AddValue(rk, szValueName, szToken); 
rk.Detach(); 
 
if (FAILED(hr)) 
return hr; 
 
goto EndCheck; 
} 
else 
{ 
if (!bRecover) 
{ 
ATLTRACE(_T("Deleting %s\n"), szValueName); 
REPORT_ERROR(_T("RegDeleteValue"), RegDeleteValue(hkParent, szValueName)) 
} 
 
BREAK_ON_ERROR(SkipAssignment(szToken)) // Strip off type 
continue;  // can never have a subkey 
} 
} 
 
if (StrChr(szToken, chDirSep) != NULL) 
return GenerateError(E_ATL_COMPOUND_KEY); 
 
if (bRegister) 
{ 
lRes = keyCur.Open(hkParent, szToken, KEY_ALL_ACCESS); 
if (ERROR_SUCCESS != lRes) 
{ 
// Failed all access try read only 
lRes = keyCur.Open(hkParent, szToken, KEY_READ); 
if (ERROR_SUCCESS != lRes) 
{ 
// Finally try creating it 
ATLTRACE(_T("Creating key %s\n"), szToken); 
lRes = keyCur.Create(hkParent, szToken); 
if (ERROR_SUCCESS != lRes) 
return GenerateError(E_ATL_CREATE_KEY_FAILED); 
} 
} 
 
BREAK_ON_ERROR(NextToken(szToken)) 
 
if (*szToken == chEquals) 
BREAK_ON_ERROR(AddValue(keyCur, NULL, szToken)) // NULL == default 
} 
else 
{ 
if (!bRecover && keyCur.Open(hkParent, szToken) != ERROR_SUCCESS) 
bRecover = TRUE; 
 
// TRACE out Key open status and if in recovery mode 
REG_TRACE_RECOVER() 
 
// Remember Subkey 
lstrcpyn(szKey, szToken, _MAX_PATH); 
 
// If in recovery mode 
 
if (bRecover || HasSubKeys(keyCur) || HasValues(keyCur)) 
{ 
BREAK_ON_ERROR(NextToken(szToken)) 
BREAK_ON_ERROR(SkipAssignment(szToken)) 
 
if (*szToken == chLeftBracket) 
{ 
BREAK_ON_ERROR(RegisterSubkeys(keyCur.m_hKey, bRegister, bRecover)) 
if (bRecover) // Turn off recovery if we are done 
{ 
bRecover = bInRecovery; 
ATLTRACE(_T("Ending Recovery Mode\n")); 
BREAK_ON_ERROR(NextToken(szToken)) 
BREAK_ON_ERROR(SkipAssignment(szToken)) 
continue; 
} 
} 
 
if (!bRecover && HasSubKeys(keyCur)) 
{ 
// See if the KEY is in the NeverDelete list and if so, don't 
if (CanForceRemoveKey(szKey)) 
{ 
ATLTRACE(_T("Deleting non-empty subkey %s by force\n"), szKey); 
REPORT_ERROR(_T("RecurseDeleteKey"), keyCur.RecurseDeleteKey(szKey)) 
} 
BREAK_ON_ERROR(NextToken(szToken)) 
continue; 
} 
 
if (bRecover) 
continue; 
} 
 
if (!bRecover && keyCur.Close() != ERROR_SUCCESS) 
   return GenerateError(E_ATL_CLOSE_KEY_FAILED); 
 
if (!bRecover && bDelete) 
{ 
ATLTRACE(_T("Deleting Key %s\n"), szKey); 
REPORT_ERROR(_T("RegDeleteKey"), RegDeleteKey(hkParent, szKey)) 
} 
 
BREAK_ON_ERROR(NextToken(szToken)) 
BREAK_ON_ERROR(SkipAssignment(szToken)) 
} 
 
EndCheck: 
 
if (bRegister) 
{ 
if (*szToken == chLeftBracket) 
{ 
BREAK_ON_ERROR(RegisterSubkeys(keyCur.m_hKey, bRegister, FALSE)) 
BREAK_ON_ERROR(NextToken(szToken)) 
} 
} 
} 
 
return hr; 
} 
 
LPTSTR CParseBuffer::Detach() 
{ 
LPTSTR lp = p; 
p = NULL; 
return lp; 
} 
 
CParseBuffer::CParseBuffer(int nInitial) 
{ 
nPos = 0; 
nSize = nInitial; 
p = (LPTSTR) CoTaskMemAlloc(nSize*sizeof(TCHAR)); 
} 
 
BOOL CParseBuffer::AddString(LPCOLESTR lpsz) 
{ 
USES_CONVERSION; 
LPCTSTR lpszT = OLE2CT(lpsz); 
while (*lpszT) 
{ 
AddChar(*lpszT); 
lpszT++; 
} 
return TRUE; 
} 
 
BOOL CParseBuffer::AddChar(TCHAR ch) 
{ 
if (nPos == nSize) // realloc 
{ 
nSize *= 2; 
p = (LPTSTR) CoTaskMemRealloc(p, nSize*sizeof(TCHAR)); 
} 
p[nPos++] = ch; 
return TRUE; 
} 
 
HRESULT CRegParser::PreProcessBuffer(LPTSTR lpszReg, LPTSTR* ppszReg) 
{ 
USES_CONVERSION; 
_ASSERTE(lpszReg != NULL); 
_ASSERTE(ppszReg != NULL); 
*ppszReg = NULL; 
int nSize = lstrlen(lpszReg)*2; 
CParseBuffer pb(nSize); 
if (pb.p == NULL) 
return E_OUTOFMEMORY; 
m_pchCur = lpszReg; 
HRESULT hr = S_OK; 
 
while (*m_pchCur != NULL) // look for end 
{ 
if (*m_pchCur == _T('%')) 
{ 
IncrementLinePos(); 
if (*m_pchCur == _T('%')) 
pb.AddChar(*m_pchCur); 
else 
{ 
LPTSTR lpszNext = StrChr(m_pchCur, _T('%')); 
if (lpszNext == NULL) 
{ 
ATLTRACE(_T("Error no closing % found\n")); 
hr = GenerateError(E_ATL_UNEXPECTED_EOS); 
break; 
} 
int nLength = lpszNext - m_pchCur; 
if (nLength > 31) 
{ 
hr = E_FAIL; 
break; 
} 
TCHAR buf[32]; 
lstrcpyn(buf, m_pchCur, nLength+1); 
LPCOLESTR lpszVar = m_pRegObj->StrFromMap(buf); 
if (lpszVar == NULL) 
{ 
hr = GenerateError(E_ATL_NOT_IN_MAP); 
break; 
} 
pb.AddString(lpszVar); 
while (m_pchCur != lpszNext) 
IncrementLinePos(); 
} 
} 
else 
pb.AddChar(*m_pchCur); 
IncrementLinePos(); 
} 
pb.AddChar(NULL); 
if (SUCCEEDED(hr)) 
*ppszReg = pb.Detach(); 
return hr; 
} 
 
HRESULT CRegParser::RegisterBuffer(LPTSTR szBuffer, BOOL bRegister) 
{ 
TCHAR   szToken[_MAX_PATH]; 
HRESULT hr = S_OK; 
 
LPTSTR szReg; 
hr = PreProcessBuffer(szBuffer, &szReg); 
if (FAILED(hr)) 
return hr; 
 
m_pchCur = szReg; 
 
// Preprocess szReg 
 
while (chEOS != *m_pchCur) 
{ 
BREAK_ON_ERROR(NextToken(szToken)) 
HKEY hkBase; 
if ((hkBase = HKeyFromString(szToken)) == NULL) 
{ 
ATLTRACE(_T("HKeyFromString failed on %s\n"), szToken); 
hr = GenerateError(E_ATL_BAD_HKEY); 
break; 
} 
 
BREAK_ON_ERROR(NextToken(szToken)) 
 
if (chLeftBracket != *szToken) 
{ 
ATLTRACE(_T("Syntax error, expecting a {, found a %s\n"), szToken); 
hr = GenerateError(E_ATL_MISSING_OPENKEY_TOKEN); 
break; 
} 
if (bRegister) 
{ 
LPTSTR szRegAtRegister = m_pchCur; 
hr = RegisterSubkeys(hkBase, bRegister); 
if (FAILED(hr)) 
{ 
ATLTRACE(_T("Failed to register, cleaning up!\n")); 
m_pchCur = szRegAtRegister; 
RegisterSubkeys(hkBase, FALSE); 
break; 
} 
} 
else 
{ 
BREAK_ON_ERROR(RegisterSubkeys(hkBase, bRegister)) 
} 
 
SkipWhiteSpace(); 
} 
CoTaskMemFree(szReg); 
return hr; 
} 
 
HRESULT CExpansionVector::Add(LPCOLESTR lpszKey, LPCOLESTR lpszValue) 
{ 
USES_CONVERSION; 
HRESULT hr = S_OK; 
 
EXPANDER* pExpand = NULL; 
ATLTRY(pExpand = new EXPANDER); 
if (pExpand == NULL) 
return E_OUTOFMEMORY; 
 
DWORD cbKey = (ocslen(lpszKey)+1)*sizeof(OLECHAR); 
DWORD cbValue = (ocslen(lpszValue)+1)*sizeof(OLECHAR); 
pExpand->szKey = (LPOLESTR)CoTaskMemAlloc(cbKey); 
pExpand->szValue = (LPOLESTR)CoTaskMemAlloc(cbValue); 
if (pExpand->szKey == NULL || pExpand->szValue == NULL) 
{ 
CoTaskMemFree(pExpand->szKey); 
CoTaskMemFree(pExpand->szValue); 
delete pExpand; 
return E_OUTOFMEMORY; 
} 
memcpy(pExpand->szKey, lpszKey, cbKey); 
memcpy(pExpand->szValue, lpszValue, cbValue); 
 
if (m_cEls == m_nSize) 
{ 
m_nSize*=2; 
m_p = (EXPANDER**)realloc(m_p, m_nSize*sizeof(EXPANDER*)); 
} 
 
if (NULL != m_p) 
{ 
m_p[m_cEls] = pExpand; 
m_cEls++; 
} 
else 
hr = E_OUTOFMEMORY; 
 
return hr; 
 
} 
 
LPCOLESTR CExpansionVector::Find(LPTSTR lpszKey) 
{ 
USES_CONVERSION; 
for (int iExpand = 0; iExpand < m_cEls; iExpand++) 
{ 
if (!lstrcmpi(OLE2T(m_p[iExpand]->szKey), lpszKey)) //are equal 
return m_p[iExpand]->szValue; 
} 
return NULL; 
} 
 
HRESULT CExpansionVector::ClearReplacements() 
{ 
for (int iExpand = 0; iExpand < m_cEls; iExpand++) 
{ 
EXPANDER* pExp = m_p[iExpand]; 
CoTaskMemFree(pExp->szValue); 
CoTaskMemFree(pExp->szKey); 
delete pExp; 
} 
m_cEls = 0; 
return S_OK; 
} 
 
HRESULT CRegObject::GenerateError(UINT nID) 
{ 
//  re.m_nID    = nID; 
//  re.m_cLines = -1; 
 
return DISP_E_EXCEPTION; 
} 
 
HRESULT STDMETHODCALLTYPE CRegObject::AddReplacement(LPCOLESTR lpszKey, LPCOLESTR lpszItem) 
{ 
m_csMap.Lock(); 
HRESULT hr = m_RepMap.Add(lpszKey, lpszItem); 
m_csMap.Unlock(); 
return hr; 
} 
 
HRESULT CRegObject::RegisterFromResource(LPCOLESTR bstrFileName, LPCTSTR szID, 
 LPCTSTR szType, BOOL bRegister) 
{ 
USES_CONVERSION; 
 
HRESULT     hr; 
CRegParser  parser(this); 
HINSTANCE   hInstResDll; 
HRSRC       hrscReg; 
HGLOBAL     hReg; 
DWORD       dwSize; 
LPSTR       szRegA; 
LPTSTR      szReg; 
 
hInstResDll = LoadLibraryEx(OLE2CT(bstrFileName), NULL, LOAD_LIBRARY_AS_DATAFILE); 
 
if (NULL == hInstResDll) 
{ 
ATLTRACE(_T("Failed to LoadLibrary on %s\n"), OLE2CT(bstrFileName)); 
hr = HRESULT_FROM_WIN32(GetLastError()); 
goto ReturnHR; 
} 
 
hrscReg = FindResource((HMODULE)hInstResDll, szID, szType); 
 
if (NULL == hrscReg) 
{ 
ATLTRACE(_T("Failed to FindResource on ID:%s TYPE:%s\n"), szID, szType); 
hr = HRESULT_FROM_WIN32(GetLastError()); 
goto ReturnHR; 
} 
 
hReg = LoadResource((HMODULE)hInstResDll, hrscReg); 
 
if (NULL == hReg) 
{ 
ATLTRACE(_T("Failed to LoadResource \n")); 
hr = HRESULT_FROM_WIN32(GetLastError()); 
goto ReturnHR; 
} 
 
dwSize = SizeofResource((HMODULE)hInstResDll, hrscReg); 
szRegA = (LPSTR)hReg; 
if (szRegA[dwSize] != NULL) 
{ 
szRegA = (LPSTR)_alloca(dwSize+1); 
memcpy(szRegA, (void*)hReg, dwSize+1); 
szRegA[dwSize] = NULL; 
} 
 
szReg = A2T(szRegA); 
 
#ifdef _DEBUG 
OutputDebugString(szReg); //would call ATLTRACE but szReg is > 512 bytes 
OutputDebugString(_T("\n")); 
#endif //_DEBUG 
 
hr = parser.RegisterBuffer(szReg, bRegister); 
 
ReturnHR: 
 
if (NULL != hInstResDll) 
FreeLibrary((HMODULE)hInstResDll); 
return hr; 
} 
 
HRESULT STDMETHODCALLTYPE CRegObject::ResourceRegister(LPCOLESTR szFileName, UINT nID, LPCOLESTR szType) 
{ 
USES_CONVERSION; 
return RegisterFromResource(szFileName, MAKEINTRESOURCE(nID), OLE2CT(szType), TRUE); 
} 
 
HRESULT STDMETHODCALLTYPE CRegObject::ResourceRegisterSz(LPCOLESTR szFileName, LPCOLESTR szID, LPCOLESTR szType) 
{ 
USES_CONVERSION; 
 
if (szID == NULL || szType == NULL) 
return E_INVALIDARG; 
 
return RegisterFromResource(szFileName, OLE2CT(szID), OLE2CT(szType), TRUE); 
} 
 
HRESULT STDMETHODCALLTYPE CRegObject::ResourceUnregister(LPCOLESTR szFileName, UINT nID, LPCOLESTR szType) 
{ 
USES_CONVERSION; 
return RegisterFromResource(szFileName, MAKEINTRESOURCE(nID), OLE2CT(szType), FALSE); 
} 
 
HRESULT STDMETHODCALLTYPE CRegObject::ResourceUnregisterSz(LPCOLESTR szFileName, LPCOLESTR szID, LPCOLESTR szType) 
{ 
USES_CONVERSION; 
if (szID == NULL || szType == NULL) 
return E_INVALIDARG; 
 
return RegisterFromResource(szFileName, OLE2CT(szID), OLE2CT(szType), FALSE); 
} 
 
HRESULT CRegObject::RegisterWithString(LPCOLESTR bstrData, BOOL bRegister) 
{ 
USES_CONVERSION; 
CRegParser  parser(this); 
 
 
LPCTSTR szReg = OLE2CT(bstrData); 
 
#ifdef _DEBUG 
OutputDebugString(szReg); //would call ATLTRACE but szReg is > 512 bytes 
OutputDebugString(_T("\n")); 
#endif //_DEBUG 
 
HRESULT hr = parser.RegisterBuffer((LPTSTR)szReg, bRegister); 
 
return hr; 
} 
 
HRESULT CRegObject::ClearReplacements() 
{ 
m_csMap.Lock(); 
HRESULT hr = m_RepMap.ClearReplacements(); 
m_csMap.Unlock(); 
return hr; 
} 
 
 
LPCOLESTR CRegObject::StrFromMap(LPTSTR lpszKey) 
{ 
m_csMap.Lock(); 
LPCOLESTR lpsz = m_RepMap.Find(lpszKey); 
if (lpsz == NULL) // not found!! 
ATLTRACE(_T("Map Entry not found\n")); 
m_csMap.Unlock(); 
return lpsz; 
} 
 
HRESULT CRegObject::MemMapAndRegister(LPCOLESTR bstrFileName, BOOL bRegister) 
{ 
USES_CONVERSION; 
 
CRegParser  parser(this); 
 
HANDLE hFile = CreateFile(OLE2CT(bstrFileName), GENERIC_READ, 0, NULL, 
  OPEN_EXISTING, 
  FILE_ATTRIBUTE_READONLY, 
  NULL); 
 
if (NULL == hFile) 
{ 
ATLTRACE(_T("Failed to CreateFile on %s\n"), OLE2CT(bstrFileName)); 
return HRESULT_FROM_WIN32(GetLastError()); 
} 
 
DWORD cbFile = GetFileSize(hFile, NULL); // No HiOrder DWORD required 
 
HANDLE hMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL); 
 
if (NULL == hMapping) 
{ 
ATLTRACE(_T("Failed to CreateFileMapping\n")); 
return HRESULT_FROM_WIN32(GetLastError()); 
} 
 
LPVOID pMap = MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0); 
 
if (NULL == pMap) 
{ 
ATLTRACE(_T("Failed to MapViewOfFile\n")); 
return HRESULT_FROM_WIN32(GetLastError()); 
} 
 
LPTSTR szReg = A2T((char*)pMap); 
 
if (chEOS != szReg[cbFile]) //ensure buffer is NULL terminated 
{ 
ATLTRACE(_T("ERROR : Bad or missing End of File\n")); 
return E_FAIL; // make a real error 
} 
 
#ifdef _DEBUG 
OutputDebugString(szReg); //would call ATLTRACE but szReg is > 512 bytes 
OutputDebugString(_T("\n")); 
#endif //_DEBUG 
 
HRESULT hRes = parser.RegisterBuffer(szReg, bRegister); 
 
//  if (FAILED(hRes)) 
//      re = parser.GetRegException(); 
 
UnmapViewOfFile(pMap); 
CloseHandle(hMapping); 
CloseHandle(hFile); 
 
return hRes; 
} 
 
HRESULT STDMETHODCALLTYPE CRegObject::FileRegister(LPCOLESTR bstrFileName) 
{ 
return MemMapAndRegister(bstrFileName, TRUE); 
} 
 
HRESULT STDMETHODCALLTYPE CRegObject::FileUnregister(LPCOLESTR bstrFileName) 
{ 
return MemMapAndRegister(bstrFileName, FALSE); 
} 
 
HRESULT STDMETHODCALLTYPE CRegObject::StringRegister(LPCOLESTR bstrData) 
{ 
return RegisterWithString(bstrData, TRUE); 
} 
 
HRESULT STDMETHODCALLTYPE CRegObject::StringUnregister(LPCOLESTR bstrData) 
{ 
return RegisterWithString(bstrData, FALSE); 
} 
 
#ifndef ATL_NO_NAMESPACE 
}; //namespace ATL 
#endif