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.

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