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.

404 lines
9.8 KiB

  1. #include "priv.h"
  2. #include <enumt.h>
  3. #include <memt.h>
  4. #include "assoc.h"
  5. class CRegistrySource : public IQuerySource, public IObjectWithRegistryKey
  6. {
  7. public: // methods
  8. CRegistrySource() : _cRef(1), _hk(NULL) {}
  9. ~CRegistrySource() { if (_hk) RegCloseKey(_hk); }
  10. HRESULT Init(HKEY hk, PCWSTR pszSub, BOOL fCreate);
  11. // IUnknown methods
  12. STDMETHODIMP QueryInterface(REFIID riid, void **ppvObj);
  13. STDMETHODIMP_(ULONG) AddRef()
  14. {
  15. return ++_cRef;
  16. }
  17. STDMETHODIMP_(ULONG) Release()
  18. {
  19. if (--_cRef > 0)
  20. return _cRef;
  21. delete this;
  22. return 0;
  23. }
  24. // IObjectWithRegistryKey
  25. STDMETHODIMP SetKey(HKEY hk);
  26. STDMETHODIMP GetKey(HKEY *phk);
  27. // IQuerySource
  28. STDMETHODIMP EnumValues(IEnumString **ppenum);
  29. STDMETHODIMP EnumSources(IEnumString **ppenum);
  30. STDMETHODIMP QueryValueString(PCWSTR pszSubSource, PCWSTR pszValue, PWSTR *ppsz);
  31. STDMETHODIMP QueryValueDword(PCWSTR pszSubSource, PCWSTR pszValue, DWORD *pdw);
  32. STDMETHODIMP QueryValueExists(PCWSTR pszSubSource, PCWSTR pszValue);
  33. STDMETHODIMP QueryValueDirect(PCWSTR pszSubSource, PCWSTR pszValue, FLAGGED_BYTE_BLOB **ppblob);
  34. STDMETHODIMP OpenSource(PCWSTR pszSubSource, BOOL fCreate, IQuerySource **ppqs);
  35. STDMETHODIMP SetValueDirect(PCWSTR pszSubSource, PCWSTR pszValue, ULONG qvt, DWORD cbData, BYTE *pvData);
  36. protected: // methods
  37. protected: // members
  38. LONG _cRef;
  39. HKEY _hk;
  40. };
  41. STDAPI CRegistrySource::QueryInterface(REFIID riid, void **ppvObj)
  42. {
  43. static const QITAB qit[] = {
  44. QITABENT(CRegistrySource, IQuerySource),
  45. QITABENT(CRegistrySource, IObjectWithRegistryKey),
  46. };
  47. return QISearch(this, qit, riid, ppvObj);
  48. }
  49. HRESULT CRegistrySource::Init(HKEY hk, PCWSTR pszSub, BOOL fCreate)
  50. {
  51. DWORD err;
  52. if (!fCreate)
  53. err = RegOpenKeyExWrapW(hk, pszSub, 0, MAXIMUM_ALLOWED, &_hk);
  54. else
  55. err = RegCreateKeyExWrapW(hk, pszSub, 0, NULL, REG_OPTION_NON_VOLATILE, MAXIMUM_ALLOWED, NULL, &_hk, NULL);
  56. return HRESULT_FROM_WIN32(err);
  57. }
  58. HRESULT CRegistrySource::SetKey(HKEY hk)
  59. {
  60. if (!_hk)
  61. {
  62. _hk = SHRegDuplicateHKey(hk);
  63. if (_hk)
  64. return S_OK;
  65. }
  66. return E_UNEXPECTED;
  67. }
  68. HRESULT CRegistrySource::GetKey(HKEY *phk)
  69. {
  70. if (_hk)
  71. {
  72. *phk = SHRegDuplicateHKey(_hk);
  73. if (*phk)
  74. return S_OK;
  75. }
  76. *phk = NULL;
  77. return E_UNEXPECTED;
  78. }
  79. HRESULT CRegistrySource::QueryValueString(PCWSTR pszSubSource, PCWSTR pszValue, PWSTR *ppsz)
  80. {
  81. HRESULT hr = E_UNEXPECTED;
  82. WCHAR sz[128];
  83. DWORD cb = sizeof(sz);
  84. DWORD dwType;
  85. LONG err = SHGetValueW(_hk, pszSubSource, pszValue, &dwType, sz, &cb);
  86. *ppsz = 0;
  87. if (err == ERROR_SUCCESS)
  88. {
  89. if (dwType == REG_SZ)
  90. {
  91. // if they are querying for the default value,
  92. // then fail if it is empty
  93. if (pszValue || *sz)
  94. hr = SHStrDupW(sz, ppsz);
  95. else
  96. hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  97. }
  98. else
  99. hr = HRESULT_FROM_WIN32(ERROR_DATATYPE_MISMATCH);
  100. }
  101. else
  102. {
  103. if (err == ERROR_MORE_DATA)
  104. {
  105. // retry with an alloc'd buffer
  106. ASSERT(cb > sizeof(sz));
  107. hr = SHCoAlloc(cb, ppsz);
  108. if (SUCCEEDED(hr))
  109. {
  110. err = SHGetValueW(_hk, pszSubSource, pszValue, &dwType, *ppsz, &cb);
  111. if (dwType != REG_SZ)
  112. err = ERROR_DATATYPE_MISMATCH;
  113. if (err)
  114. {
  115. CoTaskMemFree(*ppsz);
  116. *ppsz = 0;
  117. hr = HRESULT_FROM_WIN32(err);
  118. }
  119. }
  120. }
  121. else
  122. hr = HRESULT_FROM_WIN32(err);
  123. }
  124. return hr;
  125. }
  126. HRESULT CRegistrySource::QueryValueDword(PCWSTR pszSubSource, PCWSTR pszValue, DWORD *pdw)
  127. {
  128. DWORD cb = sizeof(*pdw);
  129. // DWORD dwType;
  130. LONG err = SHGetValueW(_hk, pszSubSource, pszValue, NULL, pdw, &cb);
  131. // dwType check REG_DWORD || REG_BINARY?
  132. return HRESULT_FROM_WIN32(err);
  133. }
  134. HRESULT CRegistrySource::QueryValueExists(PCWSTR pszSubSource, PCWSTR pszValue)
  135. {
  136. LONG err = SHGetValueW(_hk, pszSubSource, pszValue, NULL, NULL, NULL);
  137. return HRESULT_FROM_WIN32(err);
  138. }
  139. HRESULT _SHAllocBlob(DWORD cb, BYTE *pb, FLAGGED_BYTE_BLOB **ppblob)
  140. {
  141. HRESULT hr = SHCoAlloc(cb + FIELD_OFFSET(FLAGGED_BYTE_BLOB, abData), ppblob);
  142. if (SUCCEEDED(hr))
  143. {
  144. (*ppblob)->clSize = cb;
  145. if (pb)
  146. memcpy((*ppblob)->abData, pb, cb);
  147. }
  148. return hr;
  149. }
  150. HRESULT CRegistrySource::QueryValueDirect(PCWSTR pszSubSource, PCWSTR pszValue, FLAGGED_BYTE_BLOB **ppblob)
  151. {
  152. HRESULT hr = E_FAIL;
  153. BYTE rgch[256];
  154. DWORD cb = sizeof(rgch);
  155. DWORD dwType;
  156. HKEY hk = _hk;
  157. LONG err = ERROR_SUCCESS;
  158. *ppblob = 0;
  159. if (pszSubSource && *pszSubSource)
  160. {
  161. err = RegOpenKeyExWrapW(_hk, pszSubSource, 0, KEY_QUERY_VALUE, &hk);
  162. ASSERT(NO_ERROR == err || !hk);
  163. }
  164. if (err == ERROR_SUCCESS)
  165. {
  166. err = RegQueryValueExWrapW(hk, pszValue, NULL, &dwType, rgch, &cb);
  167. if (err == ERROR_SUCCESS)
  168. {
  169. hr = _SHAllocBlob(cb, rgch, ppblob);
  170. }
  171. else
  172. {
  173. if (err == ERROR_MORE_DATA)
  174. {
  175. // retry with an alloc'd buffer
  176. ASSERT(cb > sizeof(rgch));
  177. hr = _SHAllocBlob(cb, NULL, ppblob);
  178. if (SUCCEEDED(hr))
  179. {
  180. err = RegQueryValueExWrapW(hk, pszValue, NULL, &dwType, (*ppblob)->abData, &cb);
  181. if (err)
  182. {
  183. CoTaskMemFree(*ppblob);
  184. *ppblob = 0;
  185. }
  186. }
  187. }
  188. hr = HRESULT_FROM_WIN32(err);
  189. }
  190. if (hk != _hk)
  191. RegCloseKey(hk);
  192. }
  193. if (SUCCEEDED(hr))
  194. (*ppblob)->fFlags = dwType;
  195. return hr;
  196. }
  197. HRESULT CRegistrySource::OpenSource(PCWSTR pszSubSource, BOOL fCreate, IQuerySource **ppqs)
  198. {
  199. return QuerySourceCreateFromKey(_hk, pszSubSource, fCreate, IID_PPV_ARG(IQuerySource, ppqs));
  200. }
  201. HRESULT CRegistrySource::SetValueDirect(PCWSTR pszSubSource, PCWSTR pszValue, ULONG qvt, DWORD cbData, BYTE *pvData)
  202. {
  203. LONG err = SHSetValueW(_hk, pszSubSource, pszValue, qvt, pvData, cbData);
  204. return HRESULT_FROM_WIN32(err);
  205. }
  206. class CRegistryEnum : public CEnumAny<IEnumString, PWSTR>
  207. {
  208. public:
  209. HRESULT Init(HKEY hk, CRegistrySource *prs)
  210. {
  211. // we take a ref on the _punk to keep
  212. // the key alive
  213. _hk = hk;
  214. _punkKey = SAFECAST(prs, IQuerySource *);
  215. prs->AddRef();
  216. _cch = _MaxLen();
  217. if (_cch > ARRAYSIZE(_sz))
  218. {
  219. _psz = (PWSTR) LocalAlloc(LPTR, CbFromCchW(_cch));
  220. }
  221. else
  222. {
  223. _cch = ARRAYSIZE(_sz);
  224. _psz = _sz;
  225. }
  226. return _psz ? S_OK : E_OUTOFMEMORY;
  227. }
  228. virtual ~CRegistryEnum() { if (_psz && _psz != _sz) LocalFree(_psz); _punkKey->Release(); }
  229. // IUnknown methods
  230. STDMETHODIMP QueryInterface(REFIID riid, void **ppvObj);
  231. protected: // methods
  232. BOOL _Next(PWSTR *ppsz);
  233. virtual DWORD _MaxLen() = 0;
  234. virtual BOOL _RegNext(LONG i) = 0;
  235. protected:
  236. IUnknown *_punkKey;
  237. HKEY _hk;
  238. PWSTR _psz;
  239. WCHAR _sz[64];
  240. DWORD _cch;
  241. };
  242. STDAPI CRegistryEnum::QueryInterface(REFIID riid, void **ppvObj)
  243. {
  244. static const QITAB qit[] = {
  245. QITABENT(CRegistryEnum, IEnumString),
  246. };
  247. return QISearch(this, qit, riid, ppvObj);
  248. }
  249. BOOL CRegistryEnum::_Next(PWSTR *ppsz)
  250. {
  251. return (_RegNext(_cNext) && SUCCEEDED(SHStrDupW(_psz, ppsz)));
  252. }
  253. class CRegistryEnumKeys : public CRegistryEnum
  254. {
  255. protected: // methods
  256. DWORD _MaxLen()
  257. {
  258. DWORD cch = 0;
  259. RegQueryInfoKeyWrapW(
  260. _hk,
  261. NULL,
  262. NULL,
  263. NULL,
  264. NULL,
  265. &cch,
  266. NULL,
  267. NULL,
  268. NULL,
  269. NULL,
  270. NULL,
  271. NULL
  272. );
  273. return cch;
  274. }
  275. BOOL _RegNext(LONG i)
  276. {
  277. return ERROR_SUCCESS == RegEnumKeyWrapW(_hk, i, _psz, _cch);
  278. }
  279. };
  280. class CRegistryEnumValues : public CRegistryEnum
  281. {
  282. protected: // methods
  283. DWORD _MaxLen()
  284. {
  285. DWORD cch = 0;
  286. RegQueryInfoKeyWrapW(
  287. _hk,
  288. NULL,
  289. NULL,
  290. NULL,
  291. NULL,
  292. NULL,
  293. NULL,
  294. NULL,
  295. &cch,
  296. NULL,
  297. NULL,
  298. NULL
  299. );
  300. return cch;
  301. }
  302. BOOL _RegNext(LONG i)
  303. {
  304. DWORD cch = _cch;
  305. return ERROR_SUCCESS == RegEnumValueWrapW(_hk, i, _psz, &cch, NULL, NULL, NULL, NULL);
  306. }
  307. };
  308. STDMETHODIMP CRegistrySource::EnumValues(IEnumString **ppenum)
  309. {
  310. HRESULT hr = E_OUTOFMEMORY;
  311. CRegistryEnum *pre = new CRegistryEnumValues();
  312. *ppenum = 0;
  313. if (pre)
  314. {
  315. hr = pre->Init(_hk, this);
  316. if (SUCCEEDED(hr))
  317. *ppenum = pre;
  318. else
  319. pre->Release();
  320. }
  321. return hr;
  322. }
  323. STDMETHODIMP CRegistrySource::EnumSources(IEnumString **ppenum)
  324. {
  325. HRESULT hr = E_OUTOFMEMORY;
  326. CRegistryEnum *pre = new CRegistryEnumKeys();
  327. *ppenum = 0;
  328. if (pre)
  329. {
  330. hr = pre->Init(_hk, this);
  331. if (SUCCEEDED(hr))
  332. *ppenum = pre;
  333. else
  334. pre->Release();
  335. }
  336. return hr;
  337. }
  338. LWSTDAPI QuerySourceCreateFromKey(HKEY hk, PCWSTR pszSub, BOOL fCreate, REFIID riid, void **ppv)
  339. {
  340. HRESULT hr = E_OUTOFMEMORY;
  341. CRegistrySource *prs = new CRegistrySource();
  342. *ppv = 0;
  343. if (prs)
  344. {
  345. hr = prs->Init(hk, pszSub, fCreate);
  346. if (SUCCEEDED(hr))
  347. hr = prs->QueryInterface(riid, ppv);
  348. prs->Release();
  349. }
  350. return hr;
  351. }