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.

1085 lines
30 KiB

  1. #include "private.h"
  2. #include "subitem.h"
  3. #include "subsmgrp.h"
  4. #include "helper.h"
  5. #include "offl_cpp.h" // Yech. Pidl stuff.
  6. const TCHAR c_szSubscriptionInfoValue[] = TEXT("~SubsInfo");
  7. #define c_wszSubscriptionInfoValue c_szSubscriptionInfoValue
  8. // pragmas are for compatibility with the notification manager
  9. // registry data structures which were not pack 8
  10. #pragma pack(push, RegVariantBlob, 1)
  11. //#pragma pack(8)
  12. struct NT32PACKAGE
  13. {
  14. unsigned _int16 vt; /* VARTYPE *//* unsigned short int */
  15. unsigned _int16 wReserved1; /* WORD *//* unsigned short int */
  16. unsigned _int16 wReserved2; /* WORD *//* unsigned short int */
  17. unsigned _int16 wReserved3; /* WORD *//* unsigned short int */
  18. _int64 llVal; /* LONGLONG *//* __int64 */
  19. };
  20. // Q: What's going on here?
  21. // A: Not a whole lot.
  22. // We used to store a variant in the registry. Unfortunately, variants are
  23. // 16 bytes on Win32 (8 byte header + 8 bytes of data)
  24. // 24 bytes on Win64 (8 byte header + 16 bytes of data)
  25. // Unfortunately, Win64 webcheck and Win32 webcheck both read from
  26. // the same registry location, i.e. the same blob, and won't understand one another.
  27. // Thus, boom! At least, for BSTRs that are stored inline
  28. // Fortunately, we care only about only the first 16 bytes on both platforms.
  29. // Ergo, it's sufficient to store only the top half of the Win64 variant.
  30. struct SimpleVariantBlob
  31. {
  32. NT32PACKAGE var;
  33. };
  34. struct BSTRVariantBlob : public SimpleVariantBlob
  35. {
  36. DWORD dwSize;
  37. // WCHAR wsz[]; // Variable length string
  38. };
  39. struct OldBSTRVariantBlob
  40. {
  41. DWORD dwSize;
  42. VARIANT var;
  43. };
  44. struct SignatureSimpleBlob
  45. {
  46. DWORD dwSignature;
  47. SimpleVariantBlob svb;
  48. };
  49. struct SignatureBSTRBlob
  50. {
  51. DWORD dwSignature;
  52. BSTRVariantBlob bvb;
  53. };
  54. #pragma pack(pop, RegVariantBlob)
  55. #define BLOB_SIGNATURE 0x4b434f4d
  56. // We need fStream to indicate when we're upgrading IE4-style streams-of-blobs. (IE6 24398)
  57. HRESULT BlobToVariant(BYTE *pData, DWORD cbData, VARIANT *pVar, DWORD *pcbUsed, BOOL fStream)
  58. {
  59. HRESULT hr = S_OK;
  60. SimpleVariantBlob *pBlob = (SimpleVariantBlob *)pData;
  61. ASSERT(NULL != pBlob);
  62. ASSERT(cbData >= sizeof(SimpleVariantBlob));
  63. ASSERT(NULL != pVar);
  64. if ((NULL != pBlob) &&
  65. (cbData >= sizeof(SimpleVariantBlob)) &&
  66. (NULL != pVar))
  67. {
  68. memcpy(pVar, &pBlob->var, sizeof(NT32PACKAGE));
  69. switch (pVar->vt)
  70. {
  71. case VT_I4: // LONG
  72. case VT_UI1: // BYTE
  73. case VT_I2: // SHORT
  74. case VT_R4: // FLOAT
  75. case VT_R8: // DOUBLE
  76. case VT_BOOL: // VARIANT_BOOL
  77. case VT_ERROR: // SCODE
  78. case VT_CY: // CY
  79. case VT_DATE: // DATE
  80. case VT_I1: // CHAR
  81. case VT_UI2: // USHORT
  82. case VT_UI4: // ULONG
  83. case VT_INT: // INT
  84. case VT_UINT: // UINT
  85. if (pcbUsed)
  86. {
  87. *pcbUsed = sizeof(SimpleVariantBlob);
  88. }
  89. break;
  90. case VT_BSTR: // BSTR
  91. hr = E_UNEXPECTED;
  92. ASSERT(cbData >= sizeof(BSTRVariantBlob));
  93. if (cbData >= sizeof(BSTRVariantBlob))
  94. {
  95. BSTRVariantBlob *pbstrBlob = (BSTRVariantBlob *)pData;
  96. DWORD dwSize = pbstrBlob->dwSize;
  97. #ifdef WIN64
  98. ASSERT((cbData==(sizeof(BSTRVariantBlob) + dwSize))
  99. || (cbData==(sizeof(OldBSTRVariantBlob) + dwSize)));
  100. #else
  101. ASSERT((cbData==(sizeof(BSTRVariantBlob) + dwSize))
  102. || (fStream && (cbData>=(sizeof(BSTRVariantBlob) + dwSize))));
  103. #endif
  104. if ((cbData==(sizeof(BSTRVariantBlob) + dwSize))
  105. || (fStream && (cbData>=(sizeof(BSTRVariantBlob) + dwSize))))
  106. {
  107. pVar->bstrVal = SysAllocStringByteLen(NULL, dwSize);
  108. if (NULL != pVar->bstrVal)
  109. {
  110. if (pcbUsed)
  111. {
  112. *pcbUsed = sizeof(BSTRVariantBlob) + pbstrBlob->dwSize;
  113. }
  114. memcpy(pVar->bstrVal,
  115. ((BYTE *)pbstrBlob) +
  116. (FIELD_OFFSET(BSTRVariantBlob, dwSize) +
  117. sizeof(dwSize)),
  118. dwSize);
  119. hr = S_OK;
  120. }
  121. else
  122. {
  123. hr = E_OUTOFMEMORY;
  124. }
  125. }
  126. }
  127. if (FAILED(hr))
  128. {
  129. pVar->vt = VT_EMPTY;
  130. }
  131. break;
  132. default:
  133. hr = E_NOTIMPL;
  134. break;
  135. }
  136. }
  137. else
  138. {
  139. hr = E_UNEXPECTED;
  140. }
  141. return hr;
  142. }
  143. HRESULT SignatureBlobToVariant(BYTE *pData, DWORD cbData, VARIANT *pVar)
  144. {
  145. HRESULT hr;
  146. SignatureSimpleBlob *pBlob = (SignatureSimpleBlob *)pData;
  147. ASSERT(NULL != pBlob);
  148. ASSERT(cbData >= sizeof(SignatureSimpleBlob));
  149. ASSERT(NULL != pVar);
  150. ASSERT(BLOB_SIGNATURE == pBlob->dwSignature);
  151. if ((NULL != pBlob) &&
  152. (cbData >= sizeof(SignatureSimpleBlob)) &&
  153. (NULL != pVar) &&
  154. (BLOB_SIGNATURE == pBlob->dwSignature))
  155. {
  156. hr = BlobToVariant((BYTE *)&pBlob->svb,
  157. cbData - (FIELD_OFFSET(SignatureSimpleBlob, svb)),
  158. pVar,
  159. NULL);
  160. }
  161. else
  162. {
  163. hr = E_UNEXPECTED;
  164. }
  165. return hr;
  166. }
  167. HRESULT VariantToSignatureBlob(const VARIANT *pVar, BYTE **ppData, DWORD *pdwSize)
  168. {
  169. HRESULT hr;
  170. ASSERT(NULL != pVar);
  171. ASSERT(NULL != ppData);
  172. ASSERT(NULL != pdwSize);
  173. if ((NULL != pVar) && (NULL != ppData) && (NULL != pdwSize))
  174. {
  175. DWORD dwSize;
  176. DWORD dwBstrLen = 0;
  177. hr = S_OK;
  178. switch (pVar->vt)
  179. {
  180. case VT_I4: // LONG
  181. case VT_UI1: // BYTE
  182. case VT_I2: // SHORT
  183. case VT_R4: // FLOAT
  184. case VT_R8: // DOUBLE
  185. case VT_BOOL: // VARIANT_BOOL
  186. case VT_ERROR: // SCODE
  187. case VT_CY: // CY
  188. case VT_DATE: // DATE
  189. case VT_I1: // CHAR
  190. case VT_UI2: // USHORT
  191. case VT_UI4: // ULONG
  192. case VT_INT: // INT
  193. case VT_UINT: // UINT
  194. dwSize = sizeof(SignatureSimpleBlob);
  195. break;
  196. case VT_BSTR: // BSTR
  197. if (NULL != pVar->bstrVal)
  198. dwBstrLen = SysStringByteLen(pVar->bstrVal);
  199. dwSize = sizeof(SignatureBSTRBlob) + dwBstrLen;
  200. break;
  201. default:
  202. hr = E_NOTIMPL;
  203. dwSize = 0;
  204. break;
  205. }
  206. if (SUCCEEDED(hr))
  207. {
  208. SignatureSimpleBlob *pSignatureBlob = (SignatureSimpleBlob *)new BYTE[dwSize];
  209. if (NULL != pSignatureBlob)
  210. {
  211. *ppData = (BYTE *)pSignatureBlob;
  212. *pdwSize = dwSize;
  213. pSignatureBlob->dwSignature = BLOB_SIGNATURE;
  214. switch (pVar->vt)
  215. {
  216. case VT_I4: // LONG
  217. case VT_UI1: // BYTE
  218. case VT_I2: // SHORT
  219. case VT_R4: // FLOAT
  220. case VT_R8: // DOUBLE
  221. case VT_BOOL: // VARIANT_BOOL
  222. case VT_ERROR: // SCODE
  223. case VT_CY: // CY
  224. case VT_DATE: // DATE
  225. case VT_I1: // CHAR
  226. case VT_UI2: // USHORT
  227. case VT_UI4: // ULONG
  228. case VT_INT: // INT
  229. case VT_UINT: // UINT
  230. {
  231. SimpleVariantBlob *pBlob = &pSignatureBlob->svb;
  232. memcpy(&pBlob->var, pVar, sizeof(NT32PACKAGE));
  233. break;
  234. }
  235. case VT_BSTR: // BSTR
  236. {
  237. BSTRVariantBlob *pbstrBlob =
  238. &((SignatureBSTRBlob *)pSignatureBlob)->bvb;
  239. memcpy(&pbstrBlob->var, pVar, sizeof(NT32PACKAGE));
  240. pbstrBlob->dwSize = dwBstrLen;
  241. memcpy(((BYTE *)pbstrBlob) +
  242. (FIELD_OFFSET(BSTRVariantBlob, dwSize) +
  243. sizeof(dwSize)),
  244. pVar->bstrVal,
  245. dwBstrLen);
  246. break;
  247. }
  248. default:
  249. ASSERT(0); // Default case should have been eliminated!
  250. break;
  251. }
  252. }
  253. else
  254. {
  255. hr = E_OUTOFMEMORY;
  256. }
  257. }
  258. }
  259. else
  260. {
  261. hr = E_INVALIDARG;
  262. }
  263. return hr;
  264. }
  265. CEnumItemProperties::CEnumItemProperties()
  266. {
  267. ASSERT(0 == m_nCurrent);
  268. ASSERT(0 == m_nCount);
  269. ASSERT(NULL == m_pItemProps);
  270. m_cRef = 1;
  271. DllAddRef();
  272. }
  273. CEnumItemProperties::~CEnumItemProperties()
  274. {
  275. if (NULL != m_pItemProps)
  276. {
  277. for (ULONG i = 0; i < m_nCount; i++)
  278. {
  279. VariantClear(&m_pItemProps[i].variantValue);
  280. if (NULL != m_pItemProps[i].pwszName)
  281. {
  282. CoTaskMemFree(m_pItemProps[i].pwszName);
  283. }
  284. }
  285. delete [] m_pItemProps;
  286. }
  287. DllRelease();
  288. }
  289. HRESULT CEnumItemProperties::Initialize(const SUBSCRIPTIONCOOKIE *pCookie, ISubscriptionItem *psi)
  290. {
  291. HRESULT hr = E_FAIL;
  292. HKEY hkey;
  293. ASSERT(NULL != pCookie);
  294. if (OpenItemKey(pCookie, FALSE, KEY_READ, &hkey))
  295. {
  296. DWORD dwMaxValNameSize;
  297. DWORD dwMaxDataSize;
  298. DWORD dwCount;
  299. if (RegQueryInfoKey(hkey,
  300. NULL, // address of buffer for class string
  301. NULL, // address of size of class string buffer
  302. NULL, // reserved
  303. NULL, // address of buffer for number of subkeys
  304. NULL, // address of buffer for longest subkey name length
  305. NULL, // address of buffer for longest class string length
  306. &dwCount, // address of buffer for number of value entries
  307. &dwMaxValNameSize, // address of buffer for longest value name length
  308. &dwMaxDataSize, // address of buffer for longest value data length
  309. NULL, // address of buffer for security descriptor length
  310. NULL // address of buffer for last write time
  311. ) == ERROR_SUCCESS)
  312. {
  313. // This allocates enough for Password as well
  314. m_pItemProps = new ITEMPROP[dwCount];
  315. dwMaxValNameSize++; // Need room for NULL
  316. // alloca candidates:
  317. TCHAR *pszValName = new TCHAR[dwMaxValNameSize];
  318. BYTE *pData = new BYTE[dwMaxDataSize];
  319. if ((NULL != m_pItemProps) && (NULL != pData) &&
  320. (NULL != pszValName)
  321. )
  322. {
  323. hr = S_OK;
  324. for (ULONG i = 0; i < dwCount; i++)
  325. {
  326. DWORD dwType;
  327. DWORD dwSize = dwMaxDataSize;
  328. DWORD dwNameSize = dwMaxValNameSize;
  329. if (SHEnumValue(hkey, i, pszValName, &dwNameSize,
  330. &dwType, pData, &dwSize) != ERROR_SUCCESS)
  331. {
  332. hr = E_UNEXPECTED;
  333. break;
  334. }
  335. // Skip the default value and our subscription info structure
  336. if ((NULL == *pszValName) ||
  337. (0 == StrCmp(pszValName, c_szSubscriptionInfoValue))
  338. )
  339. {
  340. continue;
  341. }
  342. if (dwType != REG_BINARY)
  343. {
  344. hr = E_UNEXPECTED;
  345. break;
  346. }
  347. hr = SignatureBlobToVariant(pData, dwSize, &m_pItemProps[m_nCount].variantValue);
  348. if (SUCCEEDED(hr))
  349. {
  350. WCHAR *pwszName;
  351. pwszName = pszValName;
  352. ULONG ulSize = (lstrlenW(pwszName) + 1) * sizeof(WCHAR);
  353. m_pItemProps[m_nCount].pwszName = (WCHAR *)CoTaskMemAlloc(ulSize);
  354. if (NULL != m_pItemProps[m_nCount].pwszName)
  355. {
  356. StrCpyNW(m_pItemProps[m_nCount].pwszName, pwszName, ulSize / sizeof(WCHAR));
  357. }
  358. else
  359. {
  360. hr = E_OUTOFMEMORY;
  361. break;
  362. }
  363. m_nCount++;
  364. }
  365. else
  366. {
  367. break;
  368. }
  369. }
  370. if (SUCCEEDED(ReadPassword(psi, &m_pItemProps[m_nCount].variantValue.bstrVal)))
  371. {
  372. ULONG ulSize = sizeof(L"Password");
  373. m_pItemProps[m_nCount].pwszName = (WCHAR *)CoTaskMemAlloc(ulSize);
  374. if (NULL != m_pItemProps[m_nCount].pwszName)
  375. {
  376. StrCpyNW(m_pItemProps[m_nCount].pwszName, L"Password", ulSize / sizeof(WCHAR));
  377. m_pItemProps[m_nCount].variantValue.vt = VT_BSTR;
  378. m_nCount++;
  379. }
  380. else
  381. {
  382. SysFreeString(m_pItemProps[m_nCount].variantValue.bstrVal);
  383. }
  384. }
  385. }
  386. else
  387. {
  388. hr = E_OUTOFMEMORY;
  389. }
  390. SAFEDELETE(pszValName);
  391. SAFEDELETE(pData);
  392. }
  393. RegCloseKey(hkey);
  394. }
  395. return hr;
  396. }
  397. // IUnknown members
  398. STDMETHODIMP CEnumItemProperties::QueryInterface(REFIID riid, void **ppv)
  399. {
  400. HRESULT hr;
  401. if (NULL == ppv)
  402. {
  403. return E_INVALIDARG;
  404. }
  405. if ((IID_IUnknown == riid) || (IID_IEnumItemProperties == riid))
  406. {
  407. *ppv = (IEnumItemProperties *)this;
  408. AddRef();
  409. hr = S_OK;
  410. }
  411. else
  412. {
  413. *ppv = NULL;
  414. hr = E_NOINTERFACE;
  415. }
  416. return hr;
  417. }
  418. STDMETHODIMP_(ULONG) CEnumItemProperties::AddRef()
  419. {
  420. return ++m_cRef;
  421. }
  422. STDMETHODIMP_(ULONG) CEnumItemProperties::Release()
  423. {
  424. if (--m_cRef == 0)
  425. {
  426. delete this;
  427. return 0;
  428. }
  429. return m_cRef;
  430. }
  431. HRESULT CEnumItemProperties::CopyItem(ITEMPROP *pip, WCHAR *pwszName, VARIANT *pVar)
  432. {
  433. HRESULT hr;
  434. ASSERT(NULL != pwszName);
  435. if (NULL != pwszName)
  436. {
  437. ULONG cb = (lstrlenW(pwszName) + 1) * sizeof(WCHAR);
  438. pip->pwszName = (WCHAR *)CoTaskMemAlloc(cb);
  439. if (NULL != pip->pwszName)
  440. {
  441. StrCpyNW(pip->pwszName, pwszName, cb /sizeof(WCHAR));
  442. pip->variantValue.vt = VT_EMPTY; // is this a good idea?
  443. hr = VariantCopy(&pip->variantValue, pVar);
  444. }
  445. else
  446. {
  447. hr = E_OUTOFMEMORY;
  448. }
  449. }
  450. else
  451. {
  452. hr = E_UNEXPECTED;
  453. }
  454. return hr;
  455. }
  456. HRESULT CEnumItemProperties::CopyRange(ULONG nStart, ULONG nCount,
  457. ITEMPROP *ppip, ULONG *pnCopied)
  458. {
  459. HRESULT hr = S_OK;
  460. ULONG n = 0;
  461. ULONG i;
  462. ASSERT((NULL != ppip) && (NULL != pnCopied));
  463. for (i = nStart; (S_OK == hr) && (i < m_nCount) && (n < nCount); i++, n++)
  464. {
  465. hr = CopyItem(&ppip[n], m_pItemProps[i].pwszName, &m_pItemProps[i].variantValue);
  466. }
  467. *pnCopied = n;
  468. if (SUCCEEDED(hr))
  469. {
  470. hr = (n == nCount) ? S_OK : S_FALSE;
  471. }
  472. return hr;
  473. }
  474. // IEnumItemProperties
  475. STDMETHODIMP CEnumItemProperties::Next(
  476. /* [in] */ ULONG celt,
  477. /* [length_is][size_is][out] */ ITEMPROP *rgelt,
  478. /* [out] */ ULONG *pceltFetched)
  479. {
  480. HRESULT hr;
  481. if ((0 == celt) ||
  482. ((celt > 1) && (NULL == pceltFetched)) ||
  483. (NULL == rgelt))
  484. {
  485. return E_INVALIDARG;
  486. }
  487. DWORD nFetched;
  488. hr = CopyRange(m_nCurrent, celt, rgelt, &nFetched);
  489. m_nCurrent += nFetched;
  490. if (pceltFetched)
  491. {
  492. *pceltFetched = nFetched;
  493. }
  494. return hr;
  495. }
  496. STDMETHODIMP CEnumItemProperties::Skip(
  497. /* [in] */ ULONG celt)
  498. {
  499. HRESULT hr;
  500. m_nCurrent += celt;
  501. if (m_nCurrent > (m_nCount - 1))
  502. {
  503. m_nCurrent = m_nCount; // Passed the last one
  504. hr = S_FALSE;
  505. }
  506. else
  507. {
  508. hr = S_OK;
  509. }
  510. return hr;
  511. }
  512. STDMETHODIMP CEnumItemProperties::Reset()
  513. {
  514. m_nCurrent = 0;
  515. return S_OK;
  516. }
  517. STDMETHODIMP CEnumItemProperties::Clone(
  518. /* [out] */ IEnumItemProperties **ppenum)
  519. {
  520. HRESULT hr = E_OUTOFMEMORY;
  521. *ppenum = NULL;
  522. CEnumItemProperties *peip = new CEnumItemProperties;
  523. if (NULL != peip)
  524. {
  525. peip->m_pItemProps = new ITEMPROP[m_nCount];
  526. if (NULL != peip->m_pItemProps)
  527. {
  528. ULONG nFetched;
  529. hr = E_FAIL;
  530. peip->m_nCount = m_nCount;
  531. hr = CopyRange(0, m_nCount, peip->m_pItemProps, &nFetched);
  532. if (SUCCEEDED(hr))
  533. {
  534. ASSERT(m_nCount == nFetched);
  535. if (m_nCount == nFetched)
  536. {
  537. hr = peip->QueryInterface(IID_IEnumItemProperties, (void **)ppenum);
  538. }
  539. }
  540. }
  541. peip->Release();
  542. }
  543. return hr;
  544. }
  545. STDMETHODIMP CEnumItemProperties::GetCount(
  546. /* [out] */ ULONG *pnCount)
  547. {
  548. if (NULL == pnCount)
  549. {
  550. return E_INVALIDARG;
  551. }
  552. *pnCount = m_nCount;
  553. return S_OK;
  554. }
  555. CSubscriptionItem::CSubscriptionItem(const SUBSCRIPTIONCOOKIE *pCookie, HKEY hkey)
  556. {
  557. ASSERT(NULL != pCookie);
  558. ASSERT(0 == m_dwFlags);
  559. m_cRef = 1;
  560. if (NULL != pCookie)
  561. {
  562. m_Cookie = *pCookie;
  563. }
  564. SUBSCRIPTIONITEMINFO sii;
  565. sii.cbSize = sizeof(SUBSCRIPTIONITEMINFO);
  566. if ((hkey != NULL) &&
  567. SUCCEEDED(Read(hkey, c_wszSubscriptionInfoValue, (BYTE *)&sii, sizeof(SUBSCRIPTIONITEMINFO))))
  568. {
  569. m_dwFlags = sii.dwFlags;
  570. }
  571. DllAddRef();
  572. }
  573. CSubscriptionItem::~CSubscriptionItem()
  574. {
  575. if (m_dwFlags & SI_TEMPORARY)
  576. {
  577. TCHAR szKey[MAX_PATH];
  578. if (ItemKeyNameFromCookie(&m_Cookie, szKey, ARRAYSIZE(szKey)))
  579. {
  580. SHDeleteKey(HKEY_CURRENT_USER, szKey);
  581. }
  582. }
  583. DllRelease();
  584. }
  585. HRESULT CSubscriptionItem::Read(HKEY hkeyIn, const WCHAR *pwszValueName,
  586. BYTE *pData, DWORD dwDataSize)
  587. {
  588. HRESULT hr = E_FAIL;
  589. HKEY hkey = hkeyIn;
  590. ASSERT((NULL != pwszValueName) && (NULL != pData) && (0 != dwDataSize));
  591. if ((NULL != hkey) || OpenItemKey(&m_Cookie, FALSE, KEY_READ, &hkey))
  592. {
  593. DWORD dwType;
  594. DWORD dwSize = dwDataSize;
  595. if ((RegQueryValueExW(hkey, pwszValueName, NULL, &dwType, pData, &dwSize) == ERROR_SUCCESS) &&
  596. (dwSize == dwDataSize) && (REG_BINARY == dwType))
  597. {
  598. hr = S_OK;
  599. }
  600. if (NULL == hkeyIn)
  601. {
  602. RegCloseKey(hkey);
  603. }
  604. }
  605. return hr;
  606. }
  607. HRESULT CSubscriptionItem::ReadWithAlloc(HKEY hkeyIn, const WCHAR *pwszValueName,
  608. BYTE **ppData, DWORD *pdwDataSize)
  609. {
  610. HRESULT hr = E_FAIL;
  611. HKEY hkey = hkeyIn;
  612. ASSERT((NULL != pwszValueName) && (NULL != ppData) && (NULL != pdwDataSize));
  613. if ((NULL != hkey) || OpenItemKey(&m_Cookie, FALSE, KEY_READ, &hkey))
  614. {
  615. DWORD dwType;
  616. DWORD dwSize = 0;
  617. if (RegQueryValueExW(hkey, pwszValueName, NULL, &dwType, NULL, &dwSize) == ERROR_SUCCESS)
  618. {
  619. BYTE *pData = new BYTE[dwSize];
  620. *pdwDataSize = dwSize;
  621. if (NULL != pData)
  622. {
  623. if ((RegQueryValueExW(hkey, pwszValueName, NULL, &dwType, pData, pdwDataSize) == ERROR_SUCCESS) &&
  624. (dwSize == *pdwDataSize) && (REG_BINARY == dwType))
  625. {
  626. *ppData = pData;
  627. hr = S_OK;
  628. }
  629. else
  630. {
  631. delete [] pData;
  632. }
  633. }
  634. else
  635. {
  636. hr = E_OUTOFMEMORY;
  637. }
  638. }
  639. if (NULL == hkeyIn)
  640. {
  641. RegCloseKey(hkey);
  642. }
  643. }
  644. return hr;
  645. }
  646. HRESULT CSubscriptionItem::Write(HKEY hkeyIn, const WCHAR *pwszValueName,
  647. BYTE *pData, DWORD dwDataSize)
  648. {
  649. HRESULT hr = E_FAIL;
  650. HKEY hkey = hkeyIn;
  651. ASSERT((NULL != pwszValueName) && (NULL != pData) && (0 != dwDataSize));
  652. if ((NULL != hkey) || OpenItemKey(&m_Cookie, FALSE, KEY_WRITE, &hkey))
  653. {
  654. if (RegSetValueExW(hkey, pwszValueName, 0, REG_BINARY, pData, dwDataSize) == ERROR_SUCCESS)
  655. {
  656. hr = S_OK;
  657. }
  658. if (NULL == hkeyIn)
  659. {
  660. RegCloseKey(hkey);
  661. }
  662. }
  663. return hr;
  664. }
  665. STDMETHODIMP CSubscriptionItem::QueryInterface(REFIID riid, void **ppv)
  666. {
  667. HRESULT hr;
  668. if (NULL == ppv)
  669. {
  670. return E_INVALIDARG;
  671. }
  672. if ((IID_IUnknown == riid) || (IID_ISubscriptionItem == riid))
  673. {
  674. *ppv = (ISubscriptionItem *)this;
  675. AddRef();
  676. hr = S_OK;
  677. }
  678. else
  679. {
  680. *ppv = NULL;
  681. hr = E_NOINTERFACE;
  682. }
  683. return hr;
  684. }
  685. STDMETHODIMP_(ULONG) CSubscriptionItem::AddRef()
  686. {
  687. return ++m_cRef;
  688. }
  689. STDMETHODIMP_(ULONG) CSubscriptionItem::Release()
  690. {
  691. if (--m_cRef == 0)
  692. {
  693. delete this;
  694. return 0;
  695. }
  696. return m_cRef;
  697. }
  698. STDMETHODIMP CSubscriptionItem::GetCookie(SUBSCRIPTIONCOOKIE *pCookie)
  699. {
  700. if (NULL == pCookie)
  701. {
  702. return E_INVALIDARG;
  703. }
  704. *pCookie = m_Cookie;
  705. return S_OK;
  706. }
  707. STDMETHODIMP CSubscriptionItem::GetSubscriptionItemInfo(
  708. /* [out] */ SUBSCRIPTIONITEMINFO *pSubscriptionItemInfo)
  709. {
  710. HRESULT hr;
  711. if ((NULL == pSubscriptionItemInfo) ||
  712. (pSubscriptionItemInfo->cbSize < sizeof(SUBSCRIPTIONITEMINFO)))
  713. {
  714. return E_INVALIDARG;
  715. }
  716. hr = Read(NULL, c_wszSubscriptionInfoValue, (BYTE *)pSubscriptionItemInfo, sizeof(SUBSCRIPTIONITEMINFO));
  717. ASSERT(sizeof(SUBSCRIPTIONITEMINFO) == pSubscriptionItemInfo->cbSize);
  718. if (SUCCEEDED(hr) &&
  719. (sizeof(SUBSCRIPTIONITEMINFO) != pSubscriptionItemInfo->cbSize))
  720. {
  721. hr = E_UNEXPECTED;
  722. }
  723. return hr;
  724. }
  725. STDMETHODIMP CSubscriptionItem::SetSubscriptionItemInfo(
  726. /* [in] */ const SUBSCRIPTIONITEMINFO *pSubscriptionItemInfo)
  727. {
  728. if ((NULL == pSubscriptionItemInfo) ||
  729. (pSubscriptionItemInfo->cbSize < sizeof(SUBSCRIPTIONITEMINFO)))
  730. {
  731. return E_INVALIDARG;
  732. }
  733. m_dwFlags = pSubscriptionItemInfo->dwFlags;
  734. return Write(NULL, c_wszSubscriptionInfoValue, (BYTE *)pSubscriptionItemInfo, sizeof(SUBSCRIPTIONITEMINFO));
  735. }
  736. STDMETHODIMP CSubscriptionItem::ReadProperties(
  737. ULONG nCount,
  738. /* [size_is][in] */ const LPCWSTR rgwszName[],
  739. /* [size_is][out] */ VARIANT rgValue[])
  740. {
  741. HRESULT hr = S_OK;
  742. if ((0 == nCount) || (NULL == rgwszName) || (NULL == rgValue))
  743. {
  744. return E_INVALIDARG;
  745. }
  746. HKEY hkey;
  747. if (OpenItemKey(&m_Cookie, FALSE, KEY_READ, &hkey))
  748. {
  749. for (ULONG i = 0; (i < nCount) && (S_OK == hr); i++)
  750. {
  751. BYTE *pData;
  752. DWORD dwDataSize;
  753. if (StrCmpIW(rgwszName[i], c_szPropPassword) == 0)
  754. {
  755. if (SUCCEEDED(ReadPassword(this, &rgValue[i].bstrVal)))
  756. {
  757. rgValue[i].vt = VT_BSTR;
  758. }
  759. else
  760. {
  761. rgValue[i].vt = VT_EMPTY;
  762. }
  763. }
  764. else
  765. {
  766. HRESULT hrRead = ReadWithAlloc(hkey, rgwszName[i], &pData, &dwDataSize);
  767. if (SUCCEEDED(hrRead))
  768. {
  769. hr = SignatureBlobToVariant(pData, dwDataSize, &rgValue[i]);
  770. delete [] pData;
  771. }
  772. else
  773. {
  774. rgValue[i].vt = VT_EMPTY;
  775. }
  776. }
  777. }
  778. RegCloseKey(hkey);
  779. }
  780. else
  781. {
  782. hr = E_FAIL;
  783. }
  784. return hr;
  785. }
  786. STDMETHODIMP CSubscriptionItem::WriteProperties(
  787. ULONG nCount,
  788. /* [size_is][in] */ const LPCWSTR rgwszName[],
  789. /* [size_is][in] */ const VARIANT rgValue[])
  790. {
  791. HRESULT hr = S_OK;
  792. if ((0 == nCount) || (NULL == rgwszName) || (NULL == rgValue))
  793. {
  794. return E_INVALIDARG;
  795. }
  796. HKEY hkey;
  797. if (OpenItemKey(&m_Cookie, FALSE, KEY_WRITE, &hkey))
  798. {
  799. for (ULONG i = 0; (i < nCount) && (S_OK == hr); i++)
  800. {
  801. if (rgValue[i].vt == VT_EMPTY)
  802. {
  803. // We don't actually care if this fails since it is
  804. // meant to delete the property anyhow
  805. RegDeleteValueW(hkey, rgwszName[i]);
  806. }
  807. else
  808. {
  809. BYTE *pData;
  810. DWORD dwDataSize;
  811. // Special case the name property for easy viewing
  812. if ((VT_BSTR == rgValue[i].vt) &&
  813. (StrCmpIW(rgwszName[i], c_szPropName) == 0))
  814. {
  815. RegSetValueExW(hkey, NULL, 0, REG_SZ, (LPBYTE)rgValue[i].bstrVal,
  816. (lstrlenW(rgValue[i].bstrVal) + 1) * sizeof(WCHAR));
  817. }
  818. if (StrCmpIW(rgwszName[i], c_szPropPassword) == 0)
  819. {
  820. if (VT_BSTR == rgValue[i].vt)
  821. {
  822. hr = WritePassword(this, rgValue[i].bstrVal);
  823. }
  824. else
  825. {
  826. hr = E_INVALIDARG;
  827. }
  828. }
  829. else
  830. {
  831. hr = VariantToSignatureBlob(&rgValue[i], &pData, &dwDataSize);
  832. if (SUCCEEDED(hr))
  833. {
  834. hr = Write(hkey, rgwszName[i], pData, dwDataSize);
  835. delete [] pData;
  836. }
  837. }
  838. }
  839. }
  840. RegCloseKey(hkey);
  841. }
  842. else
  843. {
  844. hr = E_FAIL;
  845. }
  846. return hr;
  847. }
  848. STDMETHODIMP CSubscriptionItem::EnumProperties(
  849. /* [out] */ IEnumItemProperties **ppEnumItemProperties)
  850. {
  851. HRESULT hr;
  852. if (NULL == ppEnumItemProperties)
  853. {
  854. return E_INVALIDARG;
  855. }
  856. CEnumItemProperties *peip = new CEnumItemProperties;
  857. *ppEnumItemProperties = NULL;
  858. if (NULL != peip)
  859. {
  860. hr = peip->Initialize(&m_Cookie, this);
  861. if (SUCCEEDED(hr))
  862. {
  863. hr = peip->QueryInterface(IID_IEnumItemProperties, (void **)ppEnumItemProperties);
  864. }
  865. peip->Release();
  866. }
  867. else
  868. {
  869. hr = E_OUTOFMEMORY;
  870. }
  871. return hr;
  872. }
  873. STDMETHODIMP CSubscriptionItem::NotifyChanged()
  874. {
  875. HRESULT hr;
  876. // Notify the shell folder of the updated item
  877. // This is SOMEWHAT inefficient... why do we need 1000 properties for a pidl?
  878. // Why do we copy them around? Why why why?
  879. OOEBuf ooeBuf;
  880. LPMYPIDL newPidl = NULL;
  881. DWORD dwSize = 0;
  882. memset(&ooeBuf, 0, sizeof(ooeBuf));
  883. hr = LoadWithCookie(NULL, &ooeBuf, &dwSize, &m_Cookie);
  884. if (SUCCEEDED(hr))
  885. {
  886. newPidl = COfflineFolderEnum::NewPidl(dwSize);
  887. if (newPidl)
  888. {
  889. CopyToMyPooe(&ooeBuf, &(newPidl->ooe));
  890. _GenerateEvent(SHCNE_UPDATEITEM, (LPITEMIDLIST)newPidl, NULL);
  891. COfflineFolderEnum::FreePidl(newPidl);
  892. }
  893. }
  894. return hr;
  895. }