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.

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