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.

811 lines
18 KiB

  1. //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
  2. //
  3. // chanenum.cpp
  4. //
  5. // The enumerator object for channels.
  6. //
  7. // History:
  8. //
  9. // 8/7/97 edwardp Created.
  10. //
  11. ////////////////////////////////////////////////////////////////////////////////
  12. //
  13. // Includes
  14. //
  15. #include "stdinc.h"
  16. #include "chanenum.h"
  17. #include "cdfidl.h"
  18. #include "xmlutil.h"
  19. #include "chanapi.h"
  20. #include "dll.h"
  21. //
  22. // Helper functions.
  23. //
  24. //
  25. // Constructor and destructor.
  26. //
  27. //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
  28. //
  29. // *** CChannelEnum::CChannelEnum ***
  30. //
  31. // Constructor.
  32. //
  33. ////////////////////////////////////////////////////////////////////////////////
  34. CChannelEnum::CChannelEnum (
  35. DWORD dwEnumFlags,
  36. LPCWSTR pszURL
  37. )
  38. : m_cRef(1)
  39. {
  40. ASSERT(NULL == m_pseDirectoryStack);
  41. TraceMsg(TF_OBJECTS, "+ IEnumChannels");
  42. if (pszURL)
  43. {
  44. int cch = StrLenW(pszURL) + 1;
  45. m_pszURL = new TCHAR[cch];
  46. SHUnicodeToTChar(pszURL, m_pszURL, cch);
  47. }
  48. m_dwEnumFlags = dwEnumFlags;
  49. DirectoryStack_InitFromFlags(dwEnumFlags);
  50. DllAddRef();
  51. return;
  52. }
  53. //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
  54. //
  55. // *** CChannelEnum::~CChannelEnum **
  56. //
  57. // Destructor.
  58. //
  59. ////////////////////////////////////////////////////////////////////////////////
  60. CChannelEnum::~CChannelEnum(
  61. void
  62. )
  63. {
  64. TraceMsg(TF_OBJECTS, "- IEnumChannels");
  65. if (m_pszURL)
  66. delete []m_pszURL;
  67. DirectoryStack_FreeStack();
  68. DllRelease();
  69. return;
  70. }
  71. //
  72. // IUnknown methods.
  73. //
  74. //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
  75. //
  76. // *** CChannelEnum::CChannelEnum ***
  77. //
  78. // CChannelEnum QI.
  79. //
  80. ////////////////////////////////////////////////////////////////////////////////
  81. STDMETHODIMP
  82. CChannelEnum::QueryInterface (
  83. REFIID riid,
  84. void **ppv
  85. )
  86. {
  87. ASSERT(ppv);
  88. HRESULT hr;
  89. if (IID_IUnknown == riid || IID_IEnumChannels == riid)
  90. {
  91. AddRef();
  92. *ppv = (IEnumChannels*)this;
  93. hr = S_OK;
  94. }
  95. else
  96. {
  97. *ppv = NULL;
  98. hr = E_NOINTERFACE;
  99. }
  100. ASSERT((SUCCEEDED(hr) && *ppv) || (FAILED(hr) && NULL == *ppv));
  101. return hr;
  102. }
  103. //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
  104. //
  105. // *** CChannelEnum::AddRef ***
  106. //
  107. // CChannelEnum AddRef.
  108. //
  109. ////////////////////////////////////////////////////////////////////////////////
  110. STDMETHODIMP_(ULONG)
  111. CChannelEnum::AddRef (
  112. void
  113. )
  114. {
  115. ASSERT(m_cRef != 0);
  116. ASSERT(m_cRef < (ULONG)-1);
  117. return ++m_cRef;
  118. }
  119. //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
  120. //
  121. // *** CChannelEnum::Release ***
  122. //
  123. // Cdf view Release.
  124. //
  125. ////////////////////////////////////////////////////////////////////////////////
  126. STDMETHODIMP_(ULONG)
  127. CChannelEnum::Release (
  128. void
  129. )
  130. {
  131. ASSERT (m_cRef != 0);
  132. ULONG cRef = --m_cRef;
  133. if (0 == cRef)
  134. delete this;
  135. return cRef;
  136. }
  137. //
  138. // IEnumIDList methods.
  139. //
  140. //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
  141. //
  142. // *** CChannelEnum::Next ***
  143. //
  144. //
  145. // Description:
  146. // Returns the next n item id lists associated with this enumerator.
  147. //
  148. // Parameters:
  149. // [in] celt - Number of item id lists to return.
  150. // [Out] rgelt - A pointer to an array of item id list pointers that
  151. // will receive the id item lists.
  152. // [Out] pceltFetched - A pointer to a ULONG that receives a count of the
  153. // number of id lists fetched.
  154. //
  155. // Return:
  156. // S_OK if celt items where fetched.
  157. // S_FALSE if celt items where not fetched.
  158. //
  159. // Comments:
  160. //
  161. //
  162. ////////////////////////////////////////////////////////////////////////////////
  163. STDMETHODIMP
  164. CChannelEnum::Next(
  165. ULONG celt,
  166. CHANNELENUMINFO* rgelt,
  167. ULONG* pceltFetched)
  168. {
  169. ASSERT(rgelt || 0 == celt);
  170. ASSERT(pceltFetched || 1 == celt);
  171. //
  172. // pceltFetched can be NULL if and only if celt is 1.
  173. //
  174. ULONG lFetched;
  175. if (1 == celt && NULL == pceltFetched)
  176. pceltFetched = &lFetched;
  177. for (*pceltFetched = 0; *pceltFetched < celt; (*pceltFetched)++)
  178. {
  179. if (!FindNextChannel(&rgelt[*pceltFetched]))
  180. break;
  181. }
  182. return (*pceltFetched == celt) ? S_OK : S_FALSE;
  183. }
  184. //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
  185. //
  186. // *** CChannelEnum::Skip ***
  187. //
  188. // Shell doesn't call this member.
  189. //
  190. ////////////////////////////////////////////////////////////////////////////////
  191. STDMETHODIMP
  192. CChannelEnum::Skip(
  193. ULONG celt)
  194. {
  195. CHANNELENUMINFO ci = {0};
  196. //
  197. // Don't alocated any data on the FindNextChannel call.
  198. //
  199. DWORD dwOldFlags = m_dwEnumFlags;
  200. m_dwEnumFlags = 0;
  201. while (celt && FindNextChannel(&ci))
  202. celt--;
  203. m_dwEnumFlags = dwOldFlags;
  204. return 0 == celt ? S_OK : S_FALSE;
  205. }
  206. //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
  207. //
  208. // *** CChannelEnum::Reset ***
  209. //
  210. // Set the current item to the index of the first item in CFolderItems.
  211. //
  212. ////////////////////////////////////////////////////////////////////////////////
  213. STDMETHODIMP
  214. CChannelEnum::Reset(
  215. void
  216. )
  217. {
  218. DirectoryStack_FreeStack();
  219. DirectoryStack_InitFromFlags(m_dwEnumFlags);
  220. return S_OK;
  221. }
  222. //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
  223. //
  224. // *** CChannelEnum::Clone ***
  225. //
  226. // Shell doesn't call this method.
  227. //
  228. ////////////////////////////////////////////////////////////////////////////////
  229. STDMETHODIMP
  230. CChannelEnum::Clone(
  231. IEnumChannels **ppenum
  232. )
  233. {
  234. return E_NOTIMPL;
  235. }
  236. //
  237. // Directory stack functions.
  238. //
  239. //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
  240. //
  241. // *** CChannelEnum::DirectoryStack_IsEmpty ***
  242. //
  243. // Is the stack empty.
  244. //
  245. ////////////////////////////////////////////////////////////////////////////////
  246. inline BOOL
  247. CChannelEnum::DirectoryStack_IsEmpty(
  248. void
  249. )
  250. {
  251. return NULL == m_pseDirectoryStack;
  252. }
  253. //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
  254. //
  255. // *** CChannelEnum::DirectoryStack_FreeEntry ***
  256. //
  257. // Free a stack entry item.
  258. //
  259. ////////////////////////////////////////////////////////////////////////////////
  260. void
  261. CChannelEnum::DirectoryStack_FreeEntry(
  262. STACKENTRY* pse
  263. )
  264. {
  265. ASSERT(pse)
  266. ASSERT(pse->pszPath);
  267. ASSERT(!pse->pNext);
  268. delete []pse->pszPath;
  269. delete pse;
  270. return;
  271. }
  272. //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
  273. //
  274. // *** CChannelEnum::DirectoryStack_FreeStack ***
  275. //
  276. // Free all items on the stack.
  277. //
  278. ////////////////////////////////////////////////////////////////////////////////
  279. void
  280. CChannelEnum::DirectoryStack_FreeStack(
  281. void
  282. )
  283. {
  284. while (!DirectoryStack_IsEmpty())
  285. DirectoryStack_FreeEntry(DirectoryStack_Pop());
  286. return;
  287. }
  288. //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
  289. //
  290. // *** CChannelEnum::DirectoryStack_Pop ***
  291. //
  292. // Remove an item from the stack. The caller must free the item.
  293. //
  294. ////////////////////////////////////////////////////////////////////////////////
  295. STACKENTRY*
  296. CChannelEnum::DirectoryStack_Pop(
  297. void
  298. )
  299. {
  300. STACKENTRY* pse = m_pseDirectoryStack;
  301. if (m_pseDirectoryStack)
  302. {
  303. m_pseDirectoryStack = m_pseDirectoryStack->pNext;
  304. pse->pNext = NULL;
  305. }
  306. return pse;
  307. }
  308. //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
  309. //
  310. // *** CChannelEnum::DirectoryStack_Push ***
  311. //
  312. // Put a new directory on the stack.
  313. //
  314. ////////////////////////////////////////////////////////////////////////////////
  315. BOOL
  316. CChannelEnum::DirectoryStack_Push(
  317. LPCTSTR pszPath
  318. )
  319. {
  320. ASSERT(pszPath);
  321. BOOL fRet = FALSE;
  322. STACKENTRY* pse = new STACKENTRY;
  323. if (pse)
  324. {
  325. pse->pszPath = new TCHAR[StrLen(pszPath) + 1];
  326. if (pse->pszPath)
  327. {
  328. StrCpy(pse->pszPath, pszPath);
  329. pse->pNext = m_pseDirectoryStack;
  330. m_pseDirectoryStack = pse;
  331. fRet = TRUE;
  332. }
  333. else
  334. {
  335. delete pse;
  336. }
  337. }
  338. return fRet;
  339. }
  340. //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
  341. //
  342. // *** CChannelEnum::DirectoryStack_IntitFromFlags ***
  343. //
  344. // Put initial search directories on the stack.
  345. //
  346. ////////////////////////////////////////////////////////////////////////////////
  347. BOOL
  348. CChannelEnum::DirectoryStack_InitFromFlags(
  349. DWORD dwEnumFlags
  350. )
  351. {
  352. ASSERT(NULL == m_pseDirectoryStack);
  353. TCHAR szPath[MAX_PATH];
  354. szPath[0] = 0;
  355. if (dwEnumFlags & CHANENUM_DESKTOPFOLDER)
  356. {
  357. LPITEMIDLIST pidl;
  358. if (SUCCEEDED(SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOPDIRECTORY,
  359. &pidl)))
  360. {
  361. ASSERT(pidl);
  362. if (SHGetPathFromIDList(pidl, szPath))
  363. DirectoryStack_Push(szPath);
  364. ILFree(pidl);
  365. }
  366. }
  367. if (dwEnumFlags & CHANENUM_CHANNELFOLDER)
  368. {
  369. if (SUCCEEDED(Channel_GetFolder(szPath, DOC_CHANNEL)))
  370. DirectoryStack_Push(szPath);
  371. }
  372. if (dwEnumFlags & CHANENUM_SOFTUPDATEFOLDER)
  373. {
  374. TCHAR szSoftDistFolder[MAX_PATH];
  375. if (SUCCEEDED(Channel_GetFolder(szSoftDistFolder, DOC_SOFTWAREUPDATE)) &&
  376. (StrCmpI(szSoftDistFolder, szPath) != 0))
  377. {
  378. DirectoryStack_Push(szSoftDistFolder);
  379. }
  380. }
  381. return m_pseDirectoryStack != NULL;
  382. }
  383. //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
  384. //
  385. // *** CChannelEnum::DirectoryStack_PushSubdirectories ***
  386. //
  387. // Put all subdirectories of the given directory on to the stack.
  388. //
  389. ////////////////////////////////////////////////////////////////////////////////
  390. BOOL
  391. CChannelEnum::DirectoryStack_PushSubdirectories(
  392. LPCTSTR pszPath
  393. )
  394. {
  395. ASSERT(pszPath);
  396. BOOL fRet = FALSE;
  397. TCHAR szBuffer[MAX_PATH];
  398. int cch = StrLen(pszPath);
  399. StrCpyN(szBuffer, pszPath, ARRAYSIZE(szBuffer));
  400. #ifndef UNIX
  401. lstrcatn(szBuffer, TEXT("\\*.*"), ARRAYSIZE(szBuffer));
  402. #else
  403. lstrcatn(szBuffer, TEXT("/*"), ARRAYSIZE(szBuffer));
  404. #endif /* UNIX */
  405. WIN32_FIND_DATA fd;
  406. HANDLE hSearch = FindFirstFile(szBuffer, &fd);
  407. if (INVALID_HANDLE_VALUE != hSearch)
  408. {
  409. if (cch < ARRAYSIZE(szBuffer) - 2)
  410. {
  411. do {
  412. if ((FILE_ATTRIBUTE_DIRECTORY & fd.dwFileAttributes) &&
  413. !StrEql(fd.cFileName, TEXT(".")) &&
  414. !StrEql(fd.cFileName, TEXT("..")) )
  415. {
  416. StrCpyN(szBuffer + cch + 1, fd.cFileName,
  417. ARRAYSIZE(szBuffer) - cch - 1);
  418. if (DirectoryStack_Push(szBuffer))
  419. fRet = TRUE;
  420. }
  421. } while (TRUE == FindNextFile(hSearch, &fd));
  422. }
  423. FindClose(hSearch);
  424. }
  425. return fRet;
  426. }
  427. //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
  428. //
  429. // *** CChannelEnum::FindNextChannel ***
  430. //
  431. // Find the next channel.
  432. //
  433. ////////////////////////////////////////////////////////////////////////////////
  434. BOOL
  435. CChannelEnum::FindNextChannel(
  436. CHANNELENUMINFO* pInfo
  437. )
  438. {
  439. ASSERT(pInfo);
  440. BOOL fRet;
  441. if (DirectoryStack_IsEmpty())
  442. {
  443. fRet = FALSE;
  444. }
  445. else
  446. {
  447. STACKENTRY* pse = DirectoryStack_Pop();
  448. DirectoryStack_PushSubdirectories(pse->pszPath);
  449. if (ReadChannelInfo(pse->pszPath, pInfo))
  450. {
  451. fRet = TRUE;
  452. }
  453. else
  454. {
  455. fRet = FindNextChannel(pInfo);
  456. }
  457. DirectoryStack_FreeEntry(pse);
  458. }
  459. return fRet;
  460. }
  461. //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
  462. //
  463. // *** CChannelEnum::FindNextChannel ***
  464. //
  465. // Find the next channel.
  466. //
  467. ////////////////////////////////////////////////////////////////////////////////
  468. BOOL
  469. CChannelEnum::ReadChannelInfo(
  470. LPCTSTR pszPath,
  471. CHANNELENUMINFO* pInfo
  472. )
  473. {
  474. ASSERT(pszPath);
  475. ASSERT(pInfo);
  476. BOOL fRet = FALSE;
  477. DWORD dwAttributes = GetFileAttributes(pszPath);
  478. #ifndef UNIX
  479. if ((-1 != dwAttributes) && (FILE_ATTRIBUTE_SYSTEM & dwAttributes))
  480. #else
  481. if ((-1 != dwAttributes))
  482. #endif /* UNIX */
  483. {
  484. if (ContainsChannelDesktopIni(pszPath))
  485. {
  486. if (NULL == m_pszURL || URLMatchesIni(pszPath, m_pszURL))
  487. {
  488. fRet = TRUE;
  489. TCHAR szURL[INTERNET_MAX_URL_LENGTH];
  490. szURL[0] = 0;
  491. if (m_dwEnumFlags & CHANENUM_TITLE)
  492. pInfo->pszTitle = OleAllocString(PathFindFileName(pszPath));
  493. if (m_dwEnumFlags & CHANENUM_PATH)
  494. pInfo->pszPath = OleAllocString(pszPath);
  495. if (m_dwEnumFlags & CHANENUM_URL)
  496. {
  497. ReadFromIni(pszPath, szURL, ARRAYSIZE(szURL), INI_URL);
  498. pInfo->pszURL = OleAllocString(szURL);
  499. }
  500. if (m_dwEnumFlags & CHANENUM_SUBSCRIBESTATE)
  501. {
  502. if (TEXT('\0') == *szURL)
  503. ReadFromIni(pszPath, szURL, ARRAYSIZE(szURL), INI_URL);
  504. pInfo->stSubscriptionState = GetSubscriptionState(szURL);
  505. }
  506. }
  507. }
  508. }
  509. return fRet;
  510. }
  511. //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
  512. //
  513. // *** CChannelEnum::ContainsChannelDesktopIni ***
  514. //
  515. // See if the directory contains a "channel" desktop.ini
  516. //
  517. ////////////////////////////////////////////////////////////////////////////////
  518. BOOL
  519. CChannelEnum::ContainsChannelDesktopIni(
  520. LPCTSTR pszPath
  521. )
  522. {
  523. ASSERT(pszPath);
  524. BOOL fRet = FALSE;
  525. TCHAR szFolderGUID[GUID_STR_LEN];
  526. if (ReadFromIni(pszPath, szFolderGUID, ARRAYSIZE(szFolderGUID), INI_GUID))
  527. {
  528. TCHAR szChannelGUID[GUID_STR_LEN];
  529. if (SHStringFromGUID(CLSID_CDFINI, szChannelGUID,
  530. ARRAYSIZE(szChannelGUID)))
  531. {
  532. fRet = StrEql(szFolderGUID, szChannelGUID);
  533. }
  534. }
  535. return fRet;
  536. }
  537. //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
  538. //
  539. // *** CChannelEnum::URLMatchesIni ***
  540. //
  541. // See if the given url matches the url in the desktop.ini
  542. //
  543. ////////////////////////////////////////////////////////////////////////////////
  544. BOOL
  545. CChannelEnum::URLMatchesIni(
  546. LPCTSTR pszPath,
  547. LPCTSTR pszURL
  548. )
  549. {
  550. ASSERT(pszPath);
  551. ASSERT(pszURL);
  552. BOOL fRet = FALSE;
  553. TCHAR szIniURL[INTERNET_MAX_URL_LENGTH];
  554. if (ReadFromIni(pszPath, szIniURL, ARRAYSIZE(szIniURL), INI_URL))
  555. {
  556. TCHAR szCanonicalURL[INTERNET_MAX_URL_LENGTH];
  557. DWORD cch = ARRAYSIZE(szCanonicalURL);
  558. if (InternetCanonicalizeUrl(szIniURL, szCanonicalURL, &cch, ICU_NO_ENCODE))
  559. {
  560. fRet = StrEql((LPTSTR)pszURL, szCanonicalURL);
  561. }
  562. else
  563. {
  564. fRet = StrEql((LPTSTR)pszURL, szIniURL);
  565. }
  566. }
  567. return fRet;
  568. }
  569. //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
  570. //
  571. // *** CChannelEnum::ReadFromIni ***
  572. //
  573. // Read a value from the channel desktop.ini
  574. //
  575. ////////////////////////////////////////////////////////////////////////////////
  576. BOOL
  577. CChannelEnum::ReadFromIni(
  578. LPCTSTR pszPath,
  579. LPTSTR pszOut,
  580. int cch,
  581. INIVALUE iv
  582. )
  583. {
  584. static const struct _tagINISTRINGS
  585. {
  586. LPCTSTR pszSection;
  587. LPCTSTR pszKey;
  588. INIVALUE iv;
  589. }
  590. aIniTable[] =
  591. {
  592. {TEXT(".ShellClassInfo"), TEXT("CLSID"), INI_GUID},
  593. {TEXT("Channel") , TEXT("CDFURL"), INI_URL }
  594. };
  595. ASSERT(pszPath);
  596. ASSERT(pszOut || 0 == cch);
  597. ASSERT(aIniTable[iv].iv == iv);
  598. TCHAR szIniFile[MAX_PATH];
  599. PathCombine(szIniFile, pszPath, TEXT("desktop.ini"));
  600. return GetPrivateProfileString(aIniTable[iv].pszSection,
  601. aIniTable[iv].pszKey, TEXT(""), pszOut, cch,
  602. szIniFile);
  603. }
  604. //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
  605. //
  606. // *** CChannelEnum::OleAllocString ***
  607. //
  608. // Allocate an OLESTR for the given string.
  609. //
  610. ////////////////////////////////////////////////////////////////////////////////
  611. LPOLESTR
  612. CChannelEnum::OleAllocString(
  613. LPCTSTR psz
  614. )
  615. {
  616. ASSERT(psz);
  617. int cch = StrLen(psz) + 1;
  618. LPOLESTR polestr = (LPOLESTR)CoTaskMemAlloc(cch * sizeof(WCHAR));
  619. if (polestr)
  620. SHTCharToUnicode(psz, polestr, cch);
  621. return polestr;
  622. }
  623. //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
  624. //
  625. // *** CChannelEnum::GetSubscriptionState ***
  626. //
  627. // Read a value from the channel desktop.ini
  628. //
  629. ////////////////////////////////////////////////////////////////////////////////
  630. SUBSCRIPTIONSTATE
  631. CChannelEnum::GetSubscriptionState(
  632. LPCTSTR pszURL
  633. )
  634. {
  635. ASSERT(pszURL);
  636. SUBSCRIPTIONSTATE stRet = SUBSTATE_NOTSUBSCRIBED;
  637. ISubscriptionMgr* pISubscriptionMgr;
  638. HRESULT hr = CoCreateInstance(CLSID_SubscriptionMgr, NULL,
  639. CLSCTX_INPROC_SERVER, IID_ISubscriptionMgr,
  640. (void**)&pISubscriptionMgr);
  641. if (SUCCEEDED(hr))
  642. {
  643. ASSERT(pISubscriptionMgr);
  644. WCHAR wszURL[INTERNET_MAX_URL_LENGTH];
  645. if (SHTCharToUnicode(pszURL, wszURL, ARRAYSIZE(wszURL)))
  646. {
  647. BOOL fSubscribed = FALSE;
  648. pISubscriptionMgr->IsSubscribed(wszURL, &fSubscribed);
  649. if (fSubscribed)
  650. {
  651. stRet = SUBSTATE_PARTIALSUBSCRIPTION;
  652. SUBSCRIPTIONINFO si = { 0 };
  653. si.cbSize = sizeof SUBSCRIPTIONINFO;
  654. hr = pISubscriptionMgr->GetSubscriptionInfo(wszURL, &si);
  655. if (SUCCEEDED(hr))
  656. {
  657. if (!(si.fChannelFlags & CHANNEL_AGENT_PRECACHE_SOME))
  658. stRet = SUBSTATE_FULLSUBSCRIPTION;
  659. }
  660. }
  661. }
  662. pISubscriptionMgr->Release();
  663. }
  664. return stRet;
  665. }