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