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.

1198 lines
28 KiB

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