Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1282 lines
30 KiB

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