Leaked source code of windows server 2003
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.

1170 lines
29 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(LPCTSTR 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 LPCTSTR StrChr(LPCTSTR 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. // NOTE: the original atl source code used CComObjectThreadModel, but if you're linking together
  264. // multiple objects with different threading models then this breaks because the different models see different
  265. // initialization sizes for the ctor. since registration doesn't happen that often, we're just going to take
  266. // the microscopic perf hit of always assuming multithread and really grabbing a real critsec. the alternative
  267. // would be to templatize all the CRegXXX classes with a threading model parameter. but, its not worth doing that much work
  268. // for such a low use frequency component.
  269. CComMultiThreadModel::AutoCriticalSection m_csMap;
  270. };
  271. inline HRESULT STDMETHODCALLTYPE CRegObject::AddReplacement(LPCOLESTR lpszKey, LPCOLESTR lpszItem)
  272. {
  273. m_csMap.Lock();
  274. HRESULT hr = m_RepMap.Add(lpszKey, lpszItem);
  275. m_csMap.Unlock();
  276. return hr;
  277. }
  278. inline HRESULT CRegObject::RegisterFromResource(LPCOLESTR bstrFileName, LPCTSTR szID,
  279. LPCTSTR szType, BOOL bRegister)
  280. {
  281. USES_CONVERSION;
  282. HRESULT hr;
  283. CRegParser parser(this);
  284. HINSTANCE hInstResDll;
  285. HRSRC hrscReg;
  286. HGLOBAL hReg;
  287. DWORD dwSize;
  288. LPSTR szRegA;
  289. LPTSTR szReg;
  290. hInstResDll = LoadLibraryEx(OLE2CT(bstrFileName), NULL, LOAD_LIBRARY_AS_DATAFILE);
  291. if (NULL == hInstResDll)
  292. {
  293. ATLTRACE2(atlTraceRegistrar, 0, _T("Failed to LoadLibrary on %s\n"), OLE2CT(bstrFileName));
  294. hr = HRESULT_FROM_WIN32(GetLastError());
  295. goto ReturnHR;
  296. }
  297. hrscReg = FindResource((HMODULE)hInstResDll, szID, szType);
  298. if (NULL == hrscReg)
  299. {
  300. if (DWORD_PTR(szID) <= 0xffff)
  301. ATLTRACE2(atlTraceRegistrar, 0, _T("Failed to FindResource on ID:%d TYPE:%s\n"),
  302. (DWORD)(DWORD_PTR)szID, szType);
  303. else
  304. ATLTRACE2(atlTraceRegistrar, 0, _T("Failed to FindResource on ID:%s TYPE:%s\n"),
  305. szID, szType);
  306. hr = HRESULT_FROM_WIN32(GetLastError());
  307. goto ReturnHR;
  308. }
  309. hReg = LoadResource((HMODULE)hInstResDll, hrscReg);
  310. if (NULL == hReg)
  311. {
  312. ATLTRACE2(atlTraceRegistrar, 0, _T("Failed to LoadResource \n"));
  313. hr = HRESULT_FROM_WIN32(GetLastError());
  314. goto ReturnHR;
  315. }
  316. dwSize = SizeofResource((HMODULE)hInstResDll, hrscReg);
  317. szRegA = (LPSTR)hReg;
  318. if (szRegA[dwSize] != NULL)
  319. {
  320. szRegA = (LPSTR)_alloca(dwSize+1);
  321. memcpy(szRegA, (void*)hReg, dwSize+1);
  322. szRegA[dwSize] = NULL;
  323. }
  324. szReg = A2T(szRegA);
  325. hr = parser.RegisterBuffer(szReg, bRegister);
  326. ReturnHR:
  327. if (NULL != hInstResDll)
  328. FreeLibrary((HMODULE)hInstResDll);
  329. return hr;
  330. }
  331. inline HRESULT STDMETHODCALLTYPE CRegObject::ResourceRegister(LPCOLESTR szFileName, UINT nID, LPCOLESTR szType)
  332. {
  333. USES_CONVERSION;
  334. return RegisterFromResource(szFileName, MAKEINTRESOURCE(nID), OLE2CT(szType), TRUE);
  335. }
  336. inline HRESULT STDMETHODCALLTYPE CRegObject::ResourceRegisterSz(LPCOLESTR szFileName, LPCOLESTR szID, LPCOLESTR szType)
  337. {
  338. USES_CONVERSION;
  339. if (szID == NULL || szType == NULL)
  340. return E_INVALIDARG;
  341. return RegisterFromResource(szFileName, OLE2CT(szID), OLE2CT(szType), TRUE);
  342. }
  343. inline HRESULT STDMETHODCALLTYPE CRegObject::ResourceUnregister(LPCOLESTR szFileName, UINT nID, LPCOLESTR szType)
  344. {
  345. USES_CONVERSION;
  346. return RegisterFromResource(szFileName, MAKEINTRESOURCE(nID), OLE2CT(szType), FALSE);
  347. }
  348. inline HRESULT STDMETHODCALLTYPE CRegObject::ResourceUnregisterSz(LPCOLESTR szFileName, LPCOLESTR szID, LPCOLESTR szType)
  349. {
  350. USES_CONVERSION;
  351. if (szID == NULL || szType == NULL)
  352. return E_INVALIDARG;
  353. return RegisterFromResource(szFileName, OLE2CT(szID), OLE2CT(szType), FALSE);
  354. }
  355. inline HRESULT CRegObject::RegisterWithString(LPCOLESTR bstrData, BOOL bRegister)
  356. {
  357. USES_CONVERSION;
  358. CRegParser parser(this);
  359. LPCTSTR szReg = OLE2CT(bstrData);
  360. HRESULT hr = parser.RegisterBuffer((LPTSTR)szReg, bRegister);
  361. return hr;
  362. }
  363. inline HRESULT CRegObject::ClearReplacements()
  364. {
  365. m_csMap.Lock();
  366. HRESULT hr = m_RepMap.ClearReplacements();
  367. m_csMap.Unlock();
  368. return hr;
  369. }
  370. inline LPCOLESTR CRegObject::StrFromMap(LPTSTR lpszKey)
  371. {
  372. m_csMap.Lock();
  373. LPCOLESTR lpsz = m_RepMap.Find(lpszKey);
  374. if (lpsz == NULL) // not found!!
  375. ATLTRACE2(atlTraceRegistrar, 0, _T("Map Entry not found\n"));
  376. m_csMap.Unlock();
  377. return lpsz;
  378. }
  379. inline HRESULT CRegObject::CommonFileRegister(LPCOLESTR bstrFileName, BOOL bRegister)
  380. {
  381. USES_CONVERSION;
  382. CRegParser parser(this);
  383. HANDLE hFile = CreateFile(OLE2CT(bstrFileName), GENERIC_READ, 0, NULL,
  384. OPEN_EXISTING,
  385. FILE_ATTRIBUTE_READONLY,
  386. NULL);
  387. if (INVALID_HANDLE_VALUE == hFile)
  388. {
  389. ATLTRACE2(atlTraceRegistrar, 0, _T("Failed to CreateFile on %s\n"), OLE2CT(bstrFileName));
  390. return HRESULT_FROM_WIN32(GetLastError());
  391. }
  392. HRESULT hRes = S_OK;
  393. DWORD cbRead;
  394. DWORD cbFile = GetFileSize(hFile, NULL); // No HiOrder DWORD required
  395. char* szReg = (char*)_alloca(cbFile + 1);
  396. if (ReadFile(hFile, szReg, cbFile, &cbRead, NULL) == 0)
  397. {
  398. ATLTRACE2(atlTraceRegistrar, 0, "Read Failed on file%s\n", OLE2CT(bstrFileName));
  399. hRes = HRESULT_FROM_WIN32(GetLastError());
  400. }
  401. if (SUCCEEDED(hRes))
  402. {
  403. szReg[cbRead] = NULL;
  404. LPTSTR szConverted = A2T(szReg);
  405. hRes = parser.RegisterBuffer(szConverted, bRegister);
  406. }
  407. CloseHandle(hFile);
  408. return hRes;
  409. }
  410. __declspec(selectany) LPCTSTR CRegParser::rgszNeverDelete[] = //Component Catagories
  411. {
  412. _T("CLSID"), _T("TYPELIB")
  413. };
  414. __declspec(selectany) const int CRegParser::cbNeverDelete = sizeof(rgszNeverDelete) / sizeof(LPCTSTR*);
  415. __declspec(selectany) const int CRegParser::MAX_VALUE=4096;
  416. __declspec(selectany) const int CRegParser::MAX_TYPE=MAX_VALUE;
  417. inline BOOL CRegParser::VTFromRegType(LPCTSTR szValueType, VARTYPE& vt)
  418. {
  419. struct typemap
  420. {
  421. LPCTSTR lpsz;
  422. VARTYPE vt;
  423. };
  424. static const typemap map[] = {
  425. {szStringVal, VT_BSTR},
  426. {szDwordVal, VT_UI4},
  427. {szBinaryVal, VT_UI1}
  428. };
  429. for (int i=0;i<sizeof(map)/sizeof(typemap);i++)
  430. {
  431. if (!lstrcmpi(szValueType, map[i].lpsz))
  432. {
  433. vt = map[i].vt;
  434. return TRUE;
  435. }
  436. }
  437. return FALSE;
  438. }
  439. inline BYTE CRegParser::ChToByte(const TCHAR ch)
  440. {
  441. switch (ch)
  442. {
  443. case '0':
  444. case '1':
  445. case '2':
  446. case '3':
  447. case '4':
  448. case '5':
  449. case '6':
  450. case '7':
  451. case '8':
  452. case '9':
  453. return (BYTE) (ch - '0');
  454. case 'A':
  455. case 'B':
  456. case 'C':
  457. case 'D':
  458. case 'E':
  459. case 'F':
  460. return (BYTE) (10 + (ch - 'A'));
  461. case 'a':
  462. case 'b':
  463. case 'c':
  464. case 'd':
  465. case 'e':
  466. case 'f':
  467. return (BYTE) (10 + (ch - 'a'));
  468. default:
  469. ATLASSERT(FALSE);
  470. ATLTRACE2(atlTraceRegistrar, 0, _T("Bogus value %c passed as binary Hex value\n"), ch);
  471. return 0;
  472. }
  473. }
  474. inline HKEY CRegParser::HKeyFromString(LPTSTR szToken)
  475. {
  476. struct keymap
  477. {
  478. LPCTSTR lpsz;
  479. HKEY hkey;
  480. };
  481. static const keymap map[] = {
  482. {_T("HKCR"), HKEY_CLASSES_ROOT},
  483. {_T("HKCU"), HKEY_CURRENT_USER},
  484. {_T("HKLM"), HKEY_LOCAL_MACHINE},
  485. {_T("HKU"), HKEY_USERS},
  486. {_T("HKPD"), HKEY_PERFORMANCE_DATA},
  487. {_T("HKDD"), HKEY_DYN_DATA},
  488. {_T("HKCC"), HKEY_CURRENT_CONFIG},
  489. {_T("HKEY_CLASSES_ROOT"), HKEY_CLASSES_ROOT},
  490. {_T("HKEY_CURRENT_USER"), HKEY_CURRENT_USER},
  491. {_T("HKEY_LOCAL_MACHINE"), HKEY_LOCAL_MACHINE},
  492. {_T("HKEY_USERS"), HKEY_USERS},
  493. {_T("HKEY_PERFORMANCE_DATA"), HKEY_PERFORMANCE_DATA},
  494. {_T("HKEY_DYN_DATA"), HKEY_DYN_DATA},
  495. {_T("HKEY_CURRENT_CONFIG"), HKEY_CURRENT_CONFIG}
  496. };
  497. for (int i=0;i<sizeof(map)/sizeof(keymap);i++)
  498. {
  499. if (!lstrcmpi(szToken, map[i].lpsz))
  500. return map[i].hkey;
  501. }
  502. return NULL;
  503. }
  504. inline LPCTSTR CRegParser::StrChr(LPCTSTR lpsz, TCHAR ch)
  505. {
  506. LPCTSTR p = NULL;
  507. while (*lpsz)
  508. {
  509. if (*lpsz == ch)
  510. {
  511. p = lpsz;
  512. break;
  513. }
  514. lpsz = CharNext(lpsz);
  515. }
  516. return p;
  517. }
  518. inline CRegParser::CRegParser(CRegObject* pRegObj)
  519. {
  520. m_pRegObj = pRegObj;
  521. m_pchCur = NULL;
  522. }
  523. inline BOOL CRegParser::IsSpace(TCHAR ch)
  524. {
  525. switch (ch)
  526. {
  527. case _T(' '):
  528. case _T('\t'):
  529. case _T('\r'):
  530. case _T('\n'):
  531. return TRUE;
  532. }
  533. return FALSE;
  534. }
  535. inline void CRegParser::SkipWhiteSpace()
  536. {
  537. while(IsSpace(*m_pchCur))
  538. m_pchCur = CharNext(m_pchCur);
  539. }
  540. inline HRESULT CRegParser::NextToken(LPTSTR szToken)
  541. {
  542. USES_CONVERSION;
  543. SkipWhiteSpace();
  544. // NextToken cannot be called at EOS
  545. if (NULL == *m_pchCur)
  546. return GenerateError(E_ATL_UNEXPECTED_EOS);
  547. // handle quoted value / key
  548. if (chQuote == *m_pchCur)
  549. {
  550. LPCTSTR szOrig = szToken;
  551. m_pchCur = CharNext(m_pchCur);
  552. while (NULL != *m_pchCur && !EndOfVar())
  553. {
  554. if (chQuote == *m_pchCur) // If it is a quote that means we must skip it
  555. m_pchCur = CharNext(m_pchCur);
  556. LPTSTR pchPrev = m_pchCur;
  557. m_pchCur = CharNext(m_pchCur);
  558. if (szToken + sizeof(WORD) >= MAX_VALUE + szOrig)
  559. return GenerateError(E_ATL_VALUE_TOO_LARGE);
  560. for (int i = 0; pchPrev+i < m_pchCur; i++, szToken++)
  561. *szToken = *(pchPrev+i);
  562. }
  563. if (NULL == *m_pchCur)
  564. {
  565. ATLTRACE2(atlTraceRegistrar, 0, _T("NextToken : Unexpected End of File\n"));
  566. return GenerateError(E_ATL_UNEXPECTED_EOS);
  567. }
  568. *szToken = NULL;
  569. m_pchCur = CharNext(m_pchCur);
  570. }
  571. else
  572. { // Handle non-quoted ie parse up till first "White Space"
  573. while (NULL != *m_pchCur && !IsSpace(*m_pchCur))
  574. {
  575. LPTSTR pchPrev = m_pchCur;
  576. m_pchCur = CharNext(m_pchCur);
  577. for (int i = 0; pchPrev+i < m_pchCur; i++, szToken++)
  578. *szToken = *(pchPrev+i);
  579. }
  580. *szToken = NULL;
  581. }
  582. return S_OK;
  583. }
  584. inline HRESULT CRegParser::AddValue(CRegKey& rkParent,LPCTSTR szValueName, LPTSTR szToken)
  585. {
  586. USES_CONVERSION;
  587. HRESULT hr;
  588. TCHAR szTypeToken[MAX_TYPE];
  589. VARTYPE vt;
  590. LONG lRes = ERROR_SUCCESS;
  591. UINT nIDRes = 0;
  592. if (FAILED(hr = NextToken(szTypeToken)))
  593. return hr;
  594. if (!VTFromRegType(szTypeToken, vt))
  595. {
  596. ATLTRACE2(atlTraceRegistrar, 0, _T("%s Type not supported\n"), szTypeToken);
  597. return GenerateError(E_ATL_TYPE_NOT_SUPPORTED);
  598. }
  599. TCHAR szValue[MAX_VALUE];
  600. SkipWhiteSpace();
  601. if (FAILED(hr = NextToken(szValue)))
  602. return hr;
  603. ULONG ulVal;
  604. switch (vt)
  605. {
  606. case VT_BSTR:
  607. lRes = rkParent.SetValue(szValue, szValueName);
  608. ATLTRACE2(atlTraceRegistrar, 2, _T("Setting Value %s at %s\n"), szValue, !szValueName ? _T("default") : szValueName);
  609. break;
  610. case VT_UI4:
  611. #ifdef _WIN64
  612. ATLASSERT(FALSE);
  613. ulVal = 0;
  614. #pragma message( "Still need VarUI4FromStr()." )
  615. #else
  616. VarUI4FromStr(T2OLE(szValue), 0, 0, &ulVal);
  617. #endif
  618. lRes = rkParent.SetValue(ulVal, szValueName);
  619. ATLTRACE2(atlTraceRegistrar, 2, _T("Setting Value %d at %s\n"), ulVal, !szValueName ? _T("default") : szValueName);
  620. break;
  621. case VT_UI1:
  622. {
  623. int cbValue = lstrlen(szValue);
  624. if (cbValue & 0x00000001)
  625. {
  626. ATLTRACE2(atlTraceRegistrar, 0, _T("Binary Data does not fall on BYTE boundries\n"));
  627. return E_FAIL;
  628. }
  629. int cbValDiv2 = cbValue/2;
  630. BYTE* rgBinary = (BYTE*)_alloca(cbValDiv2*sizeof(BYTE));
  631. memset(rgBinary, 0, cbValDiv2);
  632. if (rgBinary == NULL)
  633. return E_FAIL;
  634. for (int irg = 0; irg < cbValue; irg++)
  635. rgBinary[(irg/2)] |= (ChToByte(szValue[irg])) << (4*(1 - (irg & 0x00000001)));
  636. lRes = RegSetValueEx(rkParent, szValueName, 0, REG_BINARY, rgBinary, cbValDiv2);
  637. break;
  638. }
  639. }
  640. if (ERROR_SUCCESS != lRes)
  641. {
  642. nIDRes = E_ATL_VALUE_SET_FAILED;
  643. hr = HRESULT_FROM_WIN32(lRes);
  644. }
  645. if (FAILED(hr = NextToken(szToken)))
  646. return hr;
  647. return S_OK;
  648. }
  649. inline BOOL CRegParser::CanForceRemoveKey(LPCTSTR szKey)
  650. {
  651. for (int iNoDel = 0; iNoDel < cbNeverDelete; iNoDel++)
  652. if (!lstrcmpi(szKey, rgszNeverDelete[iNoDel]))
  653. return FALSE; // We cannot delete it
  654. return TRUE;
  655. }
  656. inline BOOL CRegParser::HasSubKeys(HKEY hkey)
  657. {
  658. DWORD cbSubKeys = 0;
  659. if (FAILED(RegQueryInfoKey(hkey, NULL, NULL, NULL,
  660. &cbSubKeys, NULL, NULL,
  661. NULL, NULL, NULL, NULL, NULL)))
  662. {
  663. ATLTRACE2(atlTraceRegistrar, 0, _T("Should not be here!!\n"));
  664. ATLASSERT(FALSE);
  665. return FALSE;
  666. }
  667. return cbSubKeys > 0;
  668. }
  669. inline BOOL CRegParser::HasValues(HKEY hkey)
  670. {
  671. DWORD cbValues = 0;
  672. LONG lResult = RegQueryInfoKey(hkey, NULL, NULL, NULL,
  673. NULL, NULL, NULL,
  674. &cbValues, NULL, NULL, NULL, NULL);
  675. if (ERROR_SUCCESS != lResult)
  676. {
  677. ATLTRACE2(atlTraceRegistrar, 0, _T("RegQueryInfoKey Failed "));
  678. ATLASSERT(FALSE);
  679. return FALSE;
  680. }
  681. if (1 == cbValues)
  682. {
  683. DWORD cbMaxName= MAX_VALUE;
  684. TCHAR szValueName[MAX_VALUE];
  685. // Check to see if the Value is default or named
  686. lResult = RegEnumValue(hkey, 0, szValueName, &cbMaxName, NULL, NULL, NULL, NULL);
  687. if (ERROR_SUCCESS == lResult && (szValueName[0] != NULL))
  688. return TRUE; // Named Value means we have a value
  689. return FALSE;
  690. }
  691. return cbValues > 0; // More than 1 means we have a non-default value
  692. }
  693. inline HRESULT CRegParser::SkipAssignment(LPTSTR szToken)
  694. {
  695. HRESULT hr;
  696. TCHAR szValue[MAX_VALUE];
  697. if (*szToken == chEquals)
  698. {
  699. if (FAILED(hr = NextToken(szToken)))
  700. return hr;
  701. // Skip assignment
  702. SkipWhiteSpace();
  703. if (FAILED(hr = NextToken(szValue)))
  704. return hr;
  705. if (FAILED(hr = NextToken(szToken)))
  706. return hr;
  707. }
  708. return S_OK;
  709. }
  710. inline HRESULT CRegParser::PreProcessBuffer(LPCTSTR lpszReg, LPTSTR* ppszReg)
  711. {
  712. USES_CONVERSION;
  713. ATLASSERT(lpszReg != NULL);
  714. ATLASSERT(ppszReg != NULL);
  715. *ppszReg = NULL;
  716. int nSize = lstrlen(lpszReg)*2;
  717. CParseBuffer pb(nSize);
  718. if (pb.p == NULL)
  719. return E_OUTOFMEMORY;
  720. LPCTSTR pchCur = lpszReg;
  721. HRESULT hr = S_OK;
  722. while (*pchCur != NULL) // look for end
  723. {
  724. if (*pchCur == _T('%'))
  725. {
  726. pchCur = CharNext(pchCur);
  727. if (*pchCur == _T('%'))
  728. pb.AddChar(pchCur);
  729. else
  730. {
  731. LPCTSTR lpszNext = StrChr(pchCur, _T('%'));
  732. if (lpszNext == NULL)
  733. {
  734. ATLTRACE2(atlTraceRegistrar, 0, _T("Error no closing % found\n"));
  735. hr = GenerateError(E_ATL_UNEXPECTED_EOS);
  736. break;
  737. }
  738. int nLength = int(lpszNext - pchCur);
  739. if (nLength > 31)
  740. {
  741. hr = E_FAIL;
  742. break;
  743. }
  744. TCHAR buf[32];
  745. lstrcpyn(buf, pchCur, nLength+1);
  746. LPCOLESTR lpszVar = m_pRegObj->StrFromMap(buf);
  747. if (lpszVar == NULL)
  748. {
  749. hr = GenerateError(E_ATL_NOT_IN_MAP);
  750. break;
  751. }
  752. pb.AddString(lpszVar);
  753. while (pchCur != lpszNext)
  754. pchCur = CharNext(pchCur);
  755. }
  756. }
  757. else
  758. pb.AddChar(pchCur);
  759. pchCur = CharNext(pchCur);
  760. }
  761. pb.AddChar(pchCur);
  762. if (SUCCEEDED(hr))
  763. *ppszReg = pb.Detach();
  764. return hr;
  765. }
  766. inline HRESULT CRegParser::RegisterBuffer(LPTSTR szBuffer, BOOL bRegister)
  767. {
  768. TCHAR szToken[MAX_VALUE];
  769. HRESULT hr = S_OK;
  770. LPTSTR szReg;
  771. hr = PreProcessBuffer(szBuffer, &szReg);
  772. if (FAILED(hr))
  773. return hr;
  774. #if defined(_DEBUG) && defined(DEBUG_REGISTRATION)
  775. OutputDebugString(szReg); //would call ATLTRACE but szReg is > 512 bytes
  776. OutputDebugString(_T("\n"));
  777. #endif //_DEBUG
  778. m_pchCur = szReg;
  779. // Preprocess szReg
  780. while (NULL != *m_pchCur)
  781. {
  782. if (FAILED(hr = NextToken(szToken)))
  783. break;
  784. HKEY hkBase;
  785. if ((hkBase = HKeyFromString(szToken)) == NULL)
  786. {
  787. ATLTRACE2(atlTraceRegistrar, 0, _T("HKeyFromString failed on %s\n"), szToken);
  788. hr = GenerateError(E_ATL_BAD_HKEY);
  789. break;
  790. }
  791. if (FAILED(hr = NextToken(szToken)))
  792. break;
  793. if (chLeftBracket != *szToken)
  794. {
  795. ATLTRACE2(atlTraceRegistrar, 0, _T("Syntax error, expecting a {, found a %s\n"), szToken);
  796. hr = GenerateError(E_ATL_MISSING_OPENKEY_TOKEN);
  797. break;
  798. }
  799. if (bRegister)
  800. {
  801. LPTSTR szRegAtRegister = m_pchCur;
  802. hr = RegisterSubkeys(szToken, hkBase, bRegister);
  803. if (FAILED(hr))
  804. {
  805. ATLTRACE2(atlTraceRegistrar, 0, _T("Failed to register, cleaning up!\n"));
  806. m_pchCur = szRegAtRegister;
  807. RegisterSubkeys(szToken, hkBase, FALSE);
  808. break;
  809. }
  810. }
  811. else
  812. {
  813. if (FAILED(hr = RegisterSubkeys(szToken, hkBase, bRegister)))
  814. break;
  815. }
  816. SkipWhiteSpace();
  817. }
  818. CoTaskMemFree(szReg);
  819. return hr;
  820. }
  821. inline HRESULT CRegParser::RegisterSubkeys(LPTSTR szToken, HKEY hkParent, BOOL bRegister, BOOL bRecover)
  822. {
  823. CRegKey keyCur;
  824. LONG lRes;
  825. LPTSTR szKey = NULL;
  826. BOOL bDelete = TRUE;
  827. BOOL bInRecovery = bRecover;
  828. HRESULT hr = S_OK;
  829. ATLTRACE2(atlTraceRegistrar, 2, _T("Num Els = %d\n"), cbNeverDelete);
  830. if (FAILED(hr = NextToken(szToken)))
  831. return hr;
  832. while (*szToken != chRightBracket) // Continue till we see a }
  833. {
  834. BOOL bTokenDelete = !lstrcmpi(szToken, szDelete);
  835. if (!lstrcmpi(szToken, szForceRemove) || bTokenDelete)
  836. {
  837. if (FAILED(hr = NextToken(szToken)))
  838. break;
  839. if (bRegister)
  840. {
  841. CRegKey rkForceRemove;
  842. if (StrChr(szToken, chDirSep) != NULL)
  843. return GenerateError(E_ATL_COMPOUND_KEY);
  844. if (CanForceRemoveKey(szToken))
  845. {
  846. rkForceRemove.Attach(hkParent);
  847. rkForceRemove.RecurseDeleteKey(szToken);
  848. rkForceRemove.Detach();
  849. }
  850. if (bTokenDelete)
  851. {
  852. if (FAILED(hr = NextToken(szToken)))
  853. break;
  854. if (FAILED(hr = SkipAssignment(szToken)))
  855. break;
  856. goto EndCheck;
  857. }
  858. }
  859. }
  860. if (!lstrcmpi(szToken, szNoRemove))
  861. {
  862. bDelete = FALSE; // set even for register
  863. if (FAILED(hr = NextToken(szToken)))
  864. break;
  865. }
  866. if (!lstrcmpi(szToken, szValToken)) // need to add a value to hkParent
  867. {
  868. TCHAR szValueName[_MAX_PATH];
  869. if (FAILED(hr = NextToken(szValueName)))
  870. break;
  871. if (FAILED(hr = NextToken(szToken)))
  872. break;
  873. if (*szToken != chEquals)
  874. return GenerateError(E_ATL_EXPECTING_EQUAL);
  875. if (bRegister)
  876. {
  877. CRegKey rk;
  878. rk.Attach(hkParent);
  879. hr = AddValue(rk, szValueName, szToken);
  880. rk.Detach();
  881. if (FAILED(hr))
  882. return hr;
  883. goto EndCheck;
  884. }
  885. else
  886. {
  887. if (!bRecover)
  888. {
  889. ATLTRACE2(atlTraceRegistrar, 1, _T("Deleting %s\n"), szValueName);
  890. CRegKey rkParent;
  891. rkParent.Attach(hkParent);
  892. rkParent.DeleteValue(szValueName);
  893. rkParent.Detach();
  894. }
  895. if (FAILED(hr = SkipAssignment(szToken)))
  896. break;
  897. continue; // can never have a subkey
  898. }
  899. }
  900. if (StrChr(szToken, chDirSep) != NULL)
  901. return GenerateError(E_ATL_COMPOUND_KEY);
  902. if (bRegister)
  903. {
  904. lRes = keyCur.Open(hkParent, szToken, KEY_ALL_ACCESS);
  905. if (ERROR_SUCCESS != lRes)
  906. {
  907. // Failed all access try read only
  908. lRes = keyCur.Open(hkParent, szToken, KEY_READ);
  909. if (ERROR_SUCCESS != lRes)
  910. {
  911. // Finally try creating it
  912. ATLTRACE2(atlTraceRegistrar, 2, _T("Creating key %s\n"), szToken);
  913. lRes = keyCur.Create(hkParent, szToken);
  914. if (ERROR_SUCCESS != lRes)
  915. return GenerateError(E_ATL_CREATE_KEY_FAILED);
  916. }
  917. }
  918. if (FAILED(hr = NextToken(szToken)))
  919. break;
  920. if (*szToken == chEquals)
  921. {
  922. if (FAILED(hr = AddValue(keyCur, NULL, szToken))) // NULL == default
  923. break;
  924. }
  925. }
  926. else
  927. {
  928. if (!bRecover && keyCur.Open(hkParent, szToken, KEY_READ) != ERROR_SUCCESS)
  929. bRecover = TRUE;
  930. // TRACE out Key open status and if in recovery mode
  931. #ifdef _DEBUG
  932. if (!bRecover)
  933. ATLTRACE2(atlTraceRegistrar, 1, _T("Opened Key %s\n"), szToken);
  934. else
  935. ATLTRACE2(atlTraceRegistrar, 0, _T("Ignoring Open key on %s : In Recovery mode\n"), szToken);
  936. #endif //_DEBUG
  937. // Remember Subkey
  938. if (szKey == NULL)
  939. szKey = (LPTSTR)_alloca(sizeof(TCHAR)*_MAX_PATH);
  940. lstrcpyn(szKey, szToken, _MAX_PATH);
  941. // If in recovery mode
  942. if (bRecover || HasSubKeys(keyCur) || HasValues(keyCur))
  943. {
  944. if (FAILED(hr = NextToken(szToken)))
  945. break;
  946. if (FAILED(hr = SkipAssignment(szToken)))
  947. break;
  948. if (*szToken == chLeftBracket)
  949. {
  950. if (FAILED(hr = RegisterSubkeys(szToken, keyCur.m_hKey, bRegister, bRecover)))
  951. break;
  952. if (bRecover) // Turn off recovery if we are done
  953. {
  954. bRecover = bInRecovery;
  955. ATLTRACE2(atlTraceRegistrar, 0, _T("Ending Recovery Mode\n"));
  956. if (FAILED(hr = NextToken(szToken)))
  957. break;
  958. if (FAILED(hr = SkipAssignment(szToken)))
  959. break;
  960. continue;
  961. }
  962. }
  963. if (!bRecover && HasSubKeys(keyCur))
  964. {
  965. // See if the KEY is in the NeverDelete list and if so, don't
  966. if (CanForceRemoveKey(szKey))
  967. {
  968. ATLTRACE2(atlTraceRegistrar, 0, _T("Deleting non-empty subkey %s by force\n"), szKey);
  969. keyCur.RecurseDeleteKey(szKey);
  970. }
  971. if (FAILED(hr = NextToken(szToken)))
  972. break;
  973. continue;
  974. }
  975. if (bRecover)
  976. continue;
  977. }
  978. if (!bRecover && keyCur.Close() != ERROR_SUCCESS)
  979. return GenerateError(E_ATL_CLOSE_KEY_FAILED);
  980. if (!bRecover && bDelete)
  981. {
  982. ATLTRACE2(atlTraceRegistrar, 0, _T("Deleting Key %s\n"), szKey);
  983. CRegKey rkParent;
  984. rkParent.Attach(hkParent);
  985. rkParent.DeleteSubKey(szKey);
  986. rkParent.Detach();
  987. }
  988. if (FAILED(hr = NextToken(szToken)))
  989. break;
  990. if (FAILED(hr = SkipAssignment(szToken)))
  991. break;
  992. }
  993. EndCheck:
  994. if (bRegister)
  995. {
  996. if (*szToken == chLeftBracket && lstrlen(szToken) == 1)
  997. {
  998. if (FAILED(hr = RegisterSubkeys(szToken, keyCur.m_hKey, bRegister, FALSE)))
  999. break;
  1000. if (FAILED(hr = NextToken(szToken)))
  1001. break;
  1002. }
  1003. }
  1004. }
  1005. return hr;
  1006. }
  1007. }; //namespace ATL
  1008. #endif //__STATREG_H