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.

821 lines
19 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. DWORD cchPath = StrLen(pszPath) + 1;
  326. pse->pszPath = new TCHAR[cchPath];
  327. if (pse->pszPath)
  328. {
  329. StrCpyN(pse->pszPath, pszPath, cchPath);
  330. pse->pNext = m_pseDirectoryStack;
  331. m_pseDirectoryStack = pse;
  332. fRet = TRUE;
  333. }
  334. else
  335. {
  336. delete pse;
  337. }
  338. }
  339. return fRet;
  340. }
  341. //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
  342. //
  343. // *** CChannelEnum::DirectoryStack_IntitFromFlags ***
  344. //
  345. // Put initial search directories on the stack.
  346. //
  347. ////////////////////////////////////////////////////////////////////////////////
  348. BOOL
  349. CChannelEnum::DirectoryStack_InitFromFlags(
  350. DWORD dwEnumFlags
  351. )
  352. {
  353. ASSERT(NULL == m_pseDirectoryStack);
  354. TCHAR szPath[MAX_PATH];
  355. szPath[0] = 0;
  356. if (dwEnumFlags & CHANENUM_DESKTOPFOLDER)
  357. {
  358. LPITEMIDLIST pidl;
  359. if (SUCCEEDED(SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOPDIRECTORY,
  360. &pidl)))
  361. {
  362. ASSERT(pidl);
  363. if (SHGetPathFromIDList(pidl, szPath))
  364. DirectoryStack_Push(szPath);
  365. ILFree(pidl);
  366. }
  367. }
  368. if (dwEnumFlags & CHANENUM_CHANNELFOLDER)
  369. {
  370. if (SUCCEEDED(Channel_GetFolder(szPath, ARRAYSIZE(szPath), DOC_CHANNEL)))
  371. DirectoryStack_Push(szPath);
  372. }
  373. if (dwEnumFlags & CHANENUM_SOFTUPDATEFOLDER)
  374. {
  375. TCHAR szSoftDistFolder[MAX_PATH];
  376. if (SUCCEEDED(Channel_GetFolder(szSoftDistFolder, ARRAYSIZE(szSoftDistFolder), DOC_SOFTWAREUPDATE)) &&
  377. (StrCmpI(szSoftDistFolder, szPath) != 0))
  378. {
  379. DirectoryStack_Push(szSoftDistFolder);
  380. }
  381. }
  382. return m_pseDirectoryStack != NULL;
  383. }
  384. //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
  385. //
  386. // *** CChannelEnum::DirectoryStack_PushSubdirectories ***
  387. //
  388. // Put all subdirectories of the given directory on to the stack.
  389. //
  390. ////////////////////////////////////////////////////////////////////////////////
  391. BOOL
  392. CChannelEnum::DirectoryStack_PushSubdirectories(
  393. LPCTSTR pszPath
  394. )
  395. {
  396. ASSERT(pszPath);
  397. BOOL fRet = FALSE;
  398. TCHAR szBuffer[MAX_PATH];
  399. int cch = StrLen(pszPath);
  400. StrCpyN(szBuffer, pszPath, ARRAYSIZE(szBuffer));
  401. #ifndef UNIX
  402. StrCatBuff(szBuffer, TEXT("\\*.*"), ARRAYSIZE(szBuffer));
  403. #else
  404. StrCatBuff(szBuffer, TEXT("/*"), ARRAYSIZE(szBuffer));
  405. #endif /* UNIX */
  406. WIN32_FIND_DATA fd;
  407. HANDLE hSearch = FindFirstFile(szBuffer, &fd);
  408. if (INVALID_HANDLE_VALUE != hSearch)
  409. {
  410. if (cch < ARRAYSIZE(szBuffer) - 2)
  411. {
  412. do {
  413. if ((FILE_ATTRIBUTE_DIRECTORY & fd.dwFileAttributes) &&
  414. !StrEql(fd.cFileName, TEXT(".")) &&
  415. !StrEql(fd.cFileName, TEXT("..")) )
  416. {
  417. StrCpyN(szBuffer + cch + 1, fd.cFileName,
  418. ARRAYSIZE(szBuffer) - cch - 1);
  419. if (DirectoryStack_Push(szBuffer))
  420. fRet = TRUE;
  421. }
  422. } while (TRUE == FindNextFile(hSearch, &fd));
  423. }
  424. FindClose(hSearch);
  425. }
  426. return fRet;
  427. }
  428. //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
  429. //
  430. // *** CChannelEnum::FindNextChannel ***
  431. //
  432. // Find the next channel.
  433. //
  434. ////////////////////////////////////////////////////////////////////////////////
  435. BOOL
  436. CChannelEnum::FindNextChannel(
  437. CHANNELENUMINFO* pInfo
  438. )
  439. {
  440. ASSERT(pInfo);
  441. BOOL fRet;
  442. if (DirectoryStack_IsEmpty())
  443. {
  444. fRet = FALSE;
  445. }
  446. else
  447. {
  448. STACKENTRY* pse = DirectoryStack_Pop();
  449. DirectoryStack_PushSubdirectories(pse->pszPath);
  450. if (ReadChannelInfo(pse->pszPath, pInfo))
  451. {
  452. fRet = TRUE;
  453. }
  454. else
  455. {
  456. fRet = FindNextChannel(pInfo);
  457. }
  458. DirectoryStack_FreeEntry(pse);
  459. }
  460. return fRet;
  461. }
  462. //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
  463. //
  464. // *** CChannelEnum::FindNextChannel ***
  465. //
  466. // Find the next channel.
  467. //
  468. ////////////////////////////////////////////////////////////////////////////////
  469. BOOL
  470. CChannelEnum::ReadChannelInfo(
  471. LPCTSTR pszPath,
  472. CHANNELENUMINFO* pInfo
  473. )
  474. {
  475. ASSERT(pszPath);
  476. ASSERT(pInfo);
  477. BOOL fRet = FALSE;
  478. DWORD dwAttributes = GetFileAttributes(pszPath);
  479. #ifndef UNIX
  480. if ((-1 != dwAttributes) && (FILE_ATTRIBUTE_SYSTEM & dwAttributes))
  481. #else
  482. if ((-1 != dwAttributes))
  483. #endif /* UNIX */
  484. {
  485. if (ContainsChannelDesktopIni(pszPath))
  486. {
  487. if (NULL == m_pszURL || URLMatchesIni(pszPath, m_pszURL))
  488. {
  489. fRet = TRUE;
  490. TCHAR szURL[INTERNET_MAX_URL_LENGTH];
  491. szURL[0] = 0;
  492. if (m_dwEnumFlags & CHANENUM_TITLE)
  493. pInfo->pszTitle = OleAllocString(PathFindFileName(pszPath));
  494. if (m_dwEnumFlags & CHANENUM_PATH)
  495. pInfo->pszPath = OleAllocString(pszPath);
  496. if (m_dwEnumFlags & CHANENUM_URL)
  497. {
  498. ReadFromIni(pszPath, szURL, ARRAYSIZE(szURL), INI_URL);
  499. pInfo->pszURL = OleAllocString(szURL);
  500. }
  501. if (m_dwEnumFlags & CHANENUM_SUBSCRIBESTATE)
  502. {
  503. if (TEXT('\0') == *szURL)
  504. ReadFromIni(pszPath, szURL, ARRAYSIZE(szURL), INI_URL);
  505. pInfo->stSubscriptionState = GetSubscriptionState(szURL);
  506. }
  507. }
  508. }
  509. }
  510. return fRet;
  511. }
  512. //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
  513. //
  514. // *** CChannelEnum::ContainsChannelDesktopIni ***
  515. //
  516. // See if the directory contains a "channel" desktop.ini
  517. //
  518. ////////////////////////////////////////////////////////////////////////////////
  519. BOOL
  520. CChannelEnum::ContainsChannelDesktopIni(
  521. LPCTSTR pszPath
  522. )
  523. {
  524. ASSERT(pszPath);
  525. BOOL fRet = FALSE;
  526. TCHAR szFolderGUID[GUID_STR_LEN];
  527. if (ReadFromIni(pszPath, szFolderGUID, ARRAYSIZE(szFolderGUID), INI_GUID))
  528. {
  529. TCHAR szChannelGUID[GUID_STR_LEN];
  530. if (SHStringFromGUID(CLSID_CDFINI, szChannelGUID,
  531. ARRAYSIZE(szChannelGUID)))
  532. {
  533. fRet = StrEql(szFolderGUID, szChannelGUID);
  534. }
  535. }
  536. return fRet;
  537. }
  538. //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
  539. //
  540. // *** CChannelEnum::URLMatchesIni ***
  541. //
  542. // See if the given url matches the url in the desktop.ini
  543. //
  544. ////////////////////////////////////////////////////////////////////////////////
  545. BOOL
  546. CChannelEnum::URLMatchesIni(
  547. LPCTSTR pszPath,
  548. LPCTSTR pszURL
  549. )
  550. {
  551. ASSERT(pszPath);
  552. ASSERT(pszURL);
  553. BOOL fRet = FALSE;
  554. TCHAR szIniURL[INTERNET_MAX_URL_LENGTH];
  555. if (ReadFromIni(pszPath, szIniURL, ARRAYSIZE(szIniURL), INI_URL))
  556. {
  557. TCHAR szCanonicalURL[INTERNET_MAX_URL_LENGTH];
  558. DWORD cch = ARRAYSIZE(szCanonicalURL);
  559. if (InternetCanonicalizeUrl(szIniURL, szCanonicalURL, &cch, ICU_NO_ENCODE))
  560. {
  561. fRet = StrEql((LPTSTR)pszURL, szCanonicalURL);
  562. }
  563. else
  564. {
  565. fRet = StrEql((LPTSTR)pszURL, szIniURL);
  566. }
  567. }
  568. return fRet;
  569. }
  570. //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
  571. //
  572. // *** CChannelEnum::ReadFromIni ***
  573. //
  574. // Read a value from the channel desktop.ini
  575. //
  576. ////////////////////////////////////////////////////////////////////////////////
  577. BOOL
  578. CChannelEnum::ReadFromIni(
  579. LPCTSTR pszPath,
  580. LPTSTR pszOut,
  581. int cch,
  582. INIVALUE iv
  583. )
  584. {
  585. BOOL fRet;
  586. static const struct _tagINISTRINGS
  587. {
  588. LPCTSTR pszSection;
  589. LPCTSTR pszKey;
  590. INIVALUE iv;
  591. }
  592. aIniTable[] =
  593. {
  594. {TEXT(".ShellClassInfo"), TEXT("CLSID"), INI_GUID},
  595. {TEXT("Channel") , TEXT("CDFURL"), INI_URL }
  596. };
  597. ASSERT(pszPath);
  598. ASSERT(pszOut || 0 == cch);
  599. ASSERT(aIniTable[iv].iv == iv);
  600. TCHAR szIniFile[MAX_PATH];
  601. if (PathCombine(szIniFile, pszPath, TEXT("desktop.ini")))
  602. {
  603. fRet = GetPrivateProfileString(aIniTable[iv].pszSection,
  604. aIniTable[iv].pszKey, TEXT(""), pszOut, cch,
  605. szIniFile);
  606. }
  607. else
  608. {
  609. fRet = FALSE;
  610. }
  611. return fRet;
  612. }
  613. //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
  614. //
  615. // *** CChannelEnum::OleAllocString ***
  616. //
  617. // Allocate an OLESTR for the given string.
  618. //
  619. ////////////////////////////////////////////////////////////////////////////////
  620. LPOLESTR
  621. CChannelEnum::OleAllocString(
  622. LPCTSTR psz
  623. )
  624. {
  625. ASSERT(psz);
  626. int cch = StrLen(psz) + 1;
  627. LPOLESTR polestr = (LPOLESTR)CoTaskMemAlloc(cch * sizeof(WCHAR));
  628. if (polestr)
  629. SHTCharToUnicode(psz, polestr, cch);
  630. return polestr;
  631. }
  632. //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
  633. //
  634. // *** CChannelEnum::GetSubscriptionState ***
  635. //
  636. // Read a value from the channel desktop.ini
  637. //
  638. ////////////////////////////////////////////////////////////////////////////////
  639. SUBSCRIPTIONSTATE
  640. CChannelEnum::GetSubscriptionState(
  641. LPCTSTR pszURL
  642. )
  643. {
  644. ASSERT(pszURL);
  645. SUBSCRIPTIONSTATE stRet = SUBSTATE_NOTSUBSCRIBED;
  646. ISubscriptionMgr* pISubscriptionMgr;
  647. HRESULT hr = CoCreateInstance(CLSID_SubscriptionMgr, NULL,
  648. CLSCTX_INPROC_SERVER, IID_ISubscriptionMgr,
  649. (void**)&pISubscriptionMgr);
  650. if (SUCCEEDED(hr))
  651. {
  652. ASSERT(pISubscriptionMgr);
  653. WCHAR wszURL[INTERNET_MAX_URL_LENGTH];
  654. if (SHTCharToUnicode(pszURL, wszURL, ARRAYSIZE(wszURL)))
  655. {
  656. BOOL fSubscribed = FALSE;
  657. pISubscriptionMgr->IsSubscribed(wszURL, &fSubscribed);
  658. if (fSubscribed)
  659. {
  660. stRet = SUBSTATE_PARTIALSUBSCRIPTION;
  661. SUBSCRIPTIONINFO si = { 0 };
  662. si.cbSize = sizeof SUBSCRIPTIONINFO;
  663. hr = pISubscriptionMgr->GetSubscriptionInfo(wszURL, &si);
  664. if (SUCCEEDED(hr))
  665. {
  666. if (!(si.fChannelFlags & CHANNEL_AGENT_PRECACHE_SOME))
  667. stRet = SUBSTATE_FULLSUBSCRIPTION;
  668. }
  669. }
  670. }
  671. pISubscriptionMgr->Release();
  672. }
  673. return stRet;
  674. }