home *** CD-ROM | disk | FTP | other *** search
/ Team Palmtops 7 / Palmtops_numero07.iso / WinCE / SDKWindowsCE / HandHeldPCPro30 / sdk.exe / Jupiter SDK / data1.cab / ATL / include / Statreg.h < prev    next >
Encoding:
C/C++ Source or Header  |  1999-02-19  |  29.6 KB  |  1,226 lines

  1. // This is a part of the Active Template Library.
  2. // Copyright (C) 1996-1998 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Active Template Library Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Active Template Library product.
  10.  
  11. #ifndef __STATREG_H
  12. #define __STATREG_H
  13.  
  14. #define E_ATL_REGISTRAR_DESC              0x0201
  15. #define E_ATL_NOT_IN_MAP                  0x0202
  16. #define E_ATL_UNEXPECTED_EOS              0x0203
  17. #define E_ATL_VALUE_SET_FAILED            0x0204
  18. #define E_ATL_RECURSE_DELETE_FAILED       0x0205
  19. #define E_ATL_EXPECTING_EQUAL             0x0206
  20. #define E_ATL_CREATE_KEY_FAILED           0x0207
  21. #define E_ATL_DELETE_KEY_FAILED           0x0208
  22. #define E_ATL_OPEN_KEY_FAILED             0x0209
  23. #define E_ATL_CLOSE_KEY_FAILED            0x020A
  24. #define E_ATL_UNABLE_TO_COERCE            0x020B
  25. #define E_ATL_BAD_HKEY                    0x020C
  26. #define E_ATL_MISSING_OPENKEY_TOKEN       0x020D
  27. #define E_ATL_CONVERT_FAILED              0x020E
  28. #define E_ATL_TYPE_NOT_SUPPORTED          0x020F
  29. #define E_ATL_COULD_NOT_CONCAT            0x0210
  30. #define E_ATL_COMPOUND_KEY                0x0211
  31. #define E_ATL_INVALID_MAPKEY              0x0212
  32. #define E_ATL_UNSUPPORTED_VT              0x0213
  33. #define E_ATL_VALUE_GET_FAILED            0x0214
  34. #define E_ATL_VALUE_TOO_LARGE             0x0215
  35. #define E_ATL_MISSING_VALUE_DELIMETER     0x0216
  36. #define E_ATL_DATA_NOT_BYTE_ALIGNED       0x0217
  37.  
  38. namespace ATL
  39. {
  40. const TCHAR  chDirSep            = _T('\\');
  41. const TCHAR  chRightBracket      = _T('}');
  42. const TCHAR  chLeftBracket       = _T('{');
  43. const TCHAR  chQuote             = _T('\'');
  44. const TCHAR  chEquals            = _T('=');
  45. const LPCTSTR  szStringVal       = _T("S");
  46. const LPCTSTR  szDwordVal        = _T("D");
  47. const LPCTSTR  szBinaryVal       = _T("B");
  48. const LPCTSTR  szValToken        = _T("Val");
  49. const LPCTSTR  szForceRemove     = _T("ForceRemove");
  50. const LPCTSTR  szNoRemove        = _T("NoRemove");
  51. const LPCTSTR  szDelete          = _T("Delete");
  52.  
  53. class CExpansionVector
  54. {
  55. public:
  56.     //Declare EXPANDER struct.  Only used locally.
  57.     struct EXPANDER
  58.     {
  59.         LPOLESTR    szKey;
  60.         LPOLESTR    szValue;
  61.     };
  62.  
  63.     CExpansionVector()
  64.     {
  65.         m_cEls = 0;
  66.         m_nSize=10;
  67.         m_p = (EXPANDER**)malloc(m_nSize*sizeof(EXPANDER*));
  68.     }
  69.     ~CExpansionVector()
  70.     {
  71.          free(m_p);
  72.     }
  73.     HRESULT Add(LPCOLESTR lpszKey, LPCOLESTR lpszValue)
  74.     {
  75.         USES_CONVERSION;
  76.         HRESULT hr = S_OK;
  77.  
  78.         EXPANDER* pExpand = NULL;
  79.         ATLTRY(pExpand = new EXPANDER);
  80.         if (pExpand == NULL)
  81.             return E_OUTOFMEMORY;
  82.  
  83.         DWORD cbKey = (ocslen(lpszKey)+1)*sizeof(OLECHAR);
  84.         DWORD cbValue = (ocslen(lpszValue)+1)*sizeof(OLECHAR);
  85.         pExpand->szKey = (LPOLESTR)CoTaskMemAlloc(cbKey);
  86.         pExpand->szValue = (LPOLESTR)CoTaskMemAlloc(cbValue);
  87.         if (pExpand->szKey == NULL || pExpand->szValue == NULL)
  88.         {
  89.             CoTaskMemFree(pExpand->szKey);
  90.             CoTaskMemFree(pExpand->szValue);
  91.             delete pExpand;
  92.             return E_OUTOFMEMORY;
  93.         }
  94.         memcpy(pExpand->szKey, lpszKey, cbKey);
  95.         memcpy(pExpand->szValue, lpszValue, cbValue);
  96.  
  97.         if (m_cEls == m_nSize)
  98.         {
  99.             m_nSize*=2;
  100.             m_p = (EXPANDER**)realloc(m_p, m_nSize*sizeof(EXPANDER*));
  101.         }
  102.  
  103.         if (NULL != m_p)
  104.         {
  105.             m_p[m_cEls] = pExpand;
  106.             m_cEls++;
  107.         }
  108.         else
  109.             hr = E_OUTOFMEMORY;
  110.  
  111.         return hr;
  112.  
  113.     }
  114.     LPCOLESTR Find(LPTSTR lpszKey)
  115.     {
  116.         USES_CONVERSION;
  117.         for (int iExpand = 0; iExpand < m_cEls; iExpand++)
  118.         {
  119.             if (!lstrcmpi(OLE2T(m_p[iExpand]->szKey), lpszKey)) //are equal
  120.                 return m_p[iExpand]->szValue;
  121.         }
  122.         return NULL;
  123.     }
  124.     HRESULT ClearReplacements()
  125.     {
  126.         for (int iExpand = 0; iExpand < m_cEls; iExpand++)
  127.         {
  128.             EXPANDER* pExp = m_p[iExpand];
  129.             CoTaskMemFree(pExp->szValue);
  130.             CoTaskMemFree(pExp->szKey);
  131.             delete pExp;
  132.         }
  133.         m_cEls = 0;
  134.         return S_OK;
  135.     }
  136.  
  137. private:
  138.     EXPANDER** m_p;
  139.     int m_cEls;
  140.     int m_nSize;
  141. };
  142.  
  143. class CRegObject;
  144.  
  145. class CRegParser
  146. {
  147. public:
  148.     CRegParser(CRegObject* pRegObj);
  149.  
  150.     HRESULT  PreProcessBuffer(LPTSTR lpszReg, LPTSTR* ppszReg);
  151.     HRESULT  RegisterBuffer(LPTSTR szReg, BOOL bRegister);
  152.  
  153. protected:
  154.  
  155.     void    SkipWhiteSpace();
  156.     HRESULT NextToken(LPTSTR szToken);
  157.     HRESULT AddValue(CRegKey& rkParent,LPCTSTR szValueName, LPTSTR szToken);
  158.     BOOL    CanForceRemoveKey(LPCTSTR szKey);
  159.     BOOL    HasSubKeys(HKEY hkey);
  160.     BOOL    HasValues(HKEY hkey);
  161.     HRESULT RegisterSubkeys(LPTSTR szToken, HKEY hkParent, BOOL bRegister, BOOL bInRecovery = FALSE);
  162.     BOOL    IsSpace(TCHAR ch);
  163.     LPTSTR  m_pchCur;
  164.  
  165.     CRegObject*     m_pRegObj;
  166.  
  167.     HRESULT GenerateError(UINT) {return DISP_E_EXCEPTION;}
  168.     HRESULT HandleReplacements(LPTSTR& szToken);
  169.     HRESULT SkipAssignment(LPTSTR szToken);
  170.  
  171.     BOOL    EndOfVar() { return chQuote == *m_pchCur && chQuote != *CharNext(m_pchCur); }
  172.     static LPTSTR StrChr(LPTSTR lpsz, TCHAR ch);
  173.     static HKEY HKeyFromString(LPTSTR szToken);
  174.     static BYTE ChToByte(const TCHAR ch);
  175.     static BOOL VTFromRegType(LPCTSTR szValueType, VARTYPE& vt);
  176.     static LPCTSTR rgszNeverDelete[];
  177.     static const int cbNeverDelete;
  178.     static const int MAX_VALUE;
  179.     static const int MAX_TYPE;
  180.     class CParseBuffer
  181.     {
  182.     public:
  183.         int nPos;
  184.         int nSize;
  185.         LPTSTR p;
  186.         CParseBuffer(int nInitial)
  187.         {
  188.             nPos = 0;
  189.             nSize = nInitial;
  190.             p = (LPTSTR) CoTaskMemAlloc(nSize*sizeof(TCHAR));
  191.         }
  192.         ~CParseBuffer()
  193.         {
  194.             CoTaskMemFree(p);
  195.         }
  196.         BOOL AddChar(const TCHAR* pch)
  197.         {
  198.             if (nPos == nSize) // realloc
  199.             {
  200.                 nSize *= 2;
  201.                 p = (LPTSTR) CoTaskMemRealloc(p, nSize*sizeof(TCHAR));
  202.             }
  203.             p[nPos++] = *pch;
  204. #ifndef _UNICODE
  205.             if (IsDBCSLeadByte(*pch))
  206.                 p[nPos++] = *(pch + 1);
  207. #endif
  208.             return TRUE;
  209.         }
  210.         BOOL AddString(LPCOLESTR lpsz)
  211.         {
  212.             USES_CONVERSION;
  213.             LPCTSTR lpszT = OLE2CT(lpsz);
  214.             while (*lpszT)
  215.             {
  216.                 AddChar(lpszT);
  217.                 lpszT++;
  218.             }
  219.             return TRUE;
  220.         }
  221.         LPTSTR Detach()
  222.         {
  223.             LPTSTR lp = p;
  224.             p = NULL;
  225.             return lp;
  226.         }
  227.  
  228.     };
  229. };
  230.  
  231. #if defined(_ATL_DLL) | defined(_ATL_DLL_IMPL)
  232. class ATL_NO_VTABLE CRegObject
  233.  : public IRegistrar
  234. #else
  235. class CRegObject
  236. #endif
  237. {
  238. public:
  239.  
  240.     ~CRegObject(){ClearReplacements();}
  241.     HRESULT FinalConstruct() {return S_OK;}
  242.     void FinalRelease() {}
  243.  
  244.  
  245.     // Map based methods
  246.     HRESULT STDMETHODCALLTYPE AddReplacement(LPCOLESTR lpszKey, LPCOLESTR lpszItem);
  247.     HRESULT STDMETHODCALLTYPE ClearReplacements();
  248.     LPCOLESTR StrFromMap(LPTSTR lpszKey);
  249.  
  250.     // Register via a given mechanism
  251.     HRESULT STDMETHODCALLTYPE ResourceRegister(LPCOLESTR pszFileName, UINT nID, LPCOLESTR pszType);
  252.     HRESULT STDMETHODCALLTYPE ResourceRegisterSz(LPCOLESTR pszFileName, LPCOLESTR pszID, LPCOLESTR pszType);
  253.     HRESULT STDMETHODCALLTYPE ResourceUnregister(LPCOLESTR pszFileName, UINT nID, LPCOLESTR pszType);
  254.     HRESULT STDMETHODCALLTYPE ResourceUnregisterSz(LPCOLESTR pszFileName, LPCOLESTR pszID, LPCOLESTR pszType);
  255.     HRESULT STDMETHODCALLTYPE FileRegister(LPCOLESTR bstrFileName)
  256.     {
  257.         return CommonFileRegister(bstrFileName, TRUE);
  258.     }
  259.  
  260.     HRESULT STDMETHODCALLTYPE FileUnregister(LPCOLESTR bstrFileName)
  261.     {
  262.         return CommonFileRegister(bstrFileName, FALSE);
  263.     }
  264.  
  265.     HRESULT STDMETHODCALLTYPE StringRegister(LPCOLESTR bstrData)
  266.     {
  267.         return RegisterWithString(bstrData, TRUE);
  268.     }
  269.  
  270.     HRESULT STDMETHODCALLTYPE StringUnregister(LPCOLESTR bstrData)
  271.     {
  272.         return RegisterWithString(bstrData, FALSE);
  273.     }
  274.  
  275. protected:
  276.  
  277.     HRESULT CommonFileRegister(LPCOLESTR pszFileName, BOOL bRegister);
  278.     HRESULT RegisterFromResource(LPCOLESTR pszFileName, LPCTSTR pszID, LPCTSTR pszType, BOOL bRegister);
  279.     HRESULT RegisterWithString(LPCOLESTR pszData, BOOL bRegister);
  280.  
  281.     static HRESULT GenerateError(UINT) {return DISP_E_EXCEPTION;}
  282.  
  283.     CExpansionVector                                m_RepMap;
  284.     CComObjectThreadModel::AutoCriticalSection      m_csMap;
  285. };
  286.  
  287. inline HRESULT STDMETHODCALLTYPE CRegObject::AddReplacement(LPCOLESTR lpszKey, LPCOLESTR lpszItem)
  288. {
  289.     m_csMap.Lock();
  290.     HRESULT hr = m_RepMap.Add(lpszKey, lpszItem);
  291.     m_csMap.Unlock();
  292.     return hr;
  293. }
  294.  
  295. inline HRESULT CRegObject::RegisterFromResource(LPCOLESTR bstrFileName, LPCTSTR szID,
  296.                                          LPCTSTR szType, BOOL bRegister)
  297. {
  298.     USES_CONVERSION;
  299.  
  300.     HRESULT     hr;
  301.     CRegParser  parser(this);
  302.     HINSTANCE   hInstResDll;
  303.     HRSRC       hrscReg;
  304.     HGLOBAL     hReg;
  305.     DWORD       dwSize;
  306.     LPSTR       szRegA;
  307.     LPTSTR      szReg;
  308.  
  309. #if defined(_WIN32_WCE)
  310.     hInstResDll = LoadLibrary(OLE2CT(bstrFileName));
  311. #else // _WIN32_WCE
  312.     hInstResDll = LoadLibraryEx(OLE2CT(bstrFileName), NULL, LOAD_LIBRARY_AS_DATAFILE);
  313. #endif // _WIN32_WCE
  314.  
  315.     if (NULL == hInstResDll)
  316.     {
  317.         ATLTRACE2(atlTraceRegistrar, 0, _T("Failed to LoadLibrary on %s\n"), OLE2CT(bstrFileName));
  318.         hr = HRESULT_FROM_WIN32(GetLastError());
  319.         goto ReturnHR;
  320.     }
  321.  
  322.     hrscReg = FindResource((HMODULE)hInstResDll, szID, szType);
  323.  
  324.     if (NULL == hrscReg)
  325.     {
  326.         ATLTRACE2(atlTraceRegistrar, 0, (HIWORD(szID) == NULL) ? 
  327.             _T("Failed to FindResource on ID:%d TYPE:%s\n") : 
  328.             _T("Failed to FindResource on ID:%s TYPE:%s\n"), 
  329.             szID, szType);
  330.         hr = HRESULT_FROM_WIN32(GetLastError());
  331.         goto ReturnHR;
  332.     }
  333.  
  334.     hReg = LoadResource((HMODULE)hInstResDll, hrscReg);
  335.  
  336.     if (NULL == hReg)
  337.     {
  338.         ATLTRACE2(atlTraceRegistrar, 0, _T("Failed to LoadResource \n"));
  339.         hr = HRESULT_FROM_WIN32(GetLastError());
  340.         goto ReturnHR;
  341.     }
  342.  
  343.     dwSize = SizeofResource((HMODULE)hInstResDll, hrscReg);
  344.     szRegA = (LPSTR)hReg;
  345.     if (szRegA[dwSize] != NULL)
  346.     {
  347.         szRegA = (LPSTR)_alloca(dwSize+1);
  348.         memcpy(szRegA, (void*)hReg, dwSize+1);
  349.         szRegA[dwSize] = NULL;
  350.     }
  351.  
  352.     szReg = A2T(szRegA);
  353.  
  354.     hr = parser.RegisterBuffer(szReg, bRegister);
  355.  
  356. ReturnHR:
  357.  
  358.     if (NULL != hInstResDll)
  359.         FreeLibrary((HMODULE)hInstResDll);
  360.     return hr;
  361. }
  362.  
  363. inline HRESULT STDMETHODCALLTYPE CRegObject::ResourceRegister(LPCOLESTR szFileName, UINT nID, LPCOLESTR szType)
  364. {
  365.     USES_CONVERSION;
  366.     return RegisterFromResource(szFileName, MAKEINTRESOURCE(nID), OLE2CT(szType), TRUE);
  367. }
  368.  
  369. inline HRESULT STDMETHODCALLTYPE CRegObject::ResourceRegisterSz(LPCOLESTR szFileName, LPCOLESTR szID, LPCOLESTR szType)
  370. {
  371.     USES_CONVERSION;
  372.     if (szID == NULL || szType == NULL)
  373.         return E_INVALIDARG;
  374.     return RegisterFromResource(szFileName, OLE2CT(szID), OLE2CT(szType), TRUE);
  375. }
  376.  
  377. inline HRESULT STDMETHODCALLTYPE CRegObject::ResourceUnregister(LPCOLESTR szFileName, UINT nID, LPCOLESTR szType)
  378. {
  379.     USES_CONVERSION;
  380.     return RegisterFromResource(szFileName, MAKEINTRESOURCE(nID), OLE2CT(szType), FALSE);
  381. }
  382.  
  383. inline HRESULT STDMETHODCALLTYPE CRegObject::ResourceUnregisterSz(LPCOLESTR szFileName, LPCOLESTR szID, LPCOLESTR szType)
  384. {
  385.     USES_CONVERSION;
  386.     if (szID == NULL || szType == NULL)
  387.         return E_INVALIDARG;
  388.  
  389.     return RegisterFromResource(szFileName, OLE2CT(szID), OLE2CT(szType), FALSE);
  390. }
  391.  
  392. inline HRESULT CRegObject::RegisterWithString(LPCOLESTR bstrData, BOOL bRegister)
  393. {
  394.     USES_CONVERSION;
  395.     CRegParser  parser(this);
  396.  
  397.  
  398.     LPCTSTR szReg = OLE2CT(bstrData);
  399.  
  400.     HRESULT hr = parser.RegisterBuffer((LPTSTR)szReg, bRegister);
  401.  
  402.     return hr;
  403. }
  404.  
  405. inline HRESULT CRegObject::ClearReplacements()
  406. {
  407.     m_csMap.Lock();
  408.     HRESULT hr = m_RepMap.ClearReplacements();
  409.     m_csMap.Unlock();
  410.     return hr;
  411. }
  412.  
  413.  
  414. inline LPCOLESTR CRegObject::StrFromMap(LPTSTR lpszKey)
  415. {
  416.     m_csMap.Lock();
  417.     LPCOLESTR lpsz = m_RepMap.Find(lpszKey);
  418.     if (lpsz == NULL) // not found!!
  419.         ATLTRACE2(atlTraceRegistrar, 0, _T("Map Entry not found\n"));
  420.     m_csMap.Unlock();
  421.     return lpsz;
  422. }
  423.  
  424. inline HRESULT CRegObject::CommonFileRegister(LPCOLESTR bstrFileName, BOOL bRegister)
  425. {
  426.     USES_CONVERSION;
  427.  
  428.     CRegParser  parser(this);
  429.  
  430.     HANDLE hFile = CreateFile(OLE2CT(bstrFileName), GENERIC_READ, 0, NULL,
  431.                               OPEN_EXISTING,
  432.                               FILE_ATTRIBUTE_READONLY,
  433.                               NULL);
  434.     if (INVALID_HANDLE_VALUE == hFile)
  435.     {
  436.         ATLTRACE2(atlTraceRegistrar, 0, _T("Failed to CreateFile on %s\n"), OLE2CT(bstrFileName));
  437.         return HRESULT_FROM_WIN32(GetLastError());
  438.     }
  439.  
  440.     HRESULT hRes = S_OK;
  441.     DWORD cbRead;
  442.     DWORD cbFile = GetFileSize(hFile, NULL); // No HiOrder DWORD required
  443.     char* szReg = (char*)_alloca(cbFile + 1);
  444.     if (ReadFile(hFile, szReg, cbFile, &cbRead, NULL) == 0)
  445.     {
  446. #if defined(_WIN32_WCE)
  447.         ATLTRACE2(atlTraceRegistrar, 0, _T("Read Failed on file%s\n"), OLE2CT(bstrFileName));
  448. #else // _WIN32_WCE
  449.         ATLTRACE2(atlTraceRegistrar, 0, "Read Failed on file%s\n", OLE2CT(bstrFileName));
  450. #endif // _WIN32_WCE
  451.         hRes =  HRESULT_FROM_WIN32(GetLastError());
  452.     }
  453.     if (SUCCEEDED(hRes))
  454.     {
  455.         szReg[cbRead] = NULL;
  456.         LPTSTR szConverted = A2T(szReg);
  457.         hRes = parser.RegisterBuffer(szConverted, bRegister);
  458.     }
  459.     CloseHandle(hFile);
  460.     return hRes;
  461. }
  462.  
  463. __declspec(selectany) LPCTSTR CRegParser::rgszNeverDelete[] = //Component Catagories
  464. {
  465.     _T("CLSID"), _T("TYPELIB")
  466. };
  467.  
  468. __declspec(selectany) const int CRegParser::cbNeverDelete = sizeof(rgszNeverDelete) / sizeof(LPCTSTR*);
  469. __declspec(selectany) const int CRegParser::MAX_VALUE=4096;
  470. __declspec(selectany) const int CRegParser::MAX_TYPE=MAX_VALUE;
  471.  
  472.  
  473. inline BOOL CRegParser::VTFromRegType(LPCTSTR szValueType, VARTYPE& vt)
  474. {
  475.     struct typemap
  476.     {
  477.         LPCTSTR lpsz;
  478.         VARTYPE vt;
  479.     };
  480.     static const typemap map[] = {
  481.         {szStringVal, VT_BSTR},
  482.         {szDwordVal,  VT_UI4},
  483.         {szBinaryVal, VT_UI1}
  484.     };
  485.  
  486.     for (int i=0;i<sizeof(map)/sizeof(typemap);i++)
  487.     {
  488.         if (!lstrcmpi(szValueType, map[i].lpsz))
  489.         {
  490.             vt = map[i].vt;
  491.             return TRUE;
  492.         }
  493.     }
  494.  
  495.     return FALSE;
  496.  
  497. }
  498.  
  499. inline BYTE CRegParser::ChToByte(const TCHAR ch)
  500. {
  501.     switch (ch)
  502.     {
  503.         case '0':
  504.         case '1':
  505.         case '2':
  506.         case '3':
  507.         case '4':
  508.         case '5':
  509.         case '6':
  510.         case '7':
  511.         case '8':
  512.         case '9':
  513.                 return (BYTE) (ch - '0');
  514.         case 'A':
  515.         case 'B':
  516.         case 'C':
  517.         case 'D':
  518.         case 'E':
  519.         case 'F':
  520.                 return (BYTE) (10 + (ch - 'A'));
  521.         case 'a':
  522.         case 'b':
  523.         case 'c':
  524.         case 'd':
  525.         case 'e':
  526.         case 'f':
  527.                 return (BYTE) (10 + (ch - 'a'));
  528.         default:
  529.                 ATLASSERT(FALSE);
  530.                 ATLTRACE2(atlTraceRegistrar, 0, _T("Bogus value %c passed as binary Hex value\n"), ch);
  531.                 return 0;
  532.     }
  533. }
  534.  
  535. inline HKEY CRegParser::HKeyFromString(LPTSTR szToken)
  536. {
  537.     struct keymap
  538.     {
  539.         LPCTSTR lpsz;
  540.         HKEY hkey;
  541.     };
  542.     static const keymap map[] = {
  543.         {_T("HKCR"), HKEY_CLASSES_ROOT},
  544.         {_T("HKCU"), HKEY_CURRENT_USER},
  545.         {_T("HKLM"), HKEY_LOCAL_MACHINE},
  546.         {_T("HKU"),  HKEY_USERS},
  547.         WCE_DEL {_T("HKPD"), HKEY_PERFORMANCE_DATA},
  548.         WCE_DEL {_T("HKDD"), HKEY_DYN_DATA},
  549.         WCE_DEL {_T("HKCC"), HKEY_CURRENT_CONFIG},
  550.         {_T("HKEY_CLASSES_ROOT"), HKEY_CLASSES_ROOT},
  551.         {_T("HKEY_CURRENT_USER"), HKEY_CURRENT_USER},
  552.         {_T("HKEY_LOCAL_MACHINE"), HKEY_LOCAL_MACHINE},
  553.         {_T("HKEY_USERS"), HKEY_USERS},
  554.         WCE_DEL {_T("HKEY_PERFORMANCE_DATA"), HKEY_PERFORMANCE_DATA},
  555.         WCE_DEL {_T("HKEY_DYN_DATA"), HKEY_DYN_DATA},
  556.         WCE_DEL {_T("HKEY_CURRENT_CONFIG"), HKEY_CURRENT_CONFIG}
  557.     };
  558.  
  559.     for (int i=0;i<sizeof(map)/sizeof(keymap);i++)
  560.     {
  561.         if (!lstrcmpi(szToken, map[i].lpsz))
  562.             return map[i].hkey;
  563.     }
  564.     return NULL;
  565. }
  566.  
  567. inline LPTSTR CRegParser::StrChr(LPTSTR lpsz, TCHAR ch)
  568. {
  569.     LPTSTR p = NULL;
  570.     while (*lpsz)
  571.     {
  572.         if (*lpsz == ch)
  573.         {
  574.             p = lpsz;
  575.             break;
  576.         }
  577.         lpsz = CharNext(lpsz);
  578.     }
  579.     return p;
  580. }
  581.  
  582. inline CRegParser::CRegParser(CRegObject* pRegObj)
  583. {
  584.     m_pRegObj           = pRegObj;
  585.     m_pchCur            = NULL;
  586. }
  587.  
  588. inline BOOL CRegParser::IsSpace(TCHAR ch)
  589. {
  590.     switch (ch)
  591.     {
  592.         case _T(' '):
  593.         case _T('\t'):
  594.         case _T('\r'):
  595.         case _T('\n'):
  596.                 return TRUE;
  597.     }
  598.  
  599.     return FALSE;
  600. }
  601.  
  602. inline void CRegParser::SkipWhiteSpace()
  603. {
  604.     while(IsSpace(*m_pchCur))
  605.         m_pchCur = CharNext(m_pchCur);
  606. }
  607.  
  608. inline HRESULT CRegParser::NextToken(LPTSTR szToken)
  609. {
  610.     USES_CONVERSION;
  611.  
  612.     SkipWhiteSpace();
  613.  
  614.     // NextToken cannot be called at EOS
  615.     if (NULL == *m_pchCur)
  616.         return GenerateError(E_ATL_UNEXPECTED_EOS);
  617.  
  618.     // handle quoted value / key
  619.     if (chQuote == *m_pchCur)
  620.     {
  621.         LPCTSTR szOrig = szToken;
  622.  
  623.         m_pchCur = CharNext(m_pchCur);
  624.  
  625.         while (NULL != *m_pchCur && !EndOfVar())
  626.         {
  627.             if (chQuote == *m_pchCur) // If it is a quote that means we must skip it
  628.                 m_pchCur = CharNext(m_pchCur);
  629.  
  630.             LPTSTR pchPrev = m_pchCur;
  631.             m_pchCur = CharNext(m_pchCur);
  632.  
  633.             if (szToken + sizeof(WORD) >= MAX_VALUE + szOrig)
  634.                 return GenerateError(E_ATL_VALUE_TOO_LARGE);
  635.             for (int i = 0; pchPrev+i < m_pchCur; i++, szToken++)
  636.                 *szToken = *(pchPrev+i);
  637.         }
  638.  
  639.         if (NULL == *m_pchCur)
  640.         {
  641.             ATLTRACE2(atlTraceRegistrar, 0, _T("NextToken : Unexpected End of File\n"));
  642.             return GenerateError(E_ATL_UNEXPECTED_EOS);
  643.         }
  644.  
  645.         *szToken = NULL;
  646.         m_pchCur = CharNext(m_pchCur);
  647.     }
  648.  
  649.     else
  650.     {   // Handle non-quoted ie parse up till first "White Space"
  651.         while (NULL != *m_pchCur && !IsSpace(*m_pchCur))
  652.         {
  653.             LPTSTR pchPrev = m_pchCur;
  654.             m_pchCur = CharNext(m_pchCur);
  655.             for (int i = 0; pchPrev+i < m_pchCur; i++, szToken++)
  656.                 *szToken = *(pchPrev+i);
  657.         }
  658.  
  659.         *szToken = NULL;
  660.     }
  661.     return S_OK;
  662. }
  663.  
  664. inline HRESULT CRegParser::AddValue(CRegKey& rkParent,LPCTSTR szValueName, LPTSTR szToken)
  665. {
  666.     USES_CONVERSION;
  667.     HRESULT hr;
  668.  
  669.     TCHAR       szTypeToken[MAX_TYPE];
  670.     VARTYPE     vt;
  671.     LONG        lRes = ERROR_SUCCESS;
  672.     UINT        nIDRes = 0;
  673.  
  674.     if (FAILED(hr = NextToken(szTypeToken)))
  675.         return hr;
  676.     if (!VTFromRegType(szTypeToken, vt))
  677.     {
  678.         ATLTRACE2(atlTraceRegistrar, 0, _T("%s Type not supported\n"), szTypeToken);
  679.         return GenerateError(E_ATL_TYPE_NOT_SUPPORTED);
  680.     }
  681.  
  682. #if defined(_WIN32_WCE)
  683.     TCHAR *szValue = new TCHAR[MAX_VALUE];
  684.     if(!szValue)
  685.         return E_FAIL;
  686. #else
  687.     TCHAR szValue[MAX_VALUE];
  688. #endif // _WIN32_WCE
  689.     SkipWhiteSpace();
  690.     if (FAILED(hr = NextToken(szValue)))
  691.     {
  692. WCE_INS    delete [] szValue;
  693.         return hr;
  694.     }
  695.     ULONG ulVal;
  696.  
  697.     switch (vt)
  698.     {
  699.     case VT_BSTR:
  700.         lRes = rkParent.SetValue(szValue, szValueName);
  701.         ATLTRACE2(atlTraceRegistrar, 2, _T("Setting Value %s at %s\n"), szValue, !szValueName ? _T("default") : szValueName);
  702.         break;
  703.     case VT_UI4:
  704.         VarUI4FromStr(T2OLE(szValue), 0, 0, &ulVal);
  705.         lRes = rkParent.SetValue(ulVal, szValueName);
  706.         ATLTRACE2(atlTraceRegistrar, 2, _T("Setting Value %d at %s\n"), ulVal, !szValueName ? _T("default") : szValueName);
  707.         break;
  708.     case VT_UI1:
  709.         {
  710.             int cbValue = lstrlen(szValue);
  711.             if (cbValue & 0x00000001)
  712.             {
  713.                 ATLTRACE2(atlTraceRegistrar, 0, _T("Binary Data does not fall on BYTE boundries\n"));
  714. WCE_INS            delete [] szValue;
  715.                 return E_FAIL;
  716.             }
  717.             int cbValDiv2 = cbValue/2;
  718.             BYTE* rgBinary = (BYTE*)_alloca(cbValDiv2*sizeof(BYTE));
  719.             memset(rgBinary, 0, cbValDiv2);
  720.             if (rgBinary == NULL)
  721.             {
  722. WCE_INS            delete [] szValue;
  723.                 return E_FAIL;
  724.             }
  725.             for (int irg = 0; irg < cbValue; irg++)
  726.                 rgBinary[(irg/2)] |= (ChToByte(szValue[irg])) << (4*(1 - (irg & 0x00000001)));
  727.             lRes = RegSetValueEx(rkParent, szValueName, 0, REG_BINARY, rgBinary, cbValDiv2);
  728.             break;
  729.         }
  730.     }
  731.  
  732.     if (ERROR_SUCCESS != lRes)
  733.     {
  734.         nIDRes = E_ATL_VALUE_SET_FAILED;
  735.         hr = HRESULT_FROM_WIN32(lRes);
  736.     }
  737.  
  738.     if (FAILED(hr = NextToken(szToken)))
  739.     {
  740. WCE_INS    delete [] szValue;
  741.         return hr;
  742.     }
  743.     WCE_INS    delete [] szValue;
  744.     return S_OK;
  745. }
  746.  
  747. inline BOOL CRegParser::CanForceRemoveKey(LPCTSTR szKey)
  748. {
  749.     for (int iNoDel = 0; iNoDel < cbNeverDelete; iNoDel++)
  750.         if (!lstrcmpi(szKey, rgszNeverDelete[iNoDel]))
  751.              return FALSE;                       // We cannot delete it
  752.  
  753.     return TRUE;
  754. }
  755.  
  756. inline BOOL CRegParser::HasSubKeys(HKEY hkey)
  757. {
  758.     DWORD       cbSubKeys = 0;
  759.  
  760.     if (FAILED(RegQueryInfoKey(hkey, NULL, NULL, NULL,
  761.                                &cbSubKeys, NULL, NULL,
  762.                                NULL, NULL, NULL, NULL, NULL)))
  763.     {
  764.         ATLTRACE2(atlTraceRegistrar, 0, _T("Should not be here!!\n"));
  765.         ATLASSERT(FALSE);
  766.         return FALSE;
  767.     }
  768.  
  769.     return cbSubKeys > 0;
  770. }
  771.  
  772. inline BOOL CRegParser::HasValues(HKEY hkey)
  773. {
  774.     DWORD       cbValues = 0;
  775.  
  776.     LONG lResult = RegQueryInfoKey(hkey, NULL, NULL, NULL,
  777.                                   NULL, NULL, NULL,
  778.                                   &cbValues, NULL, NULL, NULL, NULL);
  779.     if (ERROR_SUCCESS != lResult)
  780.     {
  781.         ATLTRACE2(atlTraceRegistrar, 0, _T("RegQueryInfoKey Failed "));
  782.         ATLASSERT(FALSE);
  783.         return FALSE;
  784.     }
  785.  
  786.     if (1 == cbValues)
  787.     {
  788.         DWORD cbMaxName= MAX_VALUE;
  789. #if defined(_WIN32_WCE)
  790.         TCHAR *szValueName = new TCHAR[MAX_VALUE];
  791.         if(!szValueName)
  792.             return FALSE;
  793. #else
  794.         TCHAR szValueName[MAX_VALUE];
  795. #endif // _WIN32_WCE
  796.         // Check to see if the Value is default or named
  797.         lResult = RegEnumValue(hkey, 0, szValueName, &cbMaxName, NULL, NULL, NULL, NULL);
  798.         if (ERROR_SUCCESS == lResult && (szValueName[0] != NULL))
  799.         {
  800. WCE_INS        delete [] szValueName;
  801.             return TRUE; // Named Value means we have a value
  802.         }
  803. WCE_INS    delete [] szValueName;
  804.         return FALSE;
  805.     }
  806.     return cbValues > 0; // More than 1 means we have a non-default value
  807. }
  808.  
  809. inline HRESULT CRegParser::SkipAssignment(LPTSTR szToken)
  810. {
  811.     HRESULT hr;
  812. #if defined(_WIN32_WCE)
  813.     TCHAR *szValue = new TCHAR[MAX_VALUE];
  814.     if(!szValue)
  815.         return E_FAIL;
  816. #else
  817.     TCHAR szValue[MAX_VALUE];
  818. #endif // _WIN32_WCE
  819.  
  820.     if (*szToken == chEquals)
  821.     {
  822.         if (FAILED(hr = NextToken(szToken)))
  823.         {
  824. WCE_INS        delete [] szValue;
  825.             return hr;
  826.         }
  827.         // Skip assignment
  828.         SkipWhiteSpace();
  829.         if (FAILED(hr = NextToken(szValue)))
  830.         {
  831. WCE_INS        delete [] szValue;
  832.             return hr;
  833.         }
  834.         if (FAILED(hr = NextToken(szToken)))
  835.         {
  836. WCE_INS        delete [] szValue;
  837.             return hr;
  838.         }
  839.     }
  840.     WCE_INS    delete [] szValue;
  841.     return S_OK;
  842. }
  843.  
  844. inline HRESULT CRegParser::PreProcessBuffer(LPTSTR lpszReg, LPTSTR* ppszReg)
  845. {
  846.     USES_CONVERSION;
  847.     ATLASSERT(lpszReg != NULL);
  848.     ATLASSERT(ppszReg != NULL);
  849.     *ppszReg = NULL;
  850.     int nSize = lstrlen(lpszReg)*2;
  851.     CParseBuffer pb(nSize);
  852.     if (pb.p == NULL)
  853.         return E_OUTOFMEMORY;
  854.     m_pchCur = lpszReg;
  855.     HRESULT hr = S_OK;
  856.  
  857.     while (*m_pchCur != NULL) // look for end
  858.     {
  859.         if (*m_pchCur == _T('%'))
  860.         {
  861.             m_pchCur = CharNext(m_pchCur);
  862.             if (*m_pchCur == _T('%'))
  863.                 pb.AddChar(m_pchCur);
  864.             else
  865.             {
  866.                 LPTSTR lpszNext = StrChr(m_pchCur, _T('%'));
  867.                 if (lpszNext == NULL)
  868.                 {
  869.                     ATLTRACE2(atlTraceRegistrar, 0, _T("Error no closing % found\n"));
  870.                     hr = GenerateError(E_ATL_UNEXPECTED_EOS);
  871.                     break;
  872.                 }
  873.                 int nLength = lpszNext - m_pchCur;
  874.                 if (nLength > 31)
  875.                 {
  876.                     hr = E_FAIL;
  877.                     break;
  878.                 }
  879.                 TCHAR buf[32];
  880. #if defined(_WIN32_WCE)
  881.                 _tcsncpy(buf, m_pchCur, nLength);
  882.                 buf[nLength] = 0;
  883. #else // _WIN32_WCE
  884.                 lstrcpyn(buf, m_pchCur, nLength+1);
  885. #endif // _WIN32_WCE
  886.                 LPCOLESTR lpszVar = m_pRegObj->StrFromMap(buf);
  887.                 if (lpszVar == NULL)
  888.                 {
  889.                     hr = GenerateError(E_ATL_NOT_IN_MAP);
  890.                     break;
  891.                 }
  892.                 pb.AddString(lpszVar);
  893.                 while (m_pchCur != lpszNext)
  894.                     m_pchCur = CharNext(m_pchCur);
  895.             }
  896.         }
  897.         else
  898.             pb.AddChar(m_pchCur);
  899.         m_pchCur = CharNext(m_pchCur);
  900.     }
  901.     pb.AddChar(m_pchCur);
  902.     if (SUCCEEDED(hr))
  903.         *ppszReg = pb.Detach();
  904.     return hr;
  905. }
  906.  
  907. inline HRESULT CRegParser::RegisterBuffer(LPTSTR szBuffer, BOOL bRegister)
  908. {
  909. #if defined(_WIN32_WCE)
  910.     TCHAR   *szToken = new TCHAR[MAX_VALUE];
  911.     if(!szToken)
  912.         return E_FAIL;
  913. #else
  914.     TCHAR szToken[MAX_VALUE];
  915. #endif // _WIN32_WCE
  916.     HRESULT hr = S_OK;
  917.  
  918.     LPTSTR szReg;
  919.     hr = PreProcessBuffer(szBuffer, &szReg);
  920.     if (FAILED(hr))
  921.     {
  922. WCE_INS    delete [] szToken;
  923.         return hr;
  924.     }
  925.  
  926. #ifdef _DEBUG
  927.     OutputDebugString(szReg); //would call ATLTRACE but szReg is > 512 bytes
  928.     OutputDebugString(_T("\n"));
  929. #endif //_DEBUG
  930.  
  931.     m_pchCur = szReg;
  932.  
  933.     // Preprocess szReg
  934.  
  935.     while (NULL != *m_pchCur)
  936.     {
  937.         if (FAILED(hr = NextToken(szToken)))
  938.             break;
  939.         HKEY hkBase;
  940.         if ((hkBase = HKeyFromString(szToken)) == NULL)
  941.         {
  942.             ATLTRACE2(atlTraceRegistrar, 0, _T("HKeyFromString failed on %s\n"), szToken);
  943.             hr = GenerateError(E_ATL_BAD_HKEY);
  944.             break;
  945.         }
  946.  
  947.         if (FAILED(hr = NextToken(szToken)))
  948.             break;
  949.  
  950.         if (chLeftBracket != *szToken)
  951.         {
  952.             ATLTRACE2(atlTraceRegistrar, 0, _T("Syntax error, expecting a {, found a %s\n"), szToken);
  953.             hr = GenerateError(E_ATL_MISSING_OPENKEY_TOKEN);
  954.             break;
  955.         }
  956.         if (bRegister)
  957.         {
  958.             LPTSTR szRegAtRegister = m_pchCur;
  959.             hr = RegisterSubkeys(szToken, hkBase, bRegister);
  960.             if (FAILED(hr))
  961.             {
  962.                 ATLTRACE2(atlTraceRegistrar, 0, _T("Failed to register, cleaning up!\n"));
  963.                 m_pchCur = szRegAtRegister;
  964.                 RegisterSubkeys(szToken, hkBase, FALSE);
  965.                 break;
  966.             }
  967.         }
  968.         else
  969.         {
  970.             if (FAILED(hr = RegisterSubkeys(szToken, hkBase, bRegister)))
  971.                 break;
  972.         }
  973.  
  974.         SkipWhiteSpace();
  975.     }
  976.     CoTaskMemFree(szReg);
  977.  
  978.     WCE_INS    delete [] szToken;
  979.     return hr;
  980. }
  981.  
  982. inline HRESULT CRegParser::RegisterSubkeys(LPTSTR szToken, HKEY hkParent, BOOL bRegister, BOOL bRecover)
  983. {
  984.     CRegKey keyCur;
  985.     LONG    lRes;
  986.     LPTSTR  szKey = NULL;
  987.     BOOL    bDelete = TRUE;
  988.     BOOL    bInRecovery = bRecover;
  989.     HRESULT hr = S_OK;
  990.  
  991.     ATLTRACE2(atlTraceRegistrar, 2, _T("Num Els = %d\n"), cbNeverDelete);
  992.     if (FAILED(hr = NextToken(szToken)))
  993.         return hr;
  994.  
  995.  
  996.     while (*szToken != chRightBracket) // Continue till we see a }
  997.     {
  998.         BOOL bTokenDelete = !lstrcmpi(szToken, szDelete);
  999.  
  1000.         if (!lstrcmpi(szToken, szForceRemove) || bTokenDelete)
  1001.         {
  1002.             if (FAILED(hr = NextToken(szToken)))
  1003.                 break;
  1004.  
  1005.             if (bRegister)
  1006.             {
  1007.                 CRegKey rkForceRemove;
  1008.  
  1009.                 if (StrChr(szToken, chDirSep) != NULL)
  1010.                     return GenerateError(E_ATL_COMPOUND_KEY);
  1011.  
  1012.                 if (CanForceRemoveKey(szToken))
  1013.                 {
  1014.                     rkForceRemove.Attach(hkParent);
  1015.                     rkForceRemove.RecurseDeleteKey(szToken);
  1016.                     rkForceRemove.Detach();
  1017.                 }
  1018.                 if (bTokenDelete)
  1019.                 {
  1020.                     if (FAILED(hr = NextToken(szToken)))
  1021.                         break;
  1022.                     if (FAILED(hr = SkipAssignment(szToken)))
  1023.                         break;
  1024.                     goto EndCheck;
  1025.                 }
  1026.             }
  1027.  
  1028.         }
  1029.  
  1030.         if (!lstrcmpi(szToken, szNoRemove))
  1031.         {
  1032.             bDelete = FALSE;    // set even for register
  1033.             if (FAILED(hr = NextToken(szToken)))
  1034.                 break;
  1035.         }
  1036.  
  1037.         if (!lstrcmpi(szToken, szValToken)) // need to add a value to hkParent
  1038.         {
  1039. #if defined(_WIN32_WCE)
  1040.             TCHAR  *szValueName = new TCHAR[_MAX_PATH];
  1041. #else
  1042.             TCHAR  szValueName[_MAX_PATH];
  1043. #endif
  1044.  
  1045.             if (FAILED(hr = NextToken(szValueName)))
  1046.                 break;
  1047.             if (FAILED(hr = NextToken(szToken)))
  1048.                 break;
  1049.  
  1050.  
  1051.             if (*szToken != chEquals)
  1052.             {
  1053. WCE_INS                delete [] szValueName;
  1054.                 return GenerateError(E_ATL_EXPECTING_EQUAL);
  1055.             }
  1056.  
  1057.             if (bRegister)
  1058.             {
  1059.                 CRegKey rk;
  1060.  
  1061.                 rk.Attach(hkParent);
  1062.                 hr = AddValue(rk, szValueName, szToken);
  1063.                 rk.Detach();
  1064.  
  1065.                 if (FAILED(hr))
  1066.                 {
  1067. WCE_INS                    delete [] szValueName;
  1068.                     return hr;
  1069.                 }
  1070.  
  1071. WCE_INS                delete [] szValueName;
  1072.                 goto EndCheck;
  1073.             }
  1074.             else
  1075.             {
  1076.                 if (!bRecover)
  1077.                 {
  1078.                     ATLTRACE2(atlTraceRegistrar, 1, _T("Deleting %s\n"), szValueName);
  1079.                     CRegKey rkParent;
  1080.                     rkParent.Attach(hkParent);
  1081.                     rkParent.DeleteValue(szValueName);
  1082.                     rkParent.Detach();
  1083.                 }
  1084.  
  1085.                 if (FAILED(hr = SkipAssignment(szToken)))
  1086.                     break;
  1087.                 continue;  // can never have a subkey
  1088.             }
  1089.         }
  1090.  
  1091.         if (StrChr(szToken, chDirSep) != NULL)
  1092.             return GenerateError(E_ATL_COMPOUND_KEY);
  1093.  
  1094.         if (bRegister)
  1095.         {
  1096.             lRes = keyCur.Open(hkParent, szToken, KEY_ALL_ACCESS);
  1097.             if (ERROR_SUCCESS != lRes)
  1098.             {
  1099.                 // Failed all access try read only
  1100.                 lRes = keyCur.Open(hkParent, szToken, KEY_READ);
  1101.                 if (ERROR_SUCCESS != lRes)
  1102.                 {
  1103.                     // Finally try creating it
  1104.                     ATLTRACE2(atlTraceRegistrar, 2, _T("Creating key %s\n"), szToken);
  1105.                     lRes = keyCur.Create(hkParent, szToken);
  1106.                     if (ERROR_SUCCESS != lRes)
  1107.                         return GenerateError(E_ATL_CREATE_KEY_FAILED);
  1108.                 }
  1109.             }
  1110.  
  1111.             if (FAILED(hr = NextToken(szToken)))
  1112.                 break;
  1113.  
  1114.  
  1115.             if (*szToken == chEquals)
  1116.             {
  1117.                 if (FAILED(hr = AddValue(keyCur, NULL, szToken))) // NULL == default
  1118.                     break;
  1119.             }
  1120.         }
  1121.         else
  1122.         {
  1123.             if (!bRecover && keyCur.Open(hkParent, szToken, KEY_READ) != ERROR_SUCCESS)
  1124.                 bRecover = TRUE;
  1125.  
  1126.             // TRACE out Key open status and if in recovery mode
  1127. #ifdef _DEBUG
  1128.             if (!bRecover)
  1129.                 ATLTRACE2(atlTraceRegistrar, 1, _T("Opened Key %s\n"), szToken);
  1130.             else
  1131.                 ATLTRACE2(atlTraceRegistrar, 0, _T("Ignoring Open key on %s : In Recovery mode\n"), szToken);
  1132. #endif //_DEBUG
  1133.  
  1134.             // Remember Subkey
  1135.             if (szKey == NULL)
  1136.                 szKey = (LPTSTR)_alloca(sizeof(TCHAR)*_MAX_PATH);
  1137. #if defined(_WIN32_WCE)
  1138.             int nKeyLen = _tcslen(szToken);
  1139.             _tcsncpy(szKey, szToken, nKeyLen);
  1140.             szKey[nKeyLen] = '\0';
  1141. #else // _WIN32_WCE
  1142.             lstrcpyn(szKey, szToken, _MAX_PATH);
  1143. #endif // _WIN32_WCE
  1144.  
  1145.             // If in recovery mode
  1146.  
  1147.             if (bRecover || HasSubKeys(keyCur) || HasValues(keyCur))
  1148.             {
  1149.                 if (FAILED(hr = NextToken(szToken)))
  1150.                     break;
  1151.                 if (FAILED(hr = SkipAssignment(szToken)))
  1152.                     break;
  1153.  
  1154.  
  1155.                 if (*szToken == chLeftBracket)
  1156.                 {
  1157.                     if (FAILED(hr = RegisterSubkeys(szToken, keyCur.m_hKey, bRegister, bRecover)))
  1158.                         break;
  1159.                     if (bRecover) // Turn off recovery if we are done
  1160.                     {
  1161.                         bRecover = bInRecovery;
  1162.                         ATLTRACE2(atlTraceRegistrar, 0, _T("Ending Recovery Mode\n"));
  1163.                         if (FAILED(hr = NextToken(szToken)))
  1164.                             break;
  1165.                         if (FAILED(hr = SkipAssignment(szToken)))
  1166.                             break;
  1167.                         continue;
  1168.                     }
  1169.                 }
  1170.  
  1171.                 if (!bRecover && HasSubKeys(keyCur))
  1172.                 {
  1173.                     // See if the KEY is in the NeverDelete list and if so, don't
  1174.                     if (CanForceRemoveKey(szKey))
  1175.                     {
  1176.                         ATLTRACE2(atlTraceRegistrar, 0, _T("Deleting non-empty subkey %s by force\n"), szKey);
  1177.                         keyCur.RecurseDeleteKey(szKey);
  1178.                     }
  1179.                     if (FAILED(hr = NextToken(szToken)))
  1180.                         break;
  1181.                     continue;
  1182.                 }
  1183.  
  1184.                 if (bRecover)
  1185.                     continue;
  1186.             }
  1187.  
  1188.             if (!bRecover && keyCur.Close() != ERROR_SUCCESS)
  1189.                return GenerateError(E_ATL_CLOSE_KEY_FAILED);
  1190.  
  1191.             if (!bRecover && bDelete)
  1192.             {
  1193.                 ATLTRACE2(atlTraceRegistrar, 0, _T("Deleting Key %s\n"), szKey);
  1194.                 CRegKey rkParent;
  1195.                 rkParent.Attach(hkParent);
  1196.                 rkParent.DeleteSubKey(szKey);
  1197.                 rkParent.Detach();
  1198.             }
  1199.  
  1200.             if (FAILED(hr = NextToken(szToken)))
  1201.                 break;
  1202.             if (FAILED(hr = SkipAssignment(szToken)))
  1203.                 break;
  1204.         }
  1205.  
  1206. EndCheck:
  1207.  
  1208.         if (bRegister)
  1209.         {
  1210.             if (*szToken == chLeftBracket && lstrlen(szToken) == 1)
  1211.             {
  1212.                 if (FAILED(hr = RegisterSubkeys(szToken, keyCur.m_hKey, bRegister, FALSE)))
  1213.                     break;
  1214.                 if (FAILED(hr = NextToken(szToken)))
  1215.                     break;
  1216.             }
  1217.         }
  1218.     }
  1219.  
  1220.     return hr;
  1221. }
  1222.  
  1223. }; //namespace ATL
  1224.  
  1225. #endif //__STATREG_H
  1226.