statreg.cpp
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 32k
Category:

Windows Kernel

Development Platform:

Visual C++

  1. #include "precomp.h"
  2. #include "statreg.h"
  3. LPCTSTR   rgszNeverDelete[] = //Component Catagories
  4. {
  5.     _T("CLSID"), _T("TYPELIB")
  6. };
  7. const int   cbNeverDelete = sizeof(rgszNeverDelete) / sizeof(LPCTSTR*);
  8. LPTSTR StrChr(LPTSTR lpsz, TCHAR ch)
  9. {
  10.     LPTSTR p = NULL;
  11.     while (*lpsz)
  12.     {
  13.         if (*lpsz == ch)
  14.         {
  15.             p = lpsz;
  16.             break;
  17.         }
  18.         lpsz = CharNext(lpsz);
  19.     }
  20.     return p;
  21. }
  22. static HKEY WINAPI HKeyFromString(LPTSTR szToken)
  23. {
  24.     struct keymap
  25.     {
  26.         LPCTSTR lpsz;
  27.         HKEY hkey;
  28.     };
  29.     static const keymap map[] = {
  30.         {_T("HKCR"), HKEY_CLASSES_ROOT},
  31.         {_T("HKCU"), HKEY_CURRENT_USER},
  32.         {_T("HKLM"), HKEY_LOCAL_MACHINE},
  33.         {_T("HKU"),  HKEY_USERS},
  34.         {_T("HKPD"), HKEY_PERFORMANCE_DATA},
  35.         {_T("HKDD"), HKEY_DYN_DATA},
  36.         {_T("HKCC"), HKEY_CURRENT_CONFIG},
  37.         {_T("HKEY_CLASSES_ROOT"), HKEY_CLASSES_ROOT},
  38.         {_T("HKEY_CURRENT_USER"), HKEY_CURRENT_USER},
  39.         {_T("HKEY_LOCAL_MACHINE"), HKEY_LOCAL_MACHINE},
  40.         {_T("HKEY_USERS"), HKEY_USERS},
  41.         {_T("HKEY_PERFORMANCE_DATA"), HKEY_PERFORMANCE_DATA},
  42.         {_T("HKEY_DYN_DATA"), HKEY_DYN_DATA},
  43.         {_T("HKEY_CURRENT_CONFIG"), HKEY_CURRENT_CONFIG}
  44.     };
  45.     for (int i=0;i<sizeof(map)/sizeof(keymap);i++)
  46.     {
  47.         if (!lstrcmpi(szToken, map[i].lpsz))
  48.             return map[i].hkey;
  49.     }
  50.     return NULL;
  51. }
  52. static HKEY HKeyFromCompoundString(LPTSTR szToken, LPTSTR& szTail)
  53. {
  54.     if (NULL == szToken)
  55.         return NULL;
  56.     LPTSTR lpsz = StrChr(szToken, chDirSep);
  57.     if (NULL == lpsz)
  58.         return NULL;
  59.     szTail = CharNext(lpsz);
  60.     *lpsz = chEOS;
  61.     HKEY hKey = HKeyFromString(szToken);
  62.     *lpsz = chDirSep;
  63.     return hKey;
  64. }
  65. static LPVOID QueryValue(HKEY hKey, LPCTSTR szValName, DWORD& dwType)
  66. {
  67.     DWORD dwCount = 0;
  68.     if (RegQueryValueEx(hKey, szValName, NULL, &dwType, NULL, &dwCount) != ERROR_SUCCESS)
  69.     {
  70.         ASSERT(FALSE);
  71.         return NULL;
  72.     }
  73.     if (!dwCount)
  74.     {
  75.         ASSERT(FALSE);
  76.         return NULL;
  77.     }
  78.     // Not going to Check for fail on CoTaskMemAlloc & RegQueryValueEx as NULL
  79.     // will be returned regardless if anything failed
  80.     LPVOID pData = CoTaskMemAlloc(dwCount);
  81.     RegQueryValueEx(hKey, szValName, NULL, &dwType, (LPBYTE) pData, &dwCount);
  82.     return pData;
  83. }
  84. /////////////////////////////////////////////////////////////////////////////
  85. //
  86. HRESULT CRegParser::GenerateError(UINT nID)
  87. {
  88.     m_re.m_nID   = nID;
  89.     m_re.m_cLines = m_cLines;
  90.     return DISP_E_EXCEPTION;
  91. }
  92. CRegParser::CRegParser(CRegObject* pRegObj)
  93. {
  94.     m_pRegObj           = pRegObj;
  95.     m_pchCur            = NULL;
  96.     m_cLines            = 1;
  97. }
  98. BOOL CRegParser::IsSpace(TCHAR ch)
  99. {
  100.     switch (ch)
  101.     {
  102.         case chSpace:
  103.         case chTab:
  104.         case chCR:
  105.         case chLF:
  106.                 return TRUE;
  107.     }
  108.     return FALSE;
  109. }
  110. void CRegParser::IncrementLinePos()
  111. {
  112.     m_pchCur = CharNext(m_pchCur);
  113.     if (chLF == *m_pchCur)
  114.         IncrementLineCount();
  115. }
  116. void CRegParser::SkipWhiteSpace()
  117. {
  118.     while(IsSpace(*m_pchCur))
  119.         IncrementLinePos();
  120. }
  121. HRESULT CRegParser::NextToken(LPTSTR szToken)
  122. {
  123.     UINT ichToken = 0;
  124.     SkipWhiteSpace();
  125.     // NextToken cannot be called at EOS
  126.     if (chEOS == *m_pchCur)
  127.         return GenerateError(IDS_UNEXPECTED_EOS);
  128.     // handle quoted value / key
  129.     if (chQuote == *m_pchCur)
  130.     {
  131.         LPCTSTR szOrig = szToken;
  132.         IncrementLinePos(); // Skip Quote
  133.         while (chEOS != *m_pchCur && !EndOfVar())
  134.         {
  135.             if (chQuote == *m_pchCur) // If it is a quote that means we must skip it
  136.                 IncrementLinePos();   // as it has been escaped
  137.             LPTSTR pchPrev = m_pchCur;
  138.             IncrementLinePos();
  139.             if (szToken + sizeof(WORD) >= MAX_VALUE + szOrig)
  140.                 return GenerateError(IDS_VALUE_TOO_LARGE);
  141.             for (int i = 0; pchPrev+i < m_pchCur; i++, szToken++)
  142.                 *szToken = *(pchPrev+i);
  143.         }
  144.         if (chEOS == *m_pchCur)
  145.         {
  146.             ASSERT(FALSE);
  147.             return GenerateError(IDS_UNEXPECTED_EOS);
  148.         }
  149.         *szToken = chEOS;
  150.         IncrementLinePos(); // Skip end quote
  151.     }
  152.     else
  153.     {   // Handle non-quoted ie parse up till first "White Space"
  154.         while (chEOS != *m_pchCur && !IsSpace(*m_pchCur))
  155.         {
  156.             LPTSTR pchPrev = m_pchCur;
  157.             IncrementLinePos();
  158.             for (int i = 0; pchPrev+i < m_pchCur; i++, szToken++)
  159.                 *szToken = *(pchPrev+i);
  160.         }
  161.         *szToken = chEOS;
  162.     }
  163.     return S_OK;
  164. }
  165. static BOOL VTFromRegType(LPCTSTR szValueType, VARTYPE& vt)
  166. {
  167.     struct typemap
  168.     {
  169.         LPCTSTR lpsz;
  170.         VARTYPE vt;
  171.     };
  172.     static const typemap map[] = {
  173.         {szStringVal, VT_BSTR},
  174.         {szDwordVal,  VT_I4}
  175.     };
  176.     for (int i=0;i<sizeof(map)/sizeof(typemap);i++)
  177.     {
  178.         if (!lstrcmpi(szValueType, map[i].lpsz))
  179.         {
  180.             vt = map[i].vt;
  181.             return TRUE;
  182.         }
  183.     }
  184.     return FALSE;
  185. }
  186. HRESULT CRegParser::AddValue(CRegKey& rkParent,LPCTSTR szValueName, LPTSTR szToken)
  187. {
  188.     TCHAR *     pszTypeToken;
  189.     TCHAR *     pszValue = NULL;
  190.     VARTYPE     vt;
  191.     LONG        lRes = ERROR_SUCCESS;
  192.     UINT        nIDRes = 0;
  193.     HRESULT     hrResult;
  194.     pszTypeToken = new TCHAR [MAX_TYPE];
  195.     if (NULL == pszTypeToken)
  196.         return E_OUTOFMEMORY;
  197.     for (;;)
  198.     {
  199.         if (FAILED(hrResult = NextToken(pszTypeToken)))
  200.             break;
  201.         if (!VTFromRegType(pszTypeToken, vt))
  202.         {
  203.             ASSERT(FALSE);
  204.             hrResult = GenerateError(IDS_TYPE_NOT_SUPPORTED);
  205.             break;
  206.         }
  207.         SkipWhiteSpace();
  208.         pszValue = new TCHAR [MAX_VALUE];
  209.         if (NULL == pszValue)
  210.         {
  211.             hrResult = E_OUTOFMEMORY;
  212.             break;
  213.         }
  214.         if (FAILED(hrResult = NextToken(pszValue)))
  215.             break;
  216.         switch (vt)
  217.         {
  218.             case VT_BSTR:
  219.             {
  220.                 lRes = rkParent.SetValue(pszValue, szValueName);
  221.                 break;
  222.             }
  223.             case VT_I4:
  224.             {
  225.                 long lVal;
  226.                 T2OLE(pszValue, poszValue);
  227.                 VarI4FromStr(poszValue, 0, 0, &lVal);
  228.                 lRes = rkParent.SetValue(lVal, szValueName);
  229.                 break;
  230.             }
  231.         }
  232.         if (ERROR_SUCCESS != lRes)
  233.         {
  234.             nIDRes = IDS_VALUE_SET_FAILED;
  235.             hrResult = HRESULT_FROM_WIN32(lRes);
  236.             break;
  237.         }
  238.         if (FAILED(hrResult = NextToken(szToken)))
  239.             break;
  240.         hrResult = S_OK;
  241.         break;
  242.     }
  243.     if (pszTypeToken != NULL)
  244.         delete [] pszTypeToken;
  245.     if (pszValue != NULL)
  246.         delete [] pszValue;
  247.     return hrResult;
  248. }
  249. BOOL CRegParser::CanForceRemoveKey(LPCTSTR szKey)
  250. {
  251.     for (int iNoDel = 0; iNoDel < cbNeverDelete; iNoDel++)
  252.         if (!lstrcmpi(szKey, rgszNeverDelete[iNoDel]))
  253.              return FALSE;                       // We cannot delete it
  254.     return TRUE;
  255. }
  256. BOOL CRegParser::HasSubKeys(HKEY hkey)
  257. {
  258.     DWORD       cbSubKeys = 0;
  259.     if (FAILED(RegQueryInfoKey(hkey, NULL, NULL, NULL,
  260.                                &cbSubKeys, NULL, NULL,
  261.                                NULL, NULL, NULL, NULL, NULL)))
  262.     {
  263.         ASSERT(FALSE);
  264.         return FALSE; // REVIEW:really not a good return for this scenerio!
  265.     }
  266.     return cbSubKeys > 0;
  267. }
  268. BOOL CRegParser::HasValues(HKEY hkey)
  269. {
  270.     DWORD       cbValues = 0;
  271.     LONG lResult = RegQueryInfoKey(hkey, NULL, NULL, NULL,
  272.                                   NULL, NULL, NULL,
  273.                                   &cbValues, NULL, NULL, NULL, NULL);
  274.     if (ERROR_SUCCESS != lResult)
  275.     {
  276.         ASSERT(FALSE);
  277.         return FALSE;
  278.     }
  279.     if (1 == cbValues)
  280.     {
  281.         DWORD cbData = 0;
  282.         lResult = RegQueryValueEx(hkey, NULL, NULL, NULL, NULL, &cbData);
  283.         if (ERROR_SUCCESS == lResult)
  284.             return !cbData;
  285.         else
  286.             return TRUE;
  287.     }
  288.     return cbValues > 0;
  289. }
  290. HRESULT CRegParser::SkipAssignment(LPTSTR szToken)
  291. {
  292.     HRESULT hrResult;
  293.     if (NULL == szToken)
  294.         return E_POINTER;
  295.     if (*szToken == chEquals)
  296.     {
  297.         TCHAR * pszValue;
  298.         pszValue = new TCHAR [MAX_VALUE];
  299.         if (NULL == pszValue)
  300.             return E_OUTOFMEMORY;
  301.         for (;;)
  302.         {
  303.             if (FAILED(hrResult = NextToken(szToken)))
  304.                 break;
  305.             // Skip assignment
  306.             SkipWhiteSpace();
  307.             if (FAILED(hrResult = NextToken(pszValue)))
  308.                 break;
  309.             if (FAILED(hrResult = NextToken(szToken)))
  310.                 break;
  311.             hrResult = S_OK;
  312.             break;
  313.         }
  314.         delete [] pszValue;
  315.     }
  316.     return hrResult;
  317. }
  318. HRESULT CRegParser::RegisterSubkeys(HKEY hkParent, BOOL bRegister, BOOL bInRecovery)
  319. {
  320.     CRegKey keyCur;
  321.     TCHAR * pszToken;
  322.     TCHAR * pszKey;
  323.     LONG    lRes;
  324.     BOOL    bDelete = TRUE;
  325.     BOOL    bRecover = bInRecovery;
  326.     HRESULT hrResult = S_OK;
  327.     pszToken = new TCHAR [MAX_VALUE];
  328.     pszKey = new TCHAR [MAX_VALUE];
  329.     if (NULL == pszToken || NULL == pszKey)
  330.         goto Cleanup;
  331.     for (;;)
  332.     {
  333.         if (FAILED(hrResult = NextToken(pszToken)))  // Should be key name
  334.             break;
  335.         while (*pszToken != chRightBracket) // Continue till we see a }
  336.         {
  337.             BOOL bTokenDelete = !lstrcmpi(pszToken, szDelete);
  338.             if  (
  339.                 !lstrcmpi(pszToken, szForceRemove)
  340.                 ||
  341.                 bTokenDelete
  342.                 )
  343.             {
  344.                 if (FAILED(hrResult = NextToken(pszToken)))
  345.                     break;
  346.                 if (bRegister)
  347.                 {
  348.                     CRegKey rkForceRemove;
  349.                     if (StrChr(pszToken, chDirSep) != NULL)
  350.                     {
  351.                         hrResult = GenerateError(IDS_COMPOUND_KEY);
  352.                         break;
  353.                     }
  354.                     if (CanForceRemoveKey(pszToken))
  355.                     {
  356.                         rkForceRemove.Attach(hkParent);
  357.                         rkForceRemove.RecurseDeleteKey(pszToken);
  358.                         rkForceRemove.Detach();
  359.                     }
  360.                     if (bTokenDelete)
  361.                     {
  362.                         if (FAILED(hrResult = NextToken(pszToken)))
  363.                             break;
  364.                         if (FAILED(hrResult = SkipAssignment(pszToken)))
  365.                             break;
  366.                         goto EndCheck;
  367.                     }
  368.                 }
  369.             }
  370.             if (!lstrcmpi(pszToken, szNoRemove))
  371.             {
  372.                 bDelete = FALSE;    // set even for register
  373.                 if (FAILED(hrResult = NextToken(pszToken)))
  374.                     break;
  375.             }
  376.             if (!lstrcmpi(pszToken, szValToken)) // need to add a value to hkParent
  377.             {
  378.                 TCHAR  szValueName[MAX_PATH];
  379.                 if (FAILED(hrResult = NextToken(szValueName)))
  380.                     break;
  381.                 if (FAILED(hrResult = NextToken(pszToken)))
  382.                     break;
  383.                 if (*pszToken != chEquals)
  384.                 {
  385.                     hrResult = GenerateError(IDS_EXPECTING_EQUAL);
  386.                     break;
  387.                 }
  388.                 if (bRegister)
  389.                 {
  390.                     CRegKey rk;
  391.                     rk.Attach(hkParent);
  392.                     hrResult = AddValue(rk, szValueName, pszToken);
  393.                     rk.Detach();
  394.                     if (FAILED(hrResult))
  395.                         break;
  396.                     goto EndCheck;
  397.                 }
  398.                 else
  399.                 {
  400.                     if (!bRecover)
  401.                         RegDeleteValue(hkParent, szValueName);
  402.                     if (FAILED(hrResult = SkipAssignment(pszToken))) // Strip off type
  403.                         break;
  404.                     continue;  // can never have a subkey
  405.                 }
  406.             }
  407.             if (StrChr(pszToken, chDirSep) != NULL)
  408.             {
  409.                 hrResult = GenerateError(IDS_COMPOUND_KEY);
  410.                 break;
  411.             }
  412.             if (bRegister)
  413.             {
  414.                 lRes = keyCur.Open(hkParent, pszToken, KEY_ALL_ACCESS);
  415.                 if (ERROR_SUCCESS != lRes)
  416.                 {
  417.                     // Failed all access try read only
  418.                     lRes = keyCur.Open(hkParent, pszToken, KEY_READ);
  419.                     if (ERROR_SUCCESS != lRes)
  420.                     {
  421.                         // Finally try creating it
  422.                         lRes = keyCur.Create(hkParent, pszToken);
  423.                         if (ERROR_SUCCESS != lRes)
  424.                         {
  425.                             hrResult = GenerateError(IDS_CREATE_KEY_FAILED);
  426.                             break;
  427.                         }
  428.                     }
  429.                 }
  430.                 if (FAILED(hrResult = NextToken(pszToken)))
  431.                     break;
  432.                 if (*pszToken == chEquals)
  433.                 {
  434.                     if (FAILED(hrResult = AddValue(keyCur, NULL, pszToken))) // NULL == default
  435.                         break;
  436.                 }
  437.             }
  438.             else
  439.             {
  440.                 if (!bRecover && keyCur.Open(hkParent, pszToken) != ERROR_SUCCESS)
  441.                     bRecover = TRUE;
  442.                 // Remember Subkey
  443.                 lstrcpyn(pszKey, pszToken, MAX_PATH);
  444.                 // If in recovery mode
  445.                 if (bRecover || HasSubKeys(keyCur) || HasValues(keyCur))
  446.                 {
  447.                     if (FAILED(hrResult = NextToken(pszToken)))
  448.                         break;
  449.                     if (FAILED(hrResult = SkipAssignment(pszToken)))
  450.                         break;
  451.                     if (*pszToken == chLeftBracket)
  452.                     {
  453.                         if (FAILED(hrResult = RegisterSubkeys(keyCur.m_hKey, bRegister, bRecover)))
  454.                             break;
  455.                     }
  456.                     if (!bRecover && HasSubKeys(keyCur))
  457.                     {
  458.                         // See if the KEY is in the NeverDelete list and if so, don't
  459.                         if (CanForceRemoveKey(pszKey))
  460.                             keyCur.RecurseDeleteKey(pszKey);
  461.                         if (FAILED(hrResult = NextToken(pszToken)))
  462.                             break;
  463.                         continue;
  464.                     }
  465.                 }
  466.                 if (!bRecover && keyCur.Close() != ERROR_SUCCESS)
  467.                 {
  468.                     hrResult = GenerateError(IDS_CLOSE_KEY_FAILED);
  469.                     break;
  470.                 }
  471.                 if (!bRecover && bDelete)
  472.                     RegDeleteKey(hkParent, pszKey);
  473.                 if (FAILED(hrResult = NextToken(pszToken)))
  474.                     break;
  475.                 if (FAILED(hrResult = SkipAssignment(pszToken)))
  476.                     break;
  477.             }
  478. EndCheck:
  479.             if (bRegister)
  480.             {
  481.                 if (*pszToken == chLeftBracket)
  482.                 {
  483.                     if (FAILED(hrResult = RegisterSubkeys(keyCur.m_hKey, bRegister, FALSE)))
  484.                         break;
  485.                     if (FAILED(hrResult = NextToken(pszToken)))
  486.                         break;
  487.                 }
  488.             }
  489.         }
  490.         break;
  491.     }
  492. Cleanup:
  493.     if (pszKey != NULL)
  494.         delete [] pszKey;
  495.     if (pszToken != NULL)
  496.         delete [] pszToken;
  497.     return hrResult;
  498. }
  499. class CParseBuffer
  500. {
  501. public:
  502.     int nPos;
  503.     int nSize;
  504.     LPTSTR p;
  505.     CParseBuffer(int nInitial);
  506.     ~CParseBuffer() {CoTaskMemFree(p);}
  507.     BOOL AddChar(TCHAR ch);
  508.     LPTSTR Detach();
  509. };
  510. LPTSTR CParseBuffer::Detach()
  511. {
  512.     LPTSTR lp = p;
  513.     p = NULL;
  514.     return lp;
  515. }
  516. CParseBuffer::CParseBuffer(int nInitial)
  517. {
  518.     nPos = 0;
  519.     nSize = nInitial;
  520.     p = (LPTSTR) CoTaskMemAlloc(nSize*sizeof(TCHAR));
  521. }
  522. BOOL CParseBuffer::AddChar(TCHAR ch)
  523. {
  524.     if (nPos == nSize) // realloc
  525.     {
  526.         nSize *= 2;
  527.         p = (LPTSTR) CoTaskMemRealloc(p, nSize*sizeof(TCHAR));
  528.     }
  529.     if (NULL == p)
  530.     {
  531.         nSize = 0;
  532.         return FALSE;
  533.     }
  534.     p[nPos++] = ch;
  535.     return TRUE;
  536. }
  537. HRESULT CRegParser::PreProcessBuffer(LPTSTR lpszReg, LPTSTR* ppszReg)
  538. {
  539.     HRESULT hr = S_OK;
  540.     ASSERT(lpszReg != NULL);
  541.     ASSERT(ppszReg != NULL);
  542.     if (NULL == lpszReg || NULL == ppszReg)
  543.         return E_POINTER;
  544.     *ppszReg = NULL;
  545.     int nSize = lstrlen(lpszReg)*2;
  546.     CParseBuffer pb(nSize);
  547.     if (NULL == pb.p)
  548.     {
  549.         hr = E_OUTOFMEMORY;
  550.         goto Cleanup;
  551.     }
  552.     m_pchCur = lpszReg;
  553.     while (*m_pchCur != NULL) // look for end
  554.     {
  555.         if (*m_pchCur == _T('%'))
  556.         {
  557.             IncrementLinePos();
  558.             if (*m_pchCur == _T('%'))
  559.             {
  560.                 if (!pb.AddChar(*m_pchCur))
  561.                 {
  562.                     hr = E_OUTOFMEMORY;
  563.                     goto Cleanup;
  564.                 }
  565.                 
  566.             }
  567.             else
  568.             {
  569.                 LPTSTR lpszNext = StrChr(m_pchCur, _T('%'));
  570.                 if (lpszNext == NULL)
  571.                 {
  572.                     hr = GenerateError(IDS_UNEXPECTED_EOS);
  573.                     break;
  574.                 }
  575.                 int nLength = (int)(lpszNext - m_pchCur);
  576.                 if (nLength > 31)
  577.                 {
  578.                     hr = E_FAIL;
  579.                     break;
  580.                 }
  581.                 TCHAR buf[32];
  582.                 lstrcpyn(buf, m_pchCur, nLength+1);
  583.                 LPTSTR lpszVar = m_pRegObj->StrFromMap(buf);
  584.                 if (lpszVar == NULL)
  585.                 {
  586.                     hr = GenerateError(IDS_NOT_IN_MAP);
  587.                     break;
  588.                 }
  589.                 while (*lpszVar)
  590.                 {
  591.                     if (!pb.AddChar(*lpszVar))
  592.                     {
  593.                         hr = E_OUTOFMEMORY;
  594.                         goto Cleanup;
  595.                     }
  596.                     lpszVar++;
  597.                 }
  598.                 while (m_pchCur != lpszNext)
  599.                     IncrementLinePos();
  600.             }
  601.         }
  602.         else
  603.         {
  604.             if (!pb.AddChar(*m_pchCur))
  605.             {
  606.                 hr = E_OUTOFMEMORY;
  607.                 goto Cleanup;
  608.             }
  609.         }
  610.         IncrementLinePos();
  611.     }
  612.     pb.AddChar(NULL);
  613. Cleanup:
  614.     if (SUCCEEDED(hr))
  615.         *ppszReg = pb.Detach();
  616.     else
  617.         *ppszReg = NULL;
  618.     return hr;
  619. }
  620. HRESULT CRegParser::RegisterBuffer(LPTSTR szBuffer, BOOL bRegister)
  621. {
  622.     TCHAR   szToken[MAX_PATH];
  623.     HRESULT hr = S_OK;
  624.     LPTSTR szReg;
  625.     if (FAILED(hr = PreProcessBuffer(szBuffer, &szReg)))
  626.         return hr;
  627.     m_pchCur = szReg;
  628.     // Preprocess szReg
  629.     while (chEOS != *m_pchCur)
  630.     {
  631.         if (FAILED(hr = NextToken(szToken)))
  632.             break;
  633.         HKEY hkBase;
  634.         if ((hkBase = HKeyFromString(szToken)) == NULL)
  635.             hr = GenerateError(IDS_BAD_HKEY);
  636.             break;
  637.         if (FAILED(hr = NextToken(szToken)))
  638.             return hr;
  639.         if (chLeftBracket != *szToken)
  640.             hr = GenerateError(IDS_MISSING_OPENKEY_TOKEN);
  641.             break;
  642.         if (bRegister)
  643.         {
  644.             LPTSTR szRegAtRegister = m_pchCur;
  645.             HRESULT hr = RegisterSubkeys(hkBase, bRegister);
  646.             if (FAILED(hr))
  647.             {
  648.                 ASSERT(FALSE);
  649.                 m_pchCur = szRegAtRegister;
  650.                 RegisterSubkeys(hkBase, FALSE);
  651.                 break;
  652.             }
  653.         }
  654.         else
  655.         {
  656.             hr = RegisterSubkeys(hkBase, bRegister);
  657.             if (FAILED(hr))
  658.                 break;
  659.         }
  660.         SkipWhiteSpace();
  661.     }
  662.     CoTaskMemFree(szReg);
  663.     return hr;
  664. }
  665. HRESULT CExpansionVector::Add(LPCOLESTR lpszKey, LPCOLESTR lpszValue)
  666. {
  667.     HRESULT hr = S_OK;
  668.     EXPANDER*   pExpand = new EXPANDER;
  669.     pExpand->bstrKey = SysAllocString(lpszKey);
  670.     pExpand->bstrValue = SysAllocString(lpszValue);
  671. #ifndef OLE2ANSI
  672. #ifndef UNICODE
  673.     if (pExpand && pExpand->bstrKey && pExpand->bstrValue)
  674.     {
  675.         OLE2T(lpszValue, p);
  676.         pExpand->lpszValue = (LPSTR) CoTaskMemAlloc((lstrlen(p)+1)*sizeof(char));
  677.         if (pExpand->lpszValue)
  678.             lstrcpy(pExpand->lpszValue, p);
  679.         else
  680.         {
  681.             hr = E_OUTOFMEMORY;
  682.             goto Cleanup;
  683.         }
  684.     }
  685.     else
  686.     {
  687.         hr = E_OUTOFMEMORY;
  688.         goto Cleanup;
  689.     }
  690. #endif
  691. #endif
  692.     if (m_cEls == m_nSize)
  693.     {
  694.         m_nSize*=2;
  695.         m_p = (EXPANDER**)realloc(m_p, m_nSize*sizeof(EXPANDER*));
  696.     }
  697.     if (NULL == m_p)
  698.     {
  699.         hr = E_OUTOFMEMORY;
  700.         m_nSize = 0;
  701.         goto Cleanup;
  702.     }
  703.     m_p[m_cEls] = pExpand;
  704.     m_cEls++;
  705. Cleanup:
  706.     if (FAILED(hr))
  707.     {
  708.     
  709.         if (pExpand)
  710.         {
  711.             if (pExpand->bstrKey)
  712.                 SysFreeString(pExpand->bstrKey);
  713.             if (pExpand->bstrValue)
  714.                 SysFreeString(pExpand->bstrValue);
  715.             delete pExpand;
  716.         }
  717.     }
  718.     return hr;
  719. }
  720. LPTSTR CExpansionVector::Find(LPTSTR lpszKey)
  721. {
  722.     for (int iExpand = 0; iExpand < m_cEls; iExpand++)
  723.     {
  724.         OLE2T(m_p[iExpand]->bstrKey, pszKey);
  725.         if (!lstrcmpi(pszKey, lpszKey)) //are equal
  726. #if defined(UNICODE) | defined(OLE2ANSI)
  727.             return m_p[iExpand]->bstrValue;
  728. #else
  729.             return m_p[iExpand]->lpszValue;
  730. #endif
  731.     }
  732.     return NULL;
  733. }
  734. HRESULT CExpansionVector::ClearReplacements()
  735. {
  736.     for (int iExpand = 0; iExpand < m_cEls; iExpand++)
  737.     {
  738.         EXPANDER* pExp = m_p[iExpand];
  739.         SysFreeString(pExp->bstrKey);
  740.         SysFreeString(pExp->bstrValue);
  741. #ifndef OLE2ANSI
  742. #ifndef UNICODE
  743.         CoTaskMemFree(pExp->lpszValue);
  744. #endif
  745. #endif
  746.         delete pExp;
  747.     }
  748.     m_cEls = 0;
  749.     return S_OK;
  750. }
  751. HRESULT CRegObject::GenerateError(UINT nID, CRegException& re)
  752. {
  753.     re.m_nID    = nID;
  754.     re.m_cLines = -1;
  755.     return DISP_E_EXCEPTION;
  756. }
  757. HRESULT CRegObject::AddReplacement(LPCOLESTR lpszKey, LPCOLESTR lpszItem)
  758. {
  759.     m_csMap.Lock();
  760.     HRESULT hr = m_RepMap.Add(lpszKey, lpszItem);
  761.     m_csMap.Unlock();
  762.     return hr;
  763. }
  764. HRESULT CRegObject::RegisterFromResource(BSTR bstrFileName, LPCTSTR szID,
  765.                                          LPCTSTR szType, CRegException& re,
  766.                                          BOOL bRegister)
  767. {
  768.     HRESULT     hr;
  769.     CRegParser  parser(this);
  770.     HINSTANCE   hInstResDll;
  771.     HRSRC       hrscReg;
  772.     HGLOBAL     hReg;
  773.     DWORD       dwSize;
  774.     LPSTR       szRegA;
  775.     LPTSTR      szReg;
  776.     OLE2T(bstrFileName, pszFilename);
  777.     hInstResDll = LoadLibraryEx(pszFilename, NULL, LOAD_LIBRARY_AS_DATAFILE);
  778.     if (hInstResDll == NULL)
  779.     {
  780.         ASSERT(FALSE);
  781.         hr = HRESULT_FROM_WIN32(GetLastError());
  782.         goto ReturnHR;
  783.     }
  784.     hrscReg = FindResource((HMODULE)hInstResDll, szID, szType);
  785.     if (NULL == hrscReg)
  786.     {
  787.         ASSERT(FALSE);
  788.         hr = HRESULT_FROM_WIN32(GetLastError());
  789.         goto ReturnHR;
  790.     }
  791.     hReg = LoadResource((HMODULE)hInstResDll, hrscReg);
  792.     if (NULL == hReg)
  793.     {
  794.         ASSERT(FALSE);
  795.         hr = HRESULT_FROM_WIN32(GetLastError());
  796.         goto ReturnHR;
  797.     }
  798.     dwSize = SizeofResource((HMODULE)hInstResDll, hrscReg);
  799.     szRegA = (LPSTR)hReg;
  800.     if (szRegA[dwSize] != NULL)
  801.     {
  802.         szRegA = (LPSTR)malloc(dwSize+1);
  803.         if (NULL == szRegA)
  804.         {
  805.             hr = E_OUTOFMEMORY;
  806.             goto ReturnHR;
  807.         }
  808.         memcpy(szRegA, (void*)hReg, dwSize+1);
  809.         szRegA[dwSize] = NULL;
  810.         szReg = A2T(szRegA);
  811.         free(szRegA);
  812.     }
  813.     else
  814.         szReg = A2T(szRegA);
  815.     hr = parser.RegisterBuffer(szReg, bRegister);
  816.     if (FAILED(hr))
  817.         re = parser.GetRegException();
  818. ReturnHR:
  819.     if (NULL != hInstResDll)
  820.         FreeLibrary((HMODULE)hInstResDll);
  821.     return hr;
  822. }
  823. static LPCTSTR StringFromResID(VARIANT& var)
  824. {
  825.     CComVariant varTemp;
  826.     if (FAILED(VariantChangeType(&varTemp, &var, VARIANT_NOVALUEPROP, VT_I2)))
  827.         return NULL;
  828.     return MAKEINTRESOURCE(varTemp.iVal);
  829. }
  830. HRESULT CRegObject::ResourceRegister(BSTR bstrFileName, VARIANT varID,
  831.                                VARIANT varType, CRegException& re)
  832. {
  833.     CString strID;
  834.     if (VT_BSTR == varID.vt)
  835.         strID = varID.bstrVal;
  836.     CString strType;
  837.     if (VT_BSTR == varType.vt)
  838.         strType = varType.bstrVal;
  839.     return RegisterFromResource(bstrFileName,
  840.                                 (varID.vt == VT_BSTR) ? strID : StringFromResID(varID),
  841.                                 (varType.vt == VT_BSTR) ? strType : StringFromResID(varType),
  842.                                 re,
  843.                                 TRUE);
  844. }
  845. HRESULT CRegObject::ResourceUnregister(BSTR bstrFileName, VARIANT varID,
  846.                                VARIANT varType, CRegException& re)
  847. {
  848.     CString strID;
  849.     if (VT_BSTR == varID.vt)
  850.         strID = varID.bstrVal;
  851.     CString strType;
  852.     if (VT_BSTR == varType.vt)
  853.         strType = varType.bstrVal;
  854.     return RegisterFromResource(bstrFileName,
  855.                                 (varID.vt == VT_BSTR) ? strID : StringFromResID(varID),
  856.                                 (varType.vt == VT_BSTR) ? strType : StringFromResID(varType),
  857.                                 re,
  858.                                 FALSE);
  859. }
  860. HRESULT CRegObject::RegisterWithString(BSTR bstrData, BOOL bRegister, CRegException& re)
  861. {
  862.     CRegParser  parser(this);
  863.     OLE2T(bstrData, szReg);
  864.     HRESULT hr = parser.RegisterBuffer(szReg, bRegister);
  865.     if (FAILED(hr))
  866.         re = parser.GetRegException();
  867.     return hr;
  868. }
  869. HRESULT CRegObject::ClearReplacements()
  870. {
  871.     m_csMap.Lock();
  872.     HRESULT hr = m_RepMap.ClearReplacements();
  873.     m_csMap.Unlock();
  874.     return hr;
  875. }
  876. HRESULT CRegObject::DeleteKey(BSTR bstrKey, CRegException& re)
  877. {
  878.     LPTSTR szTail;
  879.     OLE2T(bstrKey, pszKey);
  880.     HKEY hkeyRoot = HKeyFromCompoundString(pszKey, szTail);
  881.     if (NULL == hkeyRoot)
  882.         return GenerateError(IDS_BAD_HKEY, re);
  883.     CRegKey key;
  884.     key.Attach(hkeyRoot);
  885.     LONG lRes = key.RecurseDeleteKey(szTail);
  886.     if (ERROR_SUCCESS != lRes)
  887.         return GenerateError(IDS_DELETE_KEY_FAILED, re);
  888.     return S_OK;
  889. }
  890. HRESULT CRegObject::AddKey(BSTR keyName, CRegException& re)
  891. {
  892.     LPTSTR szTail;
  893.     OLE2T(keyName, pszKeyName);
  894.     HKEY hkeyRoot = HKeyFromCompoundString(pszKeyName, szTail);
  895.     if (NULL == hkeyRoot)
  896.         return GenerateError(IDS_BAD_HKEY, re);
  897.     CRegKey key;
  898.     LONG lRes = key.Create(hkeyRoot, szTail);
  899.     if (ERROR_SUCCESS != lRes)
  900.         return GenerateError(IDS_CREATE_KEY_FAILED, re);
  901.     return S_OK;
  902. }
  903. HRESULT CRegObject::SetKeyValue(BSTR keyName, BSTR valueName, VARIANT value,
  904.     CRegException& re, BOOL bCreateKey)
  905. {
  906.     LPTSTR szTail;
  907.     OLE2T(keyName, pszKeyName);
  908.     HKEY hkeyRoot = HKeyFromCompoundString(pszKeyName, szTail);
  909.     if (hkeyRoot == NULL)
  910.         return GenerateError(IDS_BAD_HKEY, re);
  911.     CRegKey key;
  912.     LONG lRes;
  913.     if (bCreateKey)
  914.         lRes = key.Create(hkeyRoot, szTail);
  915.     else
  916.         lRes = key.Open(hkeyRoot, szTail);
  917.     if (ERROR_SUCCESS != lRes)
  918.         return GenerateError(IDS_CREATE_KEY_FAILED, re);
  919.     OLE2T(valueName, pval);
  920.     if (*valueName == 0)
  921.         pval = NULL;
  922.     CComVariant varString;
  923.     BSTR pb = value.bstrVal;
  924.     BYTE*   pData;
  925.     long    lBound, uBound;
  926.     UINT nIDRes = IDS_CONVERT_FAILED;
  927.     HRESULT hr = S_OK;
  928.     switch (value.vt)
  929.     {
  930.         case VT_I2:
  931.             lRes = key.SetValue(value.iVal, pval);
  932.             break;
  933.         case VT_I4:
  934.             lRes = key.SetValue(value.lVal, pval);
  935.             break;
  936.         case VT_R4:
  937.         case VT_R8:
  938.         case VT_BOOL:
  939.         case VT_DATE:
  940.         case VT_CY:
  941.             lRes = ERROR_SUCCESS;
  942.             hr = DISP_E_TYPEMISMATCH;
  943.             nIDRes = IDS_VALUE_SET_FAILED;
  944.             break;
  945.         case VT_BSTR:
  946.         {
  947.             OLE2T(pb, szpb);
  948.             lRes = key.SetValue(szpb, pval);
  949.             break;
  950.         }
  951.         case VT_SAFEARRAY|VT_UI1:
  952.             hr = E_FAIL;
  953.             if (SafeArrayGetDim(value.parray) != 1) // Verify 1 Dimension
  954.                 break;
  955.             hr = SafeArrayGetLBound(value.parray, 1, &lBound);
  956.             if (FAILED(hr))
  957.                 break;
  958.             hr = SafeArrayGetUBound(value.parray, 1, &uBound);
  959.             if (FAILED(hr))
  960.                 break;
  961.             hr = SafeArrayAccessData(value.parray, (void**)&pData);
  962.             if (FAILED(hr))
  963.                 break;
  964.             lRes = RegSetValueEx(key, pval, 0, REG_BINARY, pData,
  965.                 (uBound - lBound) + 1);
  966.             SafeArrayUnaccessData(value.parray);
  967.             break;
  968.         default:
  969.             lRes = ERROR_INVALID_DATA;
  970.     }
  971.     if (ERROR_SUCCESS != lRes)
  972.         return GenerateError(IDS_VALUE_SET_FAILED, re);
  973.     if (FAILED(hr))
  974.         return GenerateError(nIDRes, re);
  975.     return S_OK;
  976. }
  977. HRESULT CRegObject::GetKeyValue(BSTR keyName, BSTR valueName, VARIANT* value, CRegException& re)
  978. {
  979.     LPTSTR      szTail;
  980.     HRESULT     hr = S_OK;
  981.     OLE2T(keyName, szKeyName);
  982.     HKEY hkeyRoot = HKeyFromCompoundString(szKeyName, szTail);
  983.     if (NULL == hkeyRoot)
  984.         return GenerateError(IDS_BAD_HKEY, re);
  985.     CRegKey key;
  986.     LONG lRes = key.Open(hkeyRoot, szTail);
  987.     if (ERROR_SUCCESS != lRes)
  988.         return GenerateError(IDS_OPEN_KEY_FAILED, re);
  989.     DWORD dwType;
  990.     OLE2T(valueName, szValueName);
  991.     LPVOID pData = QueryValue(key.m_hKey, szValueName, dwType);
  992.     value->vt = VT_EMPTY;
  993.     if (NULL == pData)
  994.     {
  995.         hr = E_OUTOFMEMORY;
  996.         goto Cleanup;
  997.     }
  998.     switch (dwType)
  999.     {
  1000.         case REG_DWORD:
  1001.             value->vt = VT_I4;
  1002.             value->lVal = *((long *) pData);
  1003.             break;
  1004.         case REG_SZ:
  1005.         {
  1006.             value->vt = VT_BSTR;
  1007.             T2OLE((LPTSTR)pData, posData);
  1008.             value->bstrVal = SysAllocString(posData);
  1009.             if (NULL == value->bstrVal)
  1010.                 hr = E_OUTOFMEMORY;
  1011.             break;
  1012.         }
  1013.         default:
  1014.             hr = E_FAIL;
  1015.     }
  1016. Cleanup:
  1017.     if (pData)
  1018.         CoTaskMemFree(pData);
  1019.     if (FAILED(hr))
  1020.         return GenerateError(IDS_VALUE_GET_FAILED, re);
  1021.     return hr;
  1022. }
  1023. LPTSTR CRegObject::StrFromMap(LPTSTR lpszKey)
  1024. {
  1025.     m_csMap.Lock();
  1026.     LPTSTR lpsz = m_RepMap.Find(lpszKey);
  1027.     ASSERT(lpsz != NULL);
  1028.     m_csMap.Unlock();
  1029.     return lpsz;
  1030. }
  1031. HRESULT CRegObject::MemMapAndRegister(BSTR bstrFileName, BOOL bRegister,
  1032.                                       CRegException& re)
  1033. {
  1034.     CRegParser  parser(this);
  1035.     OLE2T(bstrFileName, strFilename);
  1036.     HANDLE hFile = CreateFile(strFilename, GENERIC_READ, 0, NULL,
  1037.                               OPEN_EXISTING,
  1038.                               FILE_ATTRIBUTE_READONLY,
  1039.                               NULL);
  1040.     if (hFile == INVALID_HANDLE_VALUE)
  1041.     {
  1042.         ASSERT(FALSE);
  1043.         return HRESULT_FROM_WIN32(GetLastError());
  1044.     }
  1045.     DWORD cbFile = GetFileSize(hFile, NULL); // No HiOrder DWORD required
  1046.     HANDLE hMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
  1047.     if (hMapping == NULL)
  1048.     {
  1049.         ASSERT(FALSE);
  1050.         return HRESULT_FROM_WIN32(GetLastError());
  1051.     }
  1052.     LPVOID pMap = MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0);
  1053.     if (pMap == NULL)
  1054.     {
  1055.         ASSERT(FALSE);
  1056.         return HRESULT_FROM_WIN32(GetLastError());
  1057.     }
  1058.     LPTSTR szReg = A2T((char*)pMap);
  1059.     if (chEOS != szReg[cbFile]) //ensure buffer is NULL terminated
  1060.     {
  1061.         ASSERT(FALSE);
  1062.         return E_FAIL; // make a real error
  1063.     }
  1064.     HRESULT hRes = parser.RegisterBuffer(szReg, bRegister);
  1065.     if (FAILED(hRes))
  1066.         re = parser.GetRegException();
  1067.     UnmapViewOfFile(pMap);
  1068.     CloseHandle(hMapping);
  1069.     CloseHandle(hFile);
  1070.     return hRes;
  1071. }