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.

3639 lines
100 KiB

  1. // API to install a channel by creating a system folder in the channel directory
  2. //
  3. // Julian Jiggins (julianj), 4th May, 1997
  4. //
  5. #include "stdinc.h"
  6. #include "resource.h"
  7. #include "cdfidl.h"
  8. #include "xmlutil.h"
  9. #include "persist.h"
  10. #include "cdfview.h"
  11. #include "chanapi.h"
  12. #include "chanmgrp.h"
  13. #include "chanmgri.h"
  14. #include "chanenum.h"
  15. #include "dll.h"
  16. #include "shguidp.h"
  17. #include "winineti.h"
  18. #define _SHDOCVW_
  19. #include <shdocvw.h>
  20. #include <mluisupp.h>
  21. #ifdef UNIX
  22. #undef EVAL
  23. #define EVAL(x) x
  24. STDAPI SHAddSubscribeFavorite(HWND hwnd, LPCWSTR pwszURL, LPCWSTR pwszName, DWORD dwFlags, SUBSCRIPTIONTYPE subsType, SUBSCRIPTIONINFO* pInfo);
  25. #endif /* UNIX */
  26. #define SHELLFOLDERS \
  27. TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders")
  28. // Wininet cache preload registry key in HKCU
  29. const TCHAR c_szRegKeyCachePreload[] = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Cache\\Preload");
  30. BOOL PathCombineCleanPath(LPTSTR pszCleanPath, LPCTSTR pszPath);
  31. #ifndef UNICODE
  32. int MyPathCleanupSpec(LPCTSTR pszDir, LPTSTR pszSpec);
  33. #endif
  34. void Channel_OrderItem(LPCTSTR szPath);
  35. // This was copied from shdocvw\favorite.cpp
  36. static const int CREATESUBS_ACTIVATE = 0x8000; //hidden flag meaning channel is already on system
  37. //
  38. // Debugging code
  39. //
  40. #if 0
  41. void DumpOrderList(HDPA hdpa)
  42. {
  43. int i = 0;
  44. PORDERITEM poi = (PORDERITEM)DPA_GetPtr(hdpa, i);
  45. while (poi)
  46. {
  47. TCHAR szName[MAX_PATH];
  48. wnsprintf(szName, ARRAYSIZE(szName), "nOrder=%d, lParam=%d, pidl=", poi->nOrder, poi->lParam);
  49. OutputDebugString(szName);
  50. ASSERT(SHGetPathFromIDListA(poi->pidl, szName));
  51. OutputDebugString(szName);
  52. OutputDebugString("\n");
  53. i++;
  54. poi = (PORDERITEM)DPA_GetPtr(hdpa, i);
  55. }
  56. }
  57. void DumpPidl(LPITEMIDLIST pidl)
  58. {
  59. TCHAR szName[MAX_PATH];
  60. ASSERT(SHGetPathFromIDListA(pidl, szName));
  61. OutputDebugString(szName);
  62. OutputDebugString("\n");
  63. }
  64. #endif
  65. //
  66. // Constructor and destructor.
  67. //
  68. ////////////////////////////////////////////////////////////////////////////////
  69. //
  70. // *** CChannelMgr::CChannelMgr ***
  71. //
  72. // Constructor.
  73. //
  74. ////////////////////////////////////////////////////////////////////////////////
  75. CChannelMgr::CChannelMgr (
  76. void
  77. )
  78. : m_cRef(1)
  79. {
  80. TraceMsg(TF_OBJECTS, "+ IChannelMgr");
  81. DllAddRef();
  82. return;
  83. }
  84. ////////////////////////////////////////////////////////////////////////////////
  85. //
  86. // *** CChannelMgr::~CChannelMgr ***
  87. //
  88. // Destructor.
  89. //
  90. ////////////////////////////////////////////////////////////////////////////////
  91. CChannelMgr::~CChannelMgr (
  92. void
  93. )
  94. {
  95. ASSERT(0 == m_cRef);
  96. //
  97. // Matching Release for the constructor Addref.
  98. //
  99. TraceMsg(TF_OBJECTS, "- IChannelMgr");
  100. DllRelease();
  101. return;
  102. }
  103. //
  104. // IUnknown methods.
  105. //
  106. ////////////////////////////////////////////////////////////////////////////////
  107. //
  108. // *** CChannelMgr::QueryInterface ***
  109. //
  110. // CChannelMgr QI.
  111. //
  112. ////////////////////////////////////////////////////////////////////////////////
  113. STDMETHODIMP
  114. CChannelMgr::QueryInterface (
  115. REFIID riid,
  116. void **ppv
  117. )
  118. {
  119. ASSERT(ppv);
  120. HRESULT hr;
  121. *ppv = NULL;
  122. if (IID_IUnknown == riid || IID_IChannelMgr == riid)
  123. {
  124. *ppv = (IChannelMgr*)this;
  125. }
  126. else if ((IID_IChannelMgrPriv2 == riid) || (IID_IChannelMgrPriv == riid))
  127. {
  128. *ppv = (IChannelMgrPriv2*)this;
  129. }
  130. else if (IID_IShellCopyHook == riid)
  131. {
  132. *ppv = (ICopyHook*)this;
  133. }
  134. #ifdef UNICODE
  135. else if (IID_IShellCopyHookA == riid)
  136. {
  137. *ppv = (ICopyHookA*)this;
  138. }
  139. #endif
  140. if (*ppv)
  141. {
  142. ((IUnknown*)*ppv)->AddRef();
  143. hr = S_OK;
  144. }
  145. else
  146. {
  147. hr = E_NOINTERFACE;
  148. }
  149. ASSERT((SUCCEEDED(hr) && *ppv) || (FAILED(hr) && NULL == *ppv));
  150. return hr;
  151. }
  152. ////////////////////////////////////////////////////////////////////////////////
  153. //
  154. // *** CChannelMgr::AddRef ***
  155. //
  156. ////////////////////////////////////////////////////////////////////////////////
  157. STDMETHODIMP_(ULONG)
  158. CChannelMgr::AddRef (
  159. void
  160. )
  161. {
  162. ASSERT(m_cRef != 0);
  163. ASSERT(m_cRef < (ULONG)-1);
  164. return ++m_cRef;
  165. }
  166. //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
  167. //
  168. // *** CChannelMgr::Release ***
  169. //
  170. ////////////////////////////////////////////////////////////////////////////////
  171. STDMETHODIMP_(ULONG)
  172. CChannelMgr::Release (
  173. void
  174. )
  175. {
  176. ASSERT (m_cRef != 0);
  177. ULONG cRef = --m_cRef;
  178. if (0 == cRef)
  179. delete this;
  180. return cRef;
  181. }
  182. ////////////////////////////////////////////////////////////////////////////////
  183. //
  184. // IChannelMgr member(s)
  185. //
  186. ////////////////////////////////////////////////////////////////////////////////
  187. STDMETHODIMP CChannelMgr::AddCategory(CHANNELCATEGORYINFO *pCategoryInfo)
  188. {
  189. ASSERT(pCategoryInfo);
  190. if (!pCategoryInfo || pCategoryInfo->cbSize < sizeof(CHANNELCATEGORYINFO))
  191. {
  192. return E_INVALIDARG;
  193. }
  194. //
  195. // Convert all the wide str params to tstrs
  196. //
  197. LPWSTR pwszURL = pCategoryInfo->pszURL;
  198. LPWSTR pwszTitle = pCategoryInfo->pszTitle;
  199. LPWSTR pwszLogo = pCategoryInfo->pszLogo;
  200. LPWSTR pwszIcon = pCategoryInfo->pszIcon;
  201. LPWSTR pwszWideLogo = pCategoryInfo->pszWideLogo;
  202. //
  203. // REVIEW:is this too much to alloc on the stack?
  204. //
  205. TCHAR szURL[INTERNET_MAX_URL_LENGTH];
  206. TCHAR szTitle[MAX_PATH];
  207. TCHAR szLogo[INTERNET_MAX_URL_LENGTH];
  208. TCHAR szIcon[INTERNET_MAX_URL_LENGTH];
  209. TCHAR szWideLogo[INTERNET_MAX_URL_LENGTH];
  210. LPTSTR pszURL = NULL;
  211. LPTSTR pszTitle = NULL;
  212. LPTSTR pszLogo = NULL;
  213. LPTSTR pszIcon = NULL;
  214. LPTSTR pszWideLogo = NULL;
  215. if (pwszTitle)
  216. {
  217. SHUnicodeToTChar(pwszTitle, szTitle, MAX_PATH);
  218. pszTitle = szTitle;
  219. }
  220. else
  221. {
  222. return E_INVALIDARG; // required option
  223. }
  224. if (pwszURL)
  225. {
  226. SHUnicodeToTChar(pwszURL, szURL, INTERNET_MAX_URL_LENGTH);
  227. pszURL = szURL;
  228. }
  229. if (pwszLogo)
  230. {
  231. SHUnicodeToTChar(pwszLogo, szLogo,INTERNET_MAX_URL_LENGTH);
  232. pszLogo = szLogo;
  233. }
  234. if (pwszIcon)
  235. {
  236. SHUnicodeToTChar(pwszIcon, szIcon,INTERNET_MAX_URL_LENGTH);
  237. pszIcon = szIcon;
  238. }
  239. if (pwszWideLogo)
  240. {
  241. SHUnicodeToTChar(pwszWideLogo, szWideLogo,INTERNET_MAX_URL_LENGTH);
  242. pszWideLogo = szWideLogo;
  243. }
  244. //
  245. // Find the Channel directory
  246. // Attempt to create folder if one doesn't exist
  247. //
  248. TCHAR szPath[MAX_PATH];
  249. if (FAILED(Channel_GetFolder(szPath, DOC_CHANNEL)))
  250. {
  251. return E_FAIL; // couldn't find Channel Folder or create empty one
  252. }
  253. // Convert the title into a path component
  254. TCHAR szFileTitle[MAX_PATH];
  255. szFileTitle[0] = TEXT('\0');
  256. PathCombineCleanPath(szFileTitle, pszTitle);
  257. TraceMsg(TF_GENERAL, "AddCategory(): pszTitle = %s, szFileTitle = %s", pszTitle, szFileTitle);
  258. //
  259. // add title to channel folder path
  260. //
  261. PathCombine(szPath, szPath, szFileTitle);
  262. //
  263. // Create the logoized, iconized, webviewed special folder
  264. // public ChanMgr api doesn't handle iconIndex yet. Should fix!
  265. //
  266. //
  267. // REARCHITECT: this is not clean or elegant
  268. // we only work if the incoming URL is infact a UNC
  269. // and we copy the file to the Category Folder
  270. //
  271. if (pszURL)
  272. {
  273. TCHAR szTargetPath[MAX_PATH];
  274. LPTSTR pszFilename = PathFindFileName(pszURL);
  275. //
  276. // Create folder, webview htm is just filename no path.
  277. //
  278. Channel_CreateSpecialFolder(szPath, pszFilename, pszLogo, pszWideLogo, pszIcon, 0);
  279. //
  280. // Now build target fully qualified path to use to copy html file
  281. //
  282. PathCombine(szTargetPath, szPath, pszFilename);
  283. //
  284. // Copy html into category folder and mark it hidden
  285. if (!CopyFile(pszURL, szTargetPath, FALSE))
  286. {
  287. // If the copy fails, try again after clearing the attributes.
  288. SetFileAttributes(szTargetPath, FILE_ATTRIBUTE_NORMAL);
  289. CopyFile(pszURL, szTargetPath, FALSE);
  290. }
  291. SetFileAttributes(szTargetPath, FILE_ATTRIBUTE_HIDDEN);
  292. }
  293. else
  294. Channel_CreateSpecialFolder(szPath, NULL, pszLogo, pszWideLogo, pszIcon, 0);
  295. //
  296. // Place the channel category in the appropriate "order".
  297. //
  298. Channel_OrderItem(szPath);
  299. //
  300. // Notify the system that a new item has been added.
  301. //
  302. SHChangeNotify(SHCNE_MKDIR, SHCNF_PATH, (void*)szPath, NULL);
  303. return S_OK;
  304. }
  305. //
  306. // DeleteCategory
  307. //
  308. STDMETHODIMP CChannelMgr::DeleteCategory(LPWSTR pwzTitle)
  309. {
  310. TCHAR szTitle[INTERNET_MAX_URL_LENGTH];
  311. SHUnicodeToTChar(pwzTitle, szTitle, INTERNET_MAX_URL_LENGTH);
  312. //
  313. // REVIEW: deletegate to just deleting the channel ok???
  314. //
  315. return ::DeleteChannel(szTitle);
  316. }
  317. STDMETHODIMP CChannelMgr::AddChannelShortcut(CHANNELSHORTCUTINFO *pChannelInfo)
  318. {
  319. if (!pChannelInfo ||
  320. pChannelInfo->cbSize < sizeof(CHANNELSHORTCUTINFO) ||
  321. pChannelInfo->pszURL == NULL ||
  322. pChannelInfo->pszTitle == NULL)
  323. {
  324. ASSERT(FALSE);
  325. return E_INVALIDARG;
  326. }
  327. TCHAR szURL[INTERNET_MAX_URL_LENGTH];
  328. TCHAR szTitle[INTERNET_MAX_URL_LENGTH];
  329. TCHAR szLogo[INTERNET_MAX_URL_LENGTH];
  330. TCHAR szIcon[INTERNET_MAX_URL_LENGTH];
  331. TCHAR szWideLogo[INTERNET_MAX_URL_LENGTH];
  332. LPTSTR pszLogo = NULL;
  333. LPTSTR pszIcon = NULL;
  334. LPTSTR pszWideLogo = NULL;
  335. //
  336. // Convert BSTRs to TSTRs
  337. //
  338. SHUnicodeToTChar(pChannelInfo->pszURL, szURL, INTERNET_MAX_URL_LENGTH);
  339. SHUnicodeToTChar(pChannelInfo->pszTitle, szTitle, INTERNET_MAX_URL_LENGTH);
  340. //
  341. // Now handle optional arguments
  342. //
  343. if (pChannelInfo->pszLogo != NULL)
  344. {
  345. SHUnicodeToTChar(pChannelInfo->pszLogo, szLogo, INTERNET_MAX_URL_LENGTH);
  346. pszLogo = szLogo;
  347. }
  348. if (pChannelInfo->pszWideLogo != NULL)
  349. {
  350. SHUnicodeToTChar(pChannelInfo->pszWideLogo, szWideLogo, INTERNET_MAX_URL_LENGTH);
  351. pszWideLogo = szWideLogo;
  352. }
  353. if (pChannelInfo->pszIcon != NULL)
  354. {
  355. SHUnicodeToTChar(pChannelInfo->pszIcon, szIcon, INTERNET_MAX_URL_LENGTH);
  356. pszIcon = szIcon;
  357. }
  358. return ::AddChannel(szTitle, szURL, pszLogo, pszWideLogo, pszIcon,
  359. pChannelInfo->bIsSoftware ? DOC_SOFTWAREUPDATE : DOC_CHANNEL);
  360. }
  361. STDMETHODIMP CChannelMgr::DeleteChannelShortcut(LPWSTR pwzTitle)
  362. {
  363. TCHAR szTitle[INTERNET_MAX_URL_LENGTH];
  364. SHUnicodeToTChar(pwzTitle, szTitle, INTERNET_MAX_URL_LENGTH);
  365. return ::DeleteChannel(szTitle);
  366. }
  367. STDMETHODIMP CChannelMgr::EnumChannels(DWORD dwEnumFlags, LPCWSTR pszURL,
  368. IEnumChannels** ppIEnumChannels)
  369. {
  370. *ppIEnumChannels = (IEnumChannels*) new CChannelEnum(dwEnumFlags, pszURL);
  371. return *ppIEnumChannels ? S_OK : E_OUTOFMEMORY;
  372. }
  373. //
  374. // IChannelMgrPriv
  375. //
  376. STDMETHODIMP CChannelMgr::GetBaseChannelPath(LPSTR pszPath, int cch)
  377. {
  378. ASSERT(pszPath || 0 == cch);
  379. HRESULT hr;
  380. #ifdef UNICODE
  381. TCHAR tszPath[MAX_PATH];
  382. hr = Channel_GetBasePath(tszPath, MAX_PATH);
  383. SHTCharToAnsi(tszPath, pszPath, ARRAYSIZE(tszPath));
  384. #else
  385. hr = Channel_GetBasePath(pszPath, cch);
  386. #endif
  387. return hr;
  388. }
  389. STDMETHODIMP CChannelMgr::GetChannelFolderPath (LPSTR pszPath, int cch,
  390. CHANNELFOLDERLOCATION cflChannel)
  391. {
  392. ASSERT (pszPath || 0 == cch);
  393. XMLDOCTYPE xdt;
  394. switch (cflChannel)
  395. {
  396. case CF_CHANNEL:
  397. xdt = DOC_CHANNEL;
  398. break;
  399. case CF_SOFTWAREUPDATE:
  400. xdt = DOC_SOFTWAREUPDATE;
  401. break;
  402. default:
  403. return E_INVALIDARG;
  404. }
  405. TCHAR tszPath[MAX_PATH];
  406. HRESULT hr = Channel_GetFolder(tszPath, xdt);
  407. if (FAILED(hr) || ( SUCCEEDED(hr) && cch <= StrLen(tszPath)) )
  408. return E_FAIL;
  409. #ifdef UNICODE
  410. SHTCharToAnsi(tszPath, pszPath, ARRAYSIZE(tszPath));
  411. #else
  412. StrCpy(pszPath, tszPath);
  413. #endif
  414. return S_OK;
  415. }
  416. STDMETHODIMP CChannelMgr::GetChannelFolder (LPITEMIDLIST* ppidl,
  417. CHANNELFOLDERLOCATION cflChannel)
  418. {
  419. if (ppidl == NULL)
  420. return E_FAIL;
  421. char szPath[MAX_PATH];
  422. HRESULT hr = GetChannelFolderPath (szPath, ARRAYSIZE(szPath), cflChannel);
  423. if (FAILED (hr))
  424. return hr;
  425. #ifdef UNICODE
  426. TCHAR tszPath[MAX_PATH];
  427. SHAnsiToTChar(szPath, tszPath, ARRAYSIZE(tszPath));
  428. return Channel_CreateILFromPath (tszPath, ppidl);
  429. #else
  430. return Channel_CreateILFromPath (szPath, ppidl);
  431. #endif
  432. }
  433. STDMETHODIMP CChannelMgr::InvalidateCdfCache(void)
  434. {
  435. InterlockedIncrement((LONG*)&g_dwCacheCount);
  436. return S_OK;
  437. }
  438. STDMETHODIMP CChannelMgr::PreUpdateChannelImage(
  439. LPCSTR pszPath,
  440. LPSTR pszHashItem,
  441. int* piIndex,
  442. UINT* puFlags,
  443. int* piImageIndex
  444. )
  445. {
  446. #ifdef UNICODE
  447. TCHAR tszPath[MAX_PATH];
  448. TCHAR tszHashItem[MAX_PATH];
  449. SHAnsiToTChar(pszPath, tszPath, ARRAYSIZE(tszPath));
  450. SHAnsiToTChar(pszHashItem, tszHashItem, ARRAYSIZE(tszHashItem));
  451. return ::PreUpdateChannelImage(tszPath, tszHashItem, piIndex, puFlags,
  452. piImageIndex);
  453. #else
  454. return ::PreUpdateChannelImage(pszPath, pszHashItem, piIndex, puFlags,
  455. piImageIndex);
  456. #endif
  457. }
  458. STDMETHODIMP CChannelMgr::UpdateChannelImage(
  459. LPCWSTR pszHashItem,
  460. int iIndex,
  461. UINT uFlags,
  462. int iImageIndex
  463. )
  464. {
  465. ::UpdateChannelImage(pszHashItem, iIndex, uFlags, iImageIndex);
  466. return S_OK;
  467. }
  468. STDMETHODIMP CChannelMgr::ShowChannel(
  469. IWebBrowser2 *pIWebBrowser2,
  470. LPWSTR pwszURL,
  471. HWND hwnd
  472. )
  473. {
  474. HRESULT hr;
  475. if (!pwszURL || !pIWebBrowser2)
  476. {
  477. hr = E_INVALIDARG;
  478. }
  479. else
  480. {
  481. hr = ::NavigateBrowser(pIWebBrowser2, pwszURL, hwnd);
  482. }
  483. return hr;
  484. }
  485. STDMETHODIMP CChannelMgr::IsChannelInstalled(LPCWSTR pwszURL)
  486. {
  487. return ::Channel_IsInstalled(pwszURL) ? S_OK : S_FALSE;
  488. }
  489. STDMETHODIMP CChannelMgr::AddAndSubscribe(HWND hwnd, LPCWSTR pwszURL,
  490. ISubscriptionMgr *pSubscriptionMgr)
  491. {
  492. return AddAndSubscribeEx2(hwnd, pwszURL, pSubscriptionMgr, FALSE);
  493. }
  494. STDMETHODIMP CChannelMgr::AddAndSubscribeEx2(HWND hwnd, LPCWSTR pwszURL,
  495. ISubscriptionMgr *pSubscriptionMgr,
  496. BOOL bAlwaysSubscribe)
  497. {
  498. HRESULT hr;
  499. BSTR bstrPreinstalled = NULL;
  500. HRESULT hrPreinstalled = IsChannelPreinstalled(pwszURL, &bstrPreinstalled);
  501. if (hrPreinstalled == S_OK)
  502. {
  503. RemovePreinstalledMapping(pwszURL);
  504. }
  505. WCHAR wszTitle[MAX_PATH];
  506. TASK_TRIGGER tt = {0};
  507. SUBSCRIPTIONINFO si = {0};
  508. BOOL fIsSoftware = FALSE;
  509. si.cbSize = sizeof(SUBSCRIPTIONINFO);
  510. si.fUpdateFlags |= SUBSINFO_SCHEDULE;
  511. si.schedule = SUBSSCHED_AUTO;
  512. si.pTrigger = (LPVOID)&tt;
  513. hr = DownloadMinCDF(hwnd, pwszURL, wszTitle, ARRAYSIZE(wszTitle), &si, &fIsSoftware);
  514. if (hr == S_OK)
  515. {
  516. DWORD dwFlags = 0;
  517. BOOL bInstalled = Channel_IsInstalled(pwszURL);
  518. if (bInstalled)
  519. {
  520. dwFlags |= CREATESUBS_ACTIVATE | CREATESUBS_FROMFAVORITES;
  521. }
  522. else
  523. {
  524. dwFlags |= CREATESUBS_ADDTOFAVORITES;
  525. }
  526. if (bAlwaysSubscribe || !bInstalled || (hrPreinstalled == S_OK))
  527. {
  528. if (!pSubscriptionMgr)
  529. {
  530. hr = CoCreateInstance(CLSID_SubscriptionMgr, NULL,
  531. CLSCTX_INPROC_SERVER, IID_ISubscriptionMgr,
  532. (void**)&pSubscriptionMgr);
  533. }
  534. else
  535. {
  536. pSubscriptionMgr->AddRef();
  537. }
  538. if (SUCCEEDED(hr))
  539. {
  540. hr = pSubscriptionMgr->CreateSubscription(hwnd,
  541. pwszURL,
  542. wszTitle,
  543. dwFlags,
  544. SUBSTYPE_CHANNEL,
  545. &si);
  546. // This will kill the one we may have CoCreated
  547. pSubscriptionMgr->Release();
  548. }
  549. }
  550. }
  551. if (hr != S_OK && hrPreinstalled == S_OK && bstrPreinstalled != NULL)
  552. {
  553. SetupPreinstalledMapping(pwszURL, bstrPreinstalled);
  554. }
  555. SysFreeString(bstrPreinstalled);
  556. return hr;
  557. }
  558. STDMETHODIMP CChannelMgr::WriteScreenSaverURL(LPCWSTR pwszURL, LPCWSTR pwszScreenSaverURL)
  559. {
  560. return Channel_WriteScreenSaverURL(pwszURL, pwszScreenSaverURL);
  561. }
  562. STDMETHODIMP CChannelMgr::RefreshScreenSaverURLs()
  563. {
  564. return Channel_RefreshScreenSaverURLs();
  565. }
  566. STDMETHODIMP CChannelMgr::DownloadMinCDF(HWND hwnd, LPCWSTR pwszURL,
  567. LPWSTR pwszTitle, DWORD cchTitle,
  568. SUBSCRIPTIONINFO *pSubInfo,
  569. BOOL *pfIsSoftware)
  570. {
  571. HRESULT hr;
  572. IXMLDocument* pIXMLDocument;
  573. IXMLElement* pIXMLElement;
  574. ASSERT(pSubInfo);
  575. ASSERT(pfIsSoftware);
  576. *pwszTitle = NULL;
  577. DLL_ForcePreloadDlls(PRELOAD_MSXML);
  578. hr = CoCreateInstance(CLSID_XMLDocument, NULL, CLSCTX_INPROC_SERVER,
  579. IID_IXMLDocument, (void**)&pIXMLDocument);
  580. if (SUCCEEDED(hr))
  581. {
  582. BOOL fStartedOffLine = IsGlobalOffline();
  583. BOOL fInformUserOfDownloadProblem = FALSE;
  584. SetGlobalOffline(FALSE);
  585. if (InternetAutodial(INTERNET_AUTODIAL_FORCE_ONLINE, 0))
  586. {
  587. if (!DownloadCdfUI(hwnd, pwszURL, pIXMLDocument))
  588. {
  589. hr = E_FAIL;
  590. fInformUserOfDownloadProblem = TRUE;
  591. }
  592. else
  593. {
  594. Channel_SendUpdateNotifications(pwszURL);
  595. LONG lDontCare;
  596. hr = XML_GetFirstChannelElement(pIXMLDocument, &pIXMLElement, &lDontCare);
  597. if (SUCCEEDED(hr))
  598. {
  599. *pfIsSoftware = XML_GetDocType(pIXMLDocument) == DOC_SOFTWAREUPDATE;
  600. XML_GetSubscriptionInfo(pIXMLElement, pSubInfo);
  601. BSTR bstrTitle = XML_GetAttribute(pIXMLElement, XML_TITLE);
  602. if (bstrTitle)
  603. {
  604. if (bstrTitle[0])
  605. {
  606. StrCpyNW(pwszTitle, bstrTitle, cchTitle);
  607. }
  608. else
  609. {
  610. if (StrCpyNW(pwszTitle, PathFindFileNameW(pwszURL), cchTitle))
  611. {
  612. PathRemoveExtensionW(pwszTitle);
  613. }
  614. else
  615. {
  616. hr = S_FALSE;
  617. }
  618. }
  619. SysFreeString(bstrTitle);
  620. }
  621. else
  622. {
  623. hr = E_OUTOFMEMORY;
  624. }
  625. pIXMLElement->Release();
  626. }
  627. }
  628. }
  629. else
  630. {
  631. hr = HRESULT_FROM_WIN32(GetLastError());
  632. fInformUserOfDownloadProblem = TRUE;
  633. }
  634. pIXMLDocument->Release();
  635. if (fStartedOffLine)
  636. {
  637. SetGlobalOffline(TRUE);
  638. }
  639. if (fInformUserOfDownloadProblem)
  640. {
  641. ASSERT(FAILED(hr));
  642. CDFMessageBox(hwnd, IDS_INFO_MUST_CONNECT, IDS_INFO_DLG_TITLE,
  643. MB_OK | MB_ICONINFORMATION);
  644. // Set return val to S_FALSE so the caller can distinguish between
  645. // errors which we've informed the user of and hard failures
  646. // such as out of memory, etc.
  647. hr = S_FALSE;
  648. }
  649. }
  650. return hr;
  651. }
  652. ////////////////////////////////////////////////////////////////////////////////
  653. //
  654. // *** Channel_RemoveURLMapping ***
  655. //
  656. // Description:
  657. // Removes the cache and registry settings that wininet uses to map the
  658. // given url to a local file.
  659. //
  660. ////////////////////////////////////////////////////////////////////////////////
  661. #define PRELOAD_REG_KEY \
  662. TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Cache\\Preload")
  663. void Channel_RemoveURLMapping(LPCTSTR pszURL)
  664. {
  665. DWORD cbcei = MAX_CACHE_ENTRY_INFO_SIZE;
  666. BYTE cei[MAX_CACHE_ENTRY_INFO_SIZE];
  667. LPINTERNET_CACHE_ENTRY_INFO pcei = (LPINTERNET_CACHE_ENTRY_INFO)cei;
  668. //
  669. // Look up the url in the cache
  670. //
  671. if (GetUrlCacheEntryInfoEx(pszURL, pcei, &cbcei, NULL, 0, NULL, 0))
  672. {
  673. //
  674. // see if it has a mapping because it is a preinstalled cache entry
  675. //
  676. if (pcei->CacheEntryType & INSTALLED_CACHE_ENTRY)
  677. {
  678. //
  679. // Clear the flag
  680. //
  681. pcei->CacheEntryType &= ~INSTALLED_CACHE_ENTRY;
  682. SetUrlCacheEntryInfo(pszURL, pcei, CACHE_ENTRY_ATTRIBUTE_FC);
  683. //
  684. // Now remove the mapping from the registry
  685. //
  686. HKEY hk;
  687. if (RegOpenKeyEx(HKEY_CURRENT_USER, PRELOAD_REG_KEY, 0, KEY_WRITE,
  688. &hk) == ERROR_SUCCESS)
  689. {
  690. RegDeleteValue(hk, pszURL);
  691. RegCloseKey(hk);
  692. }
  693. }
  694. }
  695. }
  696. #ifndef UNICODE
  697. //
  698. // widechar version of above routine
  699. //
  700. void Channel_RemoveURLMapping(LPCWSTR wszURL)
  701. {
  702. CHAR szURL[INTERNET_MAX_URL_LENGTH];
  703. if (SHUnicodeToTChar(wszURL, szURL, ARRAYSIZE(szURL)))
  704. {
  705. Channel_RemoveURLMapping(szURL);
  706. }
  707. }
  708. #endif
  709. // cheap lookup function to see if we are dealing with a preinstalled URL
  710. BOOL Channel_CheckURLMapping( LPCWSTR wszURL )
  711. {
  712. TCHAR szURL[INTERNET_MAX_URL_LENGTH];
  713. if (SHUnicodeToTChar(wszURL, szURL, ARRAYSIZE(szURL)))
  714. {
  715. HKEY hkey;
  716. if ( RegOpenKeyEx(HKEY_CURRENT_USER, PRELOAD_REG_KEY, 0, KEY_READ, &hkey) == ERROR_SUCCESS )
  717. {
  718. // check to see if the value exists for the URL....
  719. TCHAR szPath[MAX_PATH];
  720. DWORD cbSize = sizeof(szPath);
  721. LONG lRes = RegQueryValueEx( hkey, szURL, NULL, NULL, (LPBYTE) szPath, &cbSize );
  722. RegCloseKey( hkey );
  723. return (lRes == ERROR_SUCCESS );
  724. }
  725. }
  726. return FALSE;
  727. }
  728. ////////////////////////////////////////////////////////////////////////////////
  729. //
  730. // *** CChannelMgr::IsChannelPreinstalled ***
  731. //
  732. // Description:
  733. // Returns S_OK if the channel url has a preinstalled cache entry
  734. //
  735. ////////////////////////////////////////////////////////////////////////////////
  736. STDMETHODIMP CChannelMgr::IsChannelPreinstalled(LPCWSTR pwszURL, BSTR * bstrFile)
  737. {
  738. HRESULT hr = S_FALSE;
  739. TCHAR szURL[INTERNET_MAX_URL_LENGTH];
  740. if (SHUnicodeToTChar(pwszURL, szURL, ARRAYSIZE(szURL)))
  741. {
  742. DWORD cbcei = MAX_CACHE_ENTRY_INFO_SIZE;
  743. BYTE cei[MAX_CACHE_ENTRY_INFO_SIZE];
  744. LPINTERNET_CACHE_ENTRY_INFO pcei = (LPINTERNET_CACHE_ENTRY_INFO)cei;
  745. //
  746. // Look up the url in the cache
  747. //
  748. if (GetUrlCacheEntryInfoEx(szURL, pcei, &cbcei, NULL, 0, NULL, 0))
  749. {
  750. //
  751. // see if it has a mapping because it is a preinstalled cache entry
  752. //
  753. if (pcei->CacheEntryType & INSTALLED_CACHE_ENTRY)
  754. {
  755. //
  756. // Get a BSTR from the internet cache entry local file name
  757. //
  758. if (bstrFile)
  759. {
  760. WCHAR wszFile[MAX_PATH];
  761. SHTCharToUnicode(pcei->lpszLocalFileName, wszFile, ARRAYSIZE(wszFile));
  762. *bstrFile = SysAllocString(wszFile);
  763. }
  764. hr = S_OK;
  765. }
  766. }
  767. }
  768. return hr;
  769. }
  770. STDMETHODIMP CChannelMgr::RemovePreinstalledMapping(LPCWSTR pwszURL)
  771. {
  772. Channel_RemoveURLMapping(pwszURL);
  773. return S_OK;
  774. }
  775. STDMETHODIMP CChannelMgr::SetupPreinstalledMapping(LPCWSTR pwszURL, LPCWSTR pwszFile)
  776. {
  777. FILETIME ftZero = {0};
  778. CommitUrlCacheEntryW(pwszURL, pwszFile, ftZero, ftZero, INSTALLED_CACHE_ENTRY, NULL, 0, NULL, 0);
  779. //
  780. // Make sure that there isn't an in memory cached old version of this URL
  781. //
  782. #ifdef UNICODE
  783. Cache_RemoveItem(pwszURL);
  784. #else
  785. char szURL[INTERNET_MAX_URL_LENGTH];
  786. SHUnicodeToAnsi(pwszURL, szURL, ARRAYSIZE(szURL));
  787. Cache_RemoveItem(szURL);
  788. #endif
  789. return S_OK;
  790. }
  791. //
  792. // Create the special folder that can have a webview associated with it, and an
  793. // icon and a logo view.
  794. //
  795. HRESULT Channel_CreateSpecialFolder(
  796. LPCTSTR pszPath, // path to folder to create
  797. LPCTSTR pszURL, // url for webview
  798. LPCTSTR pszLogo, // [optional] path to logo
  799. LPCTSTR pszWideLogo, // [optional] path to wide logo
  800. LPCTSTR pszIcon, // [optional] path to icon file
  801. int nIconIndex // index to icon in above file
  802. )
  803. {
  804. //
  805. // First create the directory if it doesn't exist
  806. //
  807. if (!PathFileExists(pszPath))
  808. {
  809. if (Channel_CreateDirectory(pszPath) != 0)
  810. {
  811. return E_FAIL;
  812. }
  813. }
  814. //
  815. // Mark it as a SYSTEM folder
  816. //
  817. if (!SetFileAttributes(pszPath, FILE_ATTRIBUTE_SYSTEM))
  818. return E_FAIL;
  819. //
  820. // Make desktop.ini
  821. //
  822. TCHAR szDesktopIni[MAX_PATH];
  823. PathCombine(szDesktopIni, pszPath, TEXT("desktop.ini"));
  824. WritePrivateProfileString(NULL, NULL, NULL, szDesktopIni);
  825. //
  826. // Write ConfirmFileOp=0 to turn off shell warnings during file operations
  827. //
  828. EVAL(WritePrivateProfileString(
  829. TEXT(".ShellClassInfo"),
  830. TEXT("ConfirmFileOp"), TEXT("0"), szDesktopIni));
  831. //
  832. // Write the URL for this category folders webview
  833. //
  834. if (pszURL)
  835. {
  836. EVAL(WritePrivateProfileString(
  837. TEXT(".ShellClassInfo"),
  838. TEXT("URL"), pszURL, szDesktopIni));
  839. }
  840. //
  841. // Write the Logo for this channel if present
  842. //
  843. if (pszLogo)
  844. {
  845. EVAL(WritePrivateProfileString(
  846. TEXT(".ShellClassInfo"),
  847. TEXT("Logo"), pszLogo, szDesktopIni));
  848. }
  849. //
  850. // Write the WideLogo for this channel if present
  851. //
  852. if (pszWideLogo)
  853. {
  854. EVAL(WritePrivateProfileString(
  855. TEXT(".ShellClassInfo"),
  856. TEXT("WideLogo"), pszWideLogo, szDesktopIni));
  857. }
  858. //
  859. // Write the Icon URL for this category folder if present
  860. //
  861. if (pszIcon)
  862. {
  863. TCHAR szIconIndex[8]; // can handle 999999
  864. ASSERT(nIconIndex >= 0 && nIconIndex <= 999999); // sanity check
  865. wnsprintf(szIconIndex, ARRAYSIZE(szIconIndex), TEXT("%d"), nIconIndex);
  866. EVAL(WritePrivateProfileString(
  867. TEXT(".ShellClassInfo"),
  868. TEXT("IconIndex"), szIconIndex, szDesktopIni));
  869. EVAL(WritePrivateProfileString(
  870. TEXT(".ShellClassInfo"),
  871. TEXT("IconFile"), pszIcon, szDesktopIni));
  872. }
  873. //
  874. // Flush the buffers
  875. //
  876. WritePrivateProfileString(NULL, NULL, NULL, szDesktopIni);
  877. SetFileAttributes(szDesktopIni, FILE_ATTRIBUTE_HIDDEN);
  878. return S_OK;
  879. }
  880. //
  881. // Create the special channels folder
  882. //
  883. //
  884. // Channel folders are no longer created in IE5+
  885. //
  886. /*
  887. HRESULT Channel_CreateChannelFolder( XMLDOCTYPE xdt )
  888. {
  889. TCHAR szPath[MAX_PATH];
  890. if (SUCCEEDED(Channel_GetFolder(szPath, xdt)) && szPath[0] != 0)
  891. {
  892. //
  893. // Create a special folder with an icon that lives in the cdfview.dll
  894. //
  895. return Channel_CreateSpecialFolder(
  896. szPath, NULL, NULL, NULL, g_szModuleName, -IDI_CHANNELFOLDER);
  897. }
  898. else
  899. return E_FAIL;
  900. }
  901. */
  902. HRESULT Channel_GetBasePath(LPTSTR pszPath, int cch)
  903. {
  904. ASSERT(pszPath || 0 == cch);
  905. HRESULT hr = E_FAIL;
  906. HKEY hKey;
  907. DWORD dwLen = cch * sizeof(TCHAR);
  908. if (RegOpenKey(HKEY_CURRENT_USER, SHELLFOLDERS, &hKey) == ERROR_SUCCESS)
  909. {
  910. #ifndef UNIX
  911. if (RegQueryValueEx(hKey, TEXT("Favorites"), NULL, NULL,
  912. (LPBYTE)pszPath, &dwLen) == ERROR_SUCCESS)
  913. {
  914. hr = S_OK;
  915. }
  916. #else
  917. TCHAR szUnexpandPath[MAX_PATH+1];
  918. dwLen = MAX_PATH;
  919. if (RegQueryValueEx(hKey, TEXT("Favorites"), NULL, NULL,
  920. (LPBYTE)szUnexpandPath, &dwLen) == ERROR_SUCCESS)
  921. {
  922. hr = S_OK;
  923. }
  924. DWORD length = ExpandEnvironmentStrings((LPTSTR)szUnexpandPath,
  925. (LPTSTR)pszPath,
  926. cch);
  927. if (length == 0 || length > cch)
  928. hr = E_FAIL;
  929. #endif /* UNIX */
  930. RegCloseKey(hKey);
  931. }
  932. return hr;
  933. }
  934. BSTR Channel_GetFullPath(LPCWSTR pwszName)
  935. {
  936. ASSERT(pwszName);
  937. BSTR bstrRet = NULL;
  938. TCHAR szName[MAX_PATH];
  939. if (SHUnicodeToTChar(pwszName, szName, ARRAYSIZE(szName)))
  940. {
  941. TCHAR szPath[MAX_PATH];
  942. if (SUCCEEDED(Channel_GetFolder(szPath, DOC_CHANNEL)))
  943. {
  944. if (PathCombineCleanPath(szPath, szName))
  945. {
  946. WCHAR wszPath[MAX_PATH];
  947. if (SHTCharToUnicode(szPath, wszPath, ARRAYSIZE(wszPath)))
  948. {
  949. bstrRet = SysAllocString(wszPath);
  950. }
  951. }
  952. }
  953. }
  954. return bstrRet;
  955. }
  956. HRESULT Channel_GetFolder(LPTSTR pszPath, XMLDOCTYPE xdt )
  957. {
  958. TCHAR szFavs[MAX_PATH];
  959. TCHAR szChannel[MAX_PATH];
  960. ULONG cbChannel = sizeof(szChannel);
  961. HRESULT hr = E_FAIL;
  962. if (SUCCEEDED(Channel_GetBasePath(szFavs, ARRAYSIZE(szFavs))))
  963. {
  964. switch (xdt)
  965. {
  966. case DOC_CHANNEL:
  967. //
  968. // Get the potentially localized name of the Channel folder from the
  969. // registry if it is there. Otherwise just read it from the resource.
  970. // Then tack this on the favorites path.
  971. //
  972. if (ERROR_SUCCESS != SHRegGetUSValue(L"Software\\Microsoft\\Windows\\CurrentVersion",
  973. L"ChannelFolderName", NULL, (void*)szChannel,
  974. &cbChannel, TRUE, NULL, 0))
  975. {
  976. MLLoadString(IDS_CHANNEL_FOLDER, szChannel, ARRAYSIZE(szChannel));
  977. }
  978. break;
  979. case DOC_SOFTWAREUPDATE:
  980. MLLoadString(IDS_SOFTWAREUPDATE_FOLDER, szChannel, ARRAYSIZE(szChannel));
  981. break;
  982. }
  983. PathCombine(pszPath, szFavs, szChannel);
  984. //
  985. // If the channels folder doesn't exist create it now
  986. //
  987. if (!PathFileExists(pszPath))
  988. {
  989. //
  990. // In IE5+ use the favorites folder if the channels folder does not
  991. // exist.
  992. //
  993. StrCpy(pszPath, szFavs);
  994. //
  995. // Create special folder with an icon that lives in cdfview.dll
  996. //
  997. /*
  998. Channel_CreateSpecialFolder(
  999. pszPath, NULL, NULL, NULL, g_szModuleName, -IDI_CHANNELFOLDER);
  1000. */
  1001. }
  1002. hr = S_OK;
  1003. }
  1004. return hr;
  1005. }
  1006. // NOTE: This registry location and name is used by webcheck as well so do not
  1007. // change it here without updating webcheck.
  1008. const TCHAR c_szRegKeyWebcheck[] = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Webcheck");
  1009. const TCHAR c_szRegValueChannelGuide[] = TEXT("ChannelGuide");
  1010. HRESULT Channel_GetChannelGuide(LPTSTR pszPath, int cch)
  1011. {
  1012. ASSERT(pszPath || 0 == cch);
  1013. HRESULT hr = E_FAIL;
  1014. HKEY hKey;
  1015. DWORD dwLen = cch * sizeof(TCHAR);
  1016. if (RegOpenKey(HKEY_CURRENT_USER, c_szRegKeyWebcheck, &hKey) == ERROR_SUCCESS)
  1017. {
  1018. if (RegQueryValueEx(hKey, c_szRegValueChannelGuide, NULL, NULL,
  1019. (LPBYTE)pszPath, &dwLen) == ERROR_SUCCESS)
  1020. {
  1021. hr = S_OK;
  1022. }
  1023. RegCloseKey(hKey);
  1024. }
  1025. return hr;
  1026. }
  1027. //
  1028. // Channel_OrderChannel - Set the order of the new channel in the folder
  1029. //
  1030. void Channel_OrderItem(LPCTSTR szPath)
  1031. {
  1032. HRESULT hr;
  1033. BOOL bRet;
  1034. LPITEMIDLIST pidlParent = NULL, pidlChild = NULL;
  1035. IShellFolder *psfDesktop = NULL;
  1036. IShellFolder *psfParent = NULL;
  1037. IPersistFolder *pPF = NULL;
  1038. IOrderList *pOL = NULL;
  1039. HDPA hdpa = NULL;
  1040. int iChannel = -1; // Pick a negative index to see if we find it.
  1041. int iInsert = 0; // Assume we don't find the channel guide.
  1042. PORDERITEM poi;
  1043. // Get the full pidl of the new channel (ignore the pidlParent name)
  1044. hr = Channel_CreateILFromPath(szPath, &pidlParent);
  1045. if (FAILED(hr))
  1046. goto cleanup;
  1047. // Allocate a child pidl and make the parent pidl
  1048. pidlChild = ILClone(ILFindLastID(pidlParent));
  1049. if (!pidlChild)
  1050. goto cleanup;
  1051. bRet = ILRemoveLastID(pidlParent);
  1052. ASSERT(bRet);
  1053. // Get the IShellFolder of the parent by going through the
  1054. // desktop folder.
  1055. hr = SHGetDesktopFolder(&psfDesktop);
  1056. if (FAILED(hr))
  1057. goto cleanup;
  1058. hr = psfDesktop->BindToObject(pidlParent, NULL, IID_IShellFolder, (void**)&psfParent);
  1059. if (FAILED(hr))
  1060. goto cleanup;
  1061. // Get the order list of the parent.
  1062. hr = CoCreateInstance(CLSID_OrderListExport, NULL, CLSCTX_INPROC_SERVER, IID_IPersistFolder, (void**)&pPF);
  1063. if (FAILED(hr))
  1064. goto cleanup;
  1065. hr = pPF->Initialize(pidlParent);
  1066. if (FAILED(hr))
  1067. goto cleanup;
  1068. hr = pPF->QueryInterface(IID_IOrderList, (void**)&pOL);
  1069. if (FAILED(hr))
  1070. goto cleanup;
  1071. hr = pOL->GetOrderList(&hdpa);
  1072. // Create a DPA list if there wasn't one already.
  1073. if (!hdpa)
  1074. {
  1075. hdpa = DPA_Create(2);
  1076. if (!hdpa)
  1077. goto cleanup;
  1078. }
  1079. else
  1080. {
  1081. // First, get the channel guide pidl.
  1082. TCHAR szGuide[MAX_PATH];
  1083. WCHAR wzGuide[MAX_PATH];
  1084. LPITEMIDLIST pidlGuide = NULL;
  1085. if (SUCCEEDED(Channel_GetChannelGuide(szGuide, ARRAYSIZE(szGuide))))
  1086. {
  1087. if (SHTCharToUnicode(szGuide, wzGuide, ARRAYSIZE(wzGuide)))
  1088. {
  1089. ULONG ucch;
  1090. hr = psfParent->ParseDisplayName(NULL, NULL, wzGuide, &ucch, &pidlGuide, NULL);
  1091. ASSERT(!pidlGuide || SUCCEEDED(hr));
  1092. }
  1093. }
  1094. // Now do the search.
  1095. // Check to see if the channel is in the DPA list.
  1096. // Check to see if the channel guide is there and first.
  1097. int i = 0;
  1098. poi = (PORDERITEM)DPA_GetPtr(hdpa, i);
  1099. while (poi)
  1100. {
  1101. if (!psfParent->CompareIDs(0, pidlChild, poi->pidl))
  1102. iChannel = poi->nOrder;
  1103. if (pidlGuide && !psfParent->CompareIDs(0, pidlGuide, poi->pidl) && (poi->nOrder == 0))
  1104. iInsert = 1;
  1105. i++;
  1106. poi = (PORDERITEM)DPA_GetPtr(hdpa, i);
  1107. }
  1108. }
  1109. // If the channel pidl was not found, insert it at the end
  1110. if (iChannel < 0)
  1111. {
  1112. // Allocate an order item to insert
  1113. hr = pOL->AllocOrderItem(&poi, pidlChild);
  1114. if (SUCCEEDED(hr))
  1115. {
  1116. iChannel = DPA_InsertPtr(hdpa, 0x7fffffff, poi);
  1117. if (iChannel >= 0)
  1118. poi->nOrder = iChannel;
  1119. }
  1120. }
  1121. // Reorder the channels. The new channel is in the list at
  1122. // position iChannel. We're moving it to position iInsert.
  1123. if (iChannel >= 0)
  1124. {
  1125. int i = 0;
  1126. poi = (PORDERITEM)DPA_GetPtr(hdpa, i);
  1127. while (poi)
  1128. {
  1129. if (poi->nOrder == iChannel && iChannel >= iInsert)
  1130. poi->nOrder = iInsert;
  1131. else if (poi->nOrder >= iInsert && poi->nOrder < iChannel)
  1132. poi->nOrder++;
  1133. i++;
  1134. poi = (PORDERITEM)DPA_GetPtr(hdpa, i);
  1135. }
  1136. // Finally, set the order.
  1137. hr = pOL->SetOrderList(hdpa, psfParent);
  1138. ASSERT(SUCCEEDED(hr));
  1139. }
  1140. cleanup:
  1141. if (hdpa)
  1142. pOL->FreeOrderList(hdpa);
  1143. if (pOL)
  1144. pOL->Release();
  1145. if (pPF)
  1146. pPF->Release();
  1147. if (psfParent)
  1148. psfParent->Release();
  1149. if (psfDesktop)
  1150. psfDesktop->Release();
  1151. ILFree(pidlParent); // NULL is OK.
  1152. ILFree(pidlChild);
  1153. }
  1154. //
  1155. // AddChannel - Add a channel
  1156. //
  1157. HRESULT AddChannel(
  1158. LPCTSTR pszName,
  1159. LPCTSTR pszURL,
  1160. LPCTSTR pszLogo,
  1161. LPCTSTR pszWideLogo,
  1162. LPCTSTR pszIcon,
  1163. XMLDOCTYPE xdt )
  1164. {
  1165. HRESULT hr = S_OK;
  1166. BOOL fDirectoryAlreadyExisted = FALSE;
  1167. //
  1168. // Find the Channel directory
  1169. // Attempt to create folder if one doesn't exist
  1170. //
  1171. TCHAR szPath[MAX_PATH];
  1172. if (FAILED(Channel_GetFolder(szPath, xdt)))
  1173. {
  1174. return E_FAIL; // couldn't find Channel Folder or create empty one
  1175. }
  1176. // Cleanup each of the path components independently.
  1177. PathCombineCleanPath(szPath, pszName);
  1178. TraceMsg(TF_GENERAL, "Channel Path = %s", szPath);
  1179. //
  1180. // Make the new folder if it doesn't already exist
  1181. //
  1182. if (!PathFileExists(szPath))
  1183. {
  1184. if (Channel_CreateDirectory(szPath) != 0)
  1185. {
  1186. return E_FAIL;
  1187. }
  1188. }
  1189. else
  1190. {
  1191. fDirectoryAlreadyExisted = TRUE;
  1192. }
  1193. //
  1194. // Mark it as a SYSTEM folder
  1195. //
  1196. if (!SetFileAttributes(szPath, FILE_ATTRIBUTE_SYSTEM))
  1197. return E_FAIL;
  1198. //
  1199. // Add the channel to the registry database of all channels.
  1200. //
  1201. //if (FAILED(Reg_WriteChannel(szPath, pszURL)))
  1202. // return E_FAIL;
  1203. //
  1204. // Place the channel folder in the appropriate "order".
  1205. //
  1206. Channel_OrderItem(szPath);
  1207. // Build the CDFINI GUID string
  1208. //
  1209. TCHAR szCDFViewGUID[GUID_STR_LEN];
  1210. SHStringFromGUID(CLSID_CDFINI, szCDFViewGUID, ARRAYSIZE(szCDFViewGUID));
  1211. //
  1212. // Make desktop.ini
  1213. //
  1214. PathCombine(szPath, szPath, TEXT("desktop.ini"));
  1215. TraceMsg(TF_GENERAL, "INI path = %s", szPath);
  1216. WritePrivateProfileString(NULL, NULL, NULL, szPath); // Create desktop.ini
  1217. //
  1218. // Write in the CDFViewer GUID
  1219. //
  1220. EVAL(WritePrivateProfileString(
  1221. TEXT(".ShellClassInfo"),
  1222. TEXT("CLSID"), szCDFViewGUID, szPath));
  1223. //
  1224. // Write ConfirmFileOp=0 to turn off shell warnings during file operations
  1225. //
  1226. EVAL(WritePrivateProfileString(
  1227. TEXT(".ShellClassInfo"),
  1228. TEXT("ConfirmFileOp"), TEXT("0"), szPath));
  1229. //
  1230. // Write the actual URL for this channel
  1231. //
  1232. EVAL(WritePrivateProfileString(
  1233. TEXT("Channel"),
  1234. TEXT("CDFURL"), pszURL, szPath));
  1235. Channel_GetAndWriteScreenSaverURL(pszURL, szPath);
  1236. //
  1237. // Write the default Logo URL for this channel if present
  1238. //
  1239. if (pszLogo)
  1240. {
  1241. EVAL(WritePrivateProfileString(
  1242. TEXT("Channel"),
  1243. TEXT("Logo"), pszLogo, szPath));
  1244. }
  1245. //
  1246. // Write the default WideLogo URL for this channel if present
  1247. //
  1248. if (pszWideLogo)
  1249. {
  1250. EVAL(WritePrivateProfileString(
  1251. TEXT("Channel"),
  1252. TEXT("WideLogo"), pszWideLogo, szPath));
  1253. }
  1254. //
  1255. // Write the default Icon URL for this channel if present
  1256. //
  1257. if (pszIcon)
  1258. {
  1259. EVAL(WritePrivateProfileString(
  1260. TEXT("Channel"),
  1261. TEXT("Icon"), pszIcon, szPath));
  1262. }
  1263. //
  1264. // Flush the buffers
  1265. //
  1266. WritePrivateProfileString(NULL, NULL, NULL, szPath); // Create desktop.ini
  1267. EVAL(SetFileAttributes(szPath, FILE_ATTRIBUTE_HIDDEN));
  1268. //
  1269. // Notify the system that a new item has been added, or if the item
  1270. // already existed just send an UPDATEDIR notification
  1271. //
  1272. PathRemoveFileSpec(szPath);
  1273. if (fDirectoryAlreadyExisted)
  1274. {
  1275. SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_PATH, (void*)szPath, NULL);
  1276. }
  1277. else
  1278. {
  1279. SHChangeNotify(SHCNE_MKDIR, SHCNF_PATH, (void*)szPath, NULL);
  1280. }
  1281. return S_OK;
  1282. }
  1283. //
  1284. // DeleteChannel - Deletes a channel by name
  1285. //
  1286. // Returns
  1287. // S_OK if channel existed and successfully deleted
  1288. // S_FALSE if channel didn't exist.
  1289. // E_FAIL else.
  1290. //
  1291. HRESULT DeleteChannel(LPTSTR szName)
  1292. {
  1293. TCHAR szFolderPath[MAX_PATH];
  1294. TCHAR szDesktopIniPath[MAX_PATH];
  1295. if (PathIsRelative(szName))
  1296. {
  1297. //
  1298. // Find the Channel directory
  1299. // Note don't create if doesn't exist
  1300. //
  1301. // FEATURE: this won't find app channels.
  1302. if (FAILED(Channel_GetFolder(szFolderPath, DOC_CHANNEL)))
  1303. {
  1304. return S_FALSE; // couldn't find Channel Folder so channel can't exist
  1305. }
  1306. // Cleanup each of the path components independently.
  1307. PathCombineCleanPath(szFolderPath, szName);
  1308. TraceMsg(TF_GENERAL, "Delete Channel Path = %s", szFolderPath);
  1309. }
  1310. else
  1311. {
  1312. // Assume absolute paths were retrieved by enumeration and
  1313. // therefore don't need to be "cleaned".
  1314. StrCpyN(szFolderPath, szName, ARRAYSIZE(szFolderPath));
  1315. }
  1316. // Create the desktop.ini path
  1317. PathCombine(szDesktopIniPath, szFolderPath, TEXT("desktop.ini"));
  1318. // Find URL to CDF from desktop.ini
  1319. TCHAR szCDFURL[INTERNET_MAX_URL_LENGTH];
  1320. GetPrivateProfileString(TEXT("Channel"), TEXT("CDFURL"), TEXT(""), szCDFURL, ARRAYSIZE(szCDFURL), szDesktopIniPath);
  1321. // Remove the URL from the cache preload registry key
  1322. HKEY hkeyPreload;
  1323. LONG lRet = RegOpenKeyEx(HKEY_CURRENT_USER, c_szRegKeyCachePreload, 0, KEY_WRITE, &hkeyPreload);
  1324. if (ERROR_SUCCESS == lRet)
  1325. {
  1326. lRet = RegDeleteValue(hkeyPreload, szCDFURL);
  1327. lRet = RegCloseKey(hkeyPreload);
  1328. ASSERT(ERROR_SUCCESS == lRet);
  1329. }
  1330. if (
  1331. !DeleteFile(szDesktopIniPath)
  1332. ||
  1333. !SetFileAttributes(szFolderPath, FILE_ATTRIBUTE_NORMAL)
  1334. ||
  1335. //
  1336. // REVIEW: should change this to delete all contents of channel folder
  1337. // incase other files get stored there in the future.
  1338. //
  1339. !RemoveDirectory(szFolderPath)
  1340. )
  1341. {
  1342. return S_FALSE;
  1343. }
  1344. return S_OK;
  1345. }
  1346. //
  1347. // CountChannels - Counts the number of channels
  1348. //
  1349. // Returns the count
  1350. //
  1351. DWORD CountChannels(void)
  1352. {
  1353. DWORD cChannels = 0;
  1354. IEnumChannels *pEnum = (IEnumChannels *) new CChannelEnum(CHANENUM_CHANNELFOLDER, NULL);
  1355. if (pEnum)
  1356. {
  1357. CHANNELENUMINFO cei;
  1358. while (S_OK == pEnum->Next(1, &cei, NULL))
  1359. {
  1360. cChannels++;
  1361. }
  1362. pEnum->Release();
  1363. }
  1364. return cChannels;
  1365. }
  1366. //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
  1367. //
  1368. // *** OpenChannel ***
  1369. //
  1370. //
  1371. // Description:
  1372. // Opens a new browser and selects the given channel
  1373. //
  1374. // Parameters:
  1375. // [In] hwndParent - The owner hwnd.
  1376. // [In] hinst - The hinstance for this process.
  1377. // [In] pszCmdLine - The local path to the cdf file. This will be the path
  1378. // to the file in the cache if the cdf came from the net.
  1379. // [In] nShow - ShowWindow parameter.
  1380. //
  1381. // Return:
  1382. // None.
  1383. //
  1384. // Comments:
  1385. // This is the implementation for the context menu "Open Channel" command.
  1386. // It gets invoke via RunDll32.exe.
  1387. //
  1388. ////////////////////////////////////////////////////////////////////////////////
  1389. EXTERN_C
  1390. STDAPI_(void)
  1391. OpenChannel(
  1392. HWND hwndParent,
  1393. HINSTANCE hinst,
  1394. LPSTR pszCmdLine,
  1395. int nShow
  1396. )
  1397. {
  1398. WCHAR wszPath[INTERNET_MAX_URL_LENGTH];
  1399. if (MultiByteToWideChar(CP_ACP, 0, pszCmdLine, -1, wszPath,
  1400. ARRAYSIZE(wszPath)))
  1401. {
  1402. OpenChannelHelper(wszPath, hwndParent);
  1403. }
  1404. return;
  1405. }
  1406. //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
  1407. //
  1408. // *** Subscribe ***
  1409. //
  1410. //
  1411. // Description:
  1412. // Takes the given cdf through the user subscription path.
  1413. //
  1414. // Parameters:
  1415. // [In] hwndParent - The owner hwnd.
  1416. // [In] hinst - The hinstance for this process.
  1417. // [In] pszCmdLine - The local path to the cdf file. This will be the path
  1418. // to the file in the cache if the cdf came from the net.
  1419. // [In] nShow - ShowWindow parameter.
  1420. //
  1421. // Return:
  1422. // None.
  1423. //
  1424. // Comments:
  1425. // This is the implementation of the context menu "Subscribe" command. It
  1426. // gets invoke via rundll32.exe.
  1427. //
  1428. // This function handles channel and desktop component cdfs.
  1429. //
  1430. ////////////////////////////////////////////////////////////////////////////////
  1431. EXTERN_C
  1432. STDAPI_(void)
  1433. Subscribe(
  1434. HWND hwndParent,
  1435. HINSTANCE hinst,
  1436. LPSTR pszCmdLine,
  1437. int nShow
  1438. )
  1439. {
  1440. WCHAR wszPath[INTERNET_MAX_URL_LENGTH];
  1441. if (MultiByteToWideChar(CP_ACP, 0, pszCmdLine, -1, wszPath,
  1442. ARRAYSIZE(wszPath)))
  1443. {
  1444. SubscribeToCDF(hwndParent, wszPath, STC_ALL);
  1445. }
  1446. return;
  1447. }
  1448. //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
  1449. //
  1450. // *** ParseDesktopComponent ***
  1451. //
  1452. //
  1453. // Description:
  1454. // Fills an information structure for a desktop component and optionally
  1455. // allows the user to subscribe to the component.
  1456. //
  1457. // Parameters:
  1458. // [In] hwndOwner - The owner hwnd. If NULL there is no attempt to
  1459. // subscribe to this URL.
  1460. // [In] wszURL - The URL to the desktop component cdf.
  1461. // [Out] pInfo - A pointer that receives desktop component information
  1462. // that is read from the cdf.
  1463. //
  1464. // Return:
  1465. // S_OK if the desktop info could be read.
  1466. // S_FALSE if the user hits cancel
  1467. // E_FAIL otherwise.
  1468. //
  1469. // Comments:
  1470. // This function is used by the desktop component property pages. It may
  1471. // create a subscription to the component but unlike Subscribe, it will
  1472. // not add a desktop component to the system. Creating the component is
  1473. // left to the desktop component property pages.
  1474. //
  1475. ////////////////////////////////////////////////////////////////////////////////
  1476. EXTERN_C
  1477. STDAPI
  1478. ParseDesktopComponent(
  1479. HWND hwndOwner,
  1480. LPWSTR wszURL,
  1481. COMPONENT* pInfo
  1482. )
  1483. {
  1484. HRESULT hr;
  1485. hr = CoInitialize(NULL);
  1486. if (SUCCEEDED(hr))
  1487. {
  1488. CCdfView* pCCdfView = new CCdfView;
  1489. if (pCCdfView)
  1490. {
  1491. hr = pCCdfView->Load(wszURL, 0);
  1492. if (SUCCEEDED(hr))
  1493. {
  1494. IXMLDocument* pIXMLDocument;
  1495. TraceMsg(TF_CDFPARSE, "ParseDesktopComponent");
  1496. TCHAR szFile[MAX_PATH];
  1497. TCHAR szURL[INTERNET_MAX_URL_LENGTH];
  1498. SHUnicodeToTChar(wszURL, szURL, ARRAYSIZE(szURL));
  1499. hr = URLDownloadToCacheFile(NULL, szURL, szFile,
  1500. ARRAYSIZE(szFile), 0, NULL);
  1501. if (SUCCEEDED(hr))
  1502. {
  1503. hr = pCCdfView->ParseCdf(NULL, &pIXMLDocument, PARSE_LOCAL);
  1504. if (SUCCEEDED(hr))
  1505. {
  1506. ASSERT(pIXMLDocument);
  1507. if (DOC_DESKTOPCOMPONENT == XML_GetDocType(pIXMLDocument))
  1508. {
  1509. BOOL fOk = FALSE;
  1510. if (hwndOwner)
  1511. {
  1512. fOk = SubscriptionHelper(pIXMLDocument, hwndOwner,
  1513. SUBSTYPE_DESKTOPCHANNEL,
  1514. SUBSACTION_SUBSCRIBEONLY,
  1515. wszURL, DOC_DESKTOPCOMPONENT, NULL);
  1516. }
  1517. if (fOk)
  1518. {
  1519. if(SUCCEEDED(hr = XML_GetDesktopComponentInfo(pIXMLDocument, pInfo)) &&
  1520. !pInfo->wszSubscribedURL[0])
  1521. {
  1522. // Since XML_GetDesktopComponentInfo did not fillout the SubscribedURL
  1523. // field (because the CDF file didn't have a SELF tag), we need to
  1524. // fill it with what was really subscribed to (the URL for CDF file itself)
  1525. StrCpyNW(pInfo->wszSubscribedURL, wszURL, ARRAYSIZE(pInfo->wszSubscribedURL));
  1526. }
  1527. }
  1528. else
  1529. hr = S_FALSE;
  1530. }
  1531. else
  1532. {
  1533. hr = E_FAIL;
  1534. }
  1535. pIXMLDocument->Release();
  1536. }
  1537. }
  1538. }
  1539. pCCdfView->Release();
  1540. }
  1541. }
  1542. return hr;
  1543. }
  1544. //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
  1545. //
  1546. // *** SubscribeToCDF ***
  1547. //
  1548. //
  1549. // Description:
  1550. // Subscribes to the given cdf.
  1551. //
  1552. // Parameters:
  1553. // [In] hwndOwner - The owner hwnd. Used to display the subscription
  1554. // wizard.
  1555. // [In] wszURL - An url to the cdf.
  1556. // [In] dwFlags - The type of cdf the caller wants to subscribe to.
  1557. // STC_CHANNEL, STC_DESKTOPCOMPONENT or STC_ALL.
  1558. //
  1559. // Return:
  1560. // S_OK if the subscription worked and the user subscribed.
  1561. // S_FALSE if the subscription UI appeared but the user decided not to
  1562. // subscribe.
  1563. // E_INVALIDARG if the cdf couldn't be opened or parsed.
  1564. // E_ACCESSDENIED if the cdf file doesn't match the type specified in
  1565. // dwFlags.
  1566. // E_FAIL on any other errors.
  1567. //
  1568. // Comments:
  1569. // Private API. Currently called by desktop component drop handler.
  1570. //
  1571. ////////////////////////////////////////////////////////////////////////////////
  1572. EXTERN_C
  1573. STDAPI
  1574. SubscribeToCDF(
  1575. HWND hwndOwner,
  1576. LPWSTR wszURL,
  1577. DWORD dwFlags
  1578. )
  1579. {
  1580. HRESULT hr;
  1581. hr = CoInitialize(NULL);
  1582. if (SUCCEEDED(hr))
  1583. {
  1584. CCdfView* pCCdfView = new CCdfView;
  1585. if (pCCdfView)
  1586. {
  1587. hr = pCCdfView->Load(wszURL, 0);
  1588. if (SUCCEEDED(hr))
  1589. {
  1590. IXMLDocument* pIXMLDocument;
  1591. TraceMsg(TF_CDFPARSE, "SubscribeToCDF");
  1592. hr = pCCdfView->ParseCdf(NULL, &pIXMLDocument, PARSE_LOCAL);
  1593. if (SUCCEEDED(hr))
  1594. {
  1595. ASSERT(pIXMLDocument);
  1596. XMLDOCTYPE xdt = XML_GetDocType(pIXMLDocument);
  1597. switch(xdt)
  1598. {
  1599. case DOC_CHANNEL:
  1600. case DOC_SOFTWAREUPDATE:
  1601. // Admins can disallow adding channels and limit
  1602. // the number of installed channels.
  1603. if ((dwFlags & STC_CHANNEL) &&
  1604. !SHRestricted2W(REST_NoAddingChannels, wszURL, 0) &&
  1605. (!SHRestricted2W(REST_MaxChannelCount, NULL, 0) ||
  1606. (CountChannels() < SHRestricted2W(REST_MaxChannelCount, NULL, 0))))
  1607. {
  1608. if (SubscriptionHelper(pIXMLDocument, hwndOwner,
  1609. SUBSTYPE_CHANNEL,
  1610. SUBSACTION_ADDADDITIONALCOMPONENTS,
  1611. wszURL, xdt, NULL))
  1612. {
  1613. OpenChannelHelper(wszURL, hwndOwner);
  1614. hr = S_OK;
  1615. }
  1616. else
  1617. {
  1618. hr = S_FALSE;
  1619. }
  1620. }
  1621. else
  1622. {
  1623. hr = E_ACCESSDENIED;
  1624. }
  1625. break;
  1626. case DOC_DESKTOPCOMPONENT:
  1627. #ifndef UNIX
  1628. if (hwndOwner &&
  1629. (WhichPlatform() != PLATFORM_INTEGRATED))
  1630. #else
  1631. /* No Active Desktop on Unix */
  1632. if (0)
  1633. #endif /* UNIX */
  1634. {
  1635. TCHAR szText[MAX_PATH];
  1636. TCHAR szTitle[MAX_PATH];
  1637. MLLoadString(IDS_BROWSERONLY_DLG_TEXT,
  1638. szText, ARRAYSIZE(szText));
  1639. MLLoadString(IDS_BROWSERONLY_DLG_TITLE,
  1640. szTitle, ARRAYSIZE(szTitle));
  1641. MessageBox(hwndOwner, szText, szTitle, MB_OK);
  1642. }
  1643. else if (dwFlags & STC_DESKTOPCOMPONENT)
  1644. {
  1645. if (SubscriptionHelper(pIXMLDocument, hwndOwner,
  1646. SUBSTYPE_DESKTOPCHANNEL,
  1647. SUBSACTION_ADDADDITIONALCOMPONENTS,
  1648. wszURL,
  1649. DOC_DESKTOPCOMPONENT, NULL))
  1650. {
  1651. hr = S_OK;
  1652. }
  1653. else
  1654. {
  1655. hr = S_FALSE;
  1656. }
  1657. }
  1658. else
  1659. {
  1660. hr = E_ACCESSDENIED;
  1661. }
  1662. break;
  1663. case DOC_UNKNOWN:
  1664. //If it is NOT a cdfFile, then we get DOC_UNKNOWN. We must return error
  1665. // here sothat the caller knows that this is NOT a cdffile.
  1666. hr = E_INVALIDARG;
  1667. break;
  1668. default:
  1669. break;
  1670. }
  1671. pIXMLDocument->Release();
  1672. }
  1673. else
  1674. {
  1675. hr = E_INVALIDARG;
  1676. }
  1677. }
  1678. pCCdfView->Release();
  1679. }
  1680. CoUninitialize();
  1681. }
  1682. return hr;
  1683. }
  1684. //
  1685. // Utility functions.
  1686. //
  1687. //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
  1688. //
  1689. // *** OpenChannelHelper ***
  1690. //
  1691. //
  1692. // Description:
  1693. // Opens the browser with the wszURL channel selected.
  1694. //
  1695. // Parameters:
  1696. // [In] wszURL - The URL of the cdf file to display.
  1697. // [In] hwndOwner - The owning hwnd for error messages. Can be NULL.
  1698. //
  1699. // Return:
  1700. // S_OK if the browser was opened.
  1701. // E_FAIL otherwise.
  1702. //
  1703. // Comments:
  1704. //
  1705. //
  1706. ////////////////////////////////////////////////////////////////////////////////
  1707. HRESULT
  1708. OpenChannelHelper(
  1709. LPWSTR wszURL,
  1710. HWND hwndOwner
  1711. )
  1712. {
  1713. //
  1714. // REVIEW: Handle non-channel cdfs.
  1715. //
  1716. HRESULT hr;
  1717. hr = CoInitialize(NULL);
  1718. if (SUCCEEDED(hr))
  1719. {
  1720. IWebBrowser2* pIWebBrowser2;
  1721. hr = CoCreateInstance(CLSID_InternetExplorer, NULL, CLSCTX_LOCAL_SERVER,
  1722. IID_IWebBrowser2, (void**)&pIWebBrowser2);
  1723. if (SUCCEEDED(hr))
  1724. {
  1725. ASSERT(pIWebBrowser2);
  1726. //
  1727. // Navigate to the root url of the cdf ref'd in wszURL
  1728. //
  1729. hr = NavigateBrowser(pIWebBrowser2, wszURL, hwndOwner);
  1730. pIWebBrowser2->put_Visible(VARIANT_TRUE);
  1731. pIWebBrowser2->Release();
  1732. }
  1733. CoUninitialize();
  1734. }
  1735. return hr;
  1736. }
  1737. ////////////////////////////////////////////////////////////////////////////////
  1738. //
  1739. // *** ShowChannelPane
  1740. //
  1741. // Description - shows the channel pane for the given web browser object
  1742. //
  1743. ////////////////////////////////////////////////////////////////////////////////
  1744. HRESULT
  1745. ShowChannelPane(
  1746. IWebBrowser2* pIWebBrowser2
  1747. )
  1748. {
  1749. HRESULT hr;
  1750. VARIANT guid;
  1751. VARIANT empty = {0};
  1752. BSTR bstrGuid;
  1753. TCHAR szGuid[GUID_STR_LEN];
  1754. WCHAR wszGuid[GUID_STR_LEN];
  1755. if (!SHRestricted2W(REST_NoChannelUI, NULL, 0))
  1756. {
  1757. SHStringFromGUID(CLSID_FavBand, szGuid, ARRAYSIZE(szGuid));
  1758. SHTCharToUnicode(szGuid, wszGuid, ARRAYSIZE(wszGuid));
  1759. if ((bstrGuid = SysAllocString(wszGuid)) == NULL)
  1760. return E_OUTOFMEMORY;
  1761. guid.vt = VT_BSTR;
  1762. guid.bstrVal = bstrGuid;
  1763. hr = pIWebBrowser2->ShowBrowserBar(&guid, &empty, &empty);
  1764. SysFreeString(bstrGuid);
  1765. }
  1766. else
  1767. {
  1768. hr = E_FAIL;
  1769. }
  1770. return hr;
  1771. }
  1772. //
  1773. // These routines are only needed if we want to pidl a variant pidl for
  1774. // navigating the ChannelPane to a specific pidl
  1775. //
  1776. SAFEARRAY * MakeSafeArrayFromData(const void * pData,DWORD cbData)
  1777. {
  1778. SAFEARRAY * psa;
  1779. if (!pData || 0 == cbData)
  1780. return NULL; // nothing to do
  1781. // create a one-dimensional safe array
  1782. psa = SafeArrayCreateVector(VT_UI1,0,cbData);
  1783. ASSERT(psa);
  1784. if (psa) {
  1785. // copy data into the area in safe array reserved for data
  1786. // Note we party directly on the pointer instead of using locking/
  1787. // unlocking functions. Since we just created this and no one
  1788. // else could possibly know about it or be using it, this is OK.
  1789. ASSERT(psa->pvData);
  1790. memcpy(psa->pvData,pData,cbData);
  1791. }
  1792. return psa;
  1793. }
  1794. /************************************************************\
  1795. FUNCTION: InitVARIANTFromPidl
  1796. PARAMETER:
  1797. pvar - Allocated by caller and filled in by this function.
  1798. pidl - Allocated by caller and caller needs to free.
  1799. DESCRIPTION:
  1800. This function will take the PIDL parameter and COPY it
  1801. into the Variant data structure. This allows the pidl
  1802. to be freed and the pvar to be used later, however, it
  1803. is necessary to call VariantClear(pvar) to free memory
  1804. that this function allocates.
  1805. \************************************************************/
  1806. BOOL InitVARIANTFromPidl(VARIANT* pvar, LPCITEMIDLIST pidl)
  1807. {
  1808. UINT cb = ILGetSize(pidl);
  1809. SAFEARRAY* psa = MakeSafeArrayFromData((const void *)pidl, cb);
  1810. if (psa) {
  1811. ASSERT(psa->cDims == 1);
  1812. // ASSERT(psa->cbElements == cb);
  1813. ASSERT(ILGetSize((LPCITEMIDLIST)psa->pvData)==cb);
  1814. VariantInit(pvar);
  1815. pvar->vt = VT_ARRAY|VT_UI1;
  1816. pvar->parray = psa;
  1817. return TRUE;
  1818. }
  1819. return FALSE;
  1820. }
  1821. //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
  1822. //
  1823. // *** NavigateBrowser ***
  1824. //
  1825. //
  1826. // Description:
  1827. // Navigate the browser to the correct URL for the given cdf.
  1828. //
  1829. // Parameters:
  1830. // [In] IWebBrowser2 - The browser top naviagte.
  1831. // [In] szwURL - The path to the cdf file.
  1832. // [In] hwnd - The wner hwnd.
  1833. //
  1834. // Return:
  1835. // S_OK if the cdf file was parsed and the browser naviagted to teh URL.
  1836. // E_FAIL otherwise.
  1837. //
  1838. // Comments:
  1839. // Read the href of the first CHANNEL tag in the cfd file and navigate
  1840. // the browser to this href.
  1841. //
  1842. ////////////////////////////////////////////////////////////////////////////////
  1843. HRESULT
  1844. NavigateBrowser(
  1845. IWebBrowser2* pIWebBrowser2,
  1846. LPWSTR wszURL,
  1847. HWND hwnd
  1848. )
  1849. {
  1850. ASSERT(pIWebBrowser2);
  1851. ASSERT(wszURL);
  1852. ASSERT(*wszURL != 0);
  1853. HRESULT hr = E_FAIL;
  1854. //
  1855. // Try to navigate to the title page.
  1856. //
  1857. CCdfView* pCCdfView = new CCdfView;
  1858. if (pCCdfView)
  1859. {
  1860. hr = pCCdfView->Load(wszURL, 0);
  1861. if (SUCCEEDED(hr))
  1862. {
  1863. IXMLDocument* pIXMLDocument = NULL;
  1864. TraceMsg(TF_CDFPARSE, "NavigateBrowser");
  1865. BOOL fIsURLChannelShortcut = PathIsDirectoryW(wszURL);
  1866. hr = pCCdfView->ParseCdf(NULL, &pIXMLDocument, PARSE_LOCAL | PARSE_REMOVEGLEAM);
  1867. if (SUCCEEDED(hr))
  1868. {
  1869. ASSERT(pIXMLDocument);
  1870. //
  1871. // Iff the CDF parsed correctly then show the channel pane
  1872. //
  1873. // pIWebBrowser2->put_TheaterMode(VARIANT_TRUE);
  1874. pIWebBrowser2->put_Visible(VARIANT_TRUE);
  1875. IXMLElement* pIXMLElement;
  1876. LONG nIndex;
  1877. hr = XML_GetFirstChannelElement(pIXMLDocument,
  1878. &pIXMLElement, &nIndex);
  1879. if (SUCCEEDED(hr))
  1880. {
  1881. ASSERT(pIXMLElement);
  1882. BSTR bstrURL = XML_GetAttribute(pIXMLElement, XML_HREF);
  1883. if (bstrURL && *bstrURL)
  1884. {
  1885. if (!fIsURLChannelShortcut)
  1886. {
  1887. LPOLESTR pszPath = Channel_GetChannelPanePath(wszURL);
  1888. if (pszPath)
  1889. {
  1890. if (SUCCEEDED(ShowChannelPane(pIWebBrowser2)))
  1891. NavigateChannelPane(pIWebBrowser2, pszPath);
  1892. CoTaskMemFree(pszPath);
  1893. }
  1894. }
  1895. else
  1896. {
  1897. TCHAR szChanDir[MAX_PATH];
  1898. if (SUCCEEDED(Channel_GetFolder(szChanDir,
  1899. DOC_CHANNEL)))
  1900. {
  1901. WCHAR wszChanDir[MAX_PATH];
  1902. if (SHTCharToUnicode(szChanDir, wszChanDir,
  1903. ARRAYSIZE(wszChanDir)))
  1904. {
  1905. if (PathIsPrefixW(wszChanDir, wszURL))
  1906. {
  1907. if (SUCCEEDED(ShowChannelPane(
  1908. pIWebBrowser2)))
  1909. {
  1910. NavigateChannelPane(pIWebBrowser2,
  1911. wszURL);
  1912. }
  1913. }
  1914. }
  1915. }
  1916. }
  1917. VARIANT vNull = {0};
  1918. VARIANT vTargetURL;
  1919. vTargetURL.vt = VT_BSTR;
  1920. vTargetURL.bstrVal = bstrURL;
  1921. //
  1922. // Nav the main browser pain to the target URL
  1923. //
  1924. hr = pIWebBrowser2->Navigate2(&vTargetURL, &vNull,
  1925. &vNull, &vNull, &vNull);
  1926. }
  1927. if (bstrURL)
  1928. SysFreeString(bstrURL);
  1929. pIXMLElement->Release();
  1930. }
  1931. }
  1932. else if (OLE_E_NOCACHE == hr)
  1933. {
  1934. VARIANT vNull = {0};
  1935. VARIANT vTargetURL;
  1936. if (!fIsURLChannelShortcut)
  1937. {
  1938. vTargetURL.bstrVal = SysAllocString(wszURL);
  1939. }
  1940. else
  1941. {
  1942. vTargetURL.bstrVal = pCCdfView->ReadFromIni(TSTR_INI_URL);
  1943. }
  1944. if (vTargetURL.bstrVal)
  1945. {
  1946. vTargetURL.vt = VT_BSTR;
  1947. //
  1948. // Nav the main browser pain to the target URL
  1949. //
  1950. hr = pIWebBrowser2->Navigate2(&vTargetURL, &vNull, &vNull,
  1951. &vNull, &vNull);
  1952. SysFreeString(vTargetURL.bstrVal);
  1953. }
  1954. }
  1955. if (pIXMLDocument)
  1956. pIXMLDocument->Release();
  1957. }
  1958. pCCdfView->Release();
  1959. }
  1960. return hr;
  1961. }
  1962. //
  1963. // Navigate the channel pane to the given channel.
  1964. //
  1965. HRESULT
  1966. NavigateChannelPane(
  1967. IWebBrowser2* pIWebBrowser2,
  1968. LPCWSTR pwszPath
  1969. )
  1970. {
  1971. ASSERT(pIWebBrowser2);
  1972. HRESULT hr = E_FAIL;
  1973. if (pwszPath)
  1974. {
  1975. TCHAR szPath[MAX_PATH];
  1976. if (SHUnicodeToTChar(pwszPath, szPath, ARRAYSIZE(szPath)))
  1977. {
  1978. LPITEMIDLIST pidl;
  1979. if (SUCCEEDED(Channel_CreateILFromPath(szPath, &pidl)))
  1980. {
  1981. ASSERT(pidl);
  1982. VARIANT varPath;
  1983. if (InitVARIANTFromPidl(&varPath, pidl))
  1984. {
  1985. VARIANT varNull = {0};
  1986. VARIANT varFlags;
  1987. varFlags.vt = VT_I4;
  1988. varFlags.lVal = navBrowserBar;
  1989. hr = pIWebBrowser2->Navigate2(&varPath, &varFlags,
  1990. &varNull, &varNull,
  1991. &varNull);
  1992. VariantClear(&varPath);
  1993. }
  1994. ILFree(pidl);
  1995. }
  1996. }
  1997. }
  1998. return hr;
  1999. }
  2000. //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
  2001. //
  2002. // *** SubscriptionHelper ***
  2003. //
  2004. //
  2005. // Description:
  2006. // Gets subscription information from the given document and uses that info
  2007. // to create a subscription
  2008. //
  2009. // Parameters:
  2010. // [In] pIXMLDocument - A pointer to the cdf document.
  2011. // [In] hwnd - The ownser hwnd. Used to display UI.
  2012. // [In] st - The type of subscription.
  2013. // [In] sa - Flag used to determine if additional steps should
  2014. // be taken if a user does create a subscription.
  2015. //
  2016. // Return:
  2017. // TRUE if a subscition for this document exists when this function returns.
  2018. // FALSE if the document doesn't have a subscription and one wasn't created.
  2019. //
  2020. // Comments:
  2021. // If a subscription to a channel is created then a channel shortcut has to
  2022. // be added to the favorites\channel folder.
  2023. //
  2024. // If a subscription to a desktop component is created then the caller
  2025. // determines if the desktop component gets added to the system.
  2026. //
  2027. ////////////////////////////////////////////////////////////////////////////////
  2028. BOOL
  2029. SubscriptionHelper(
  2030. IXMLDocument *pIXMLDocument,
  2031. HWND hwnd,
  2032. SUBSCRIPTIONTYPE st,
  2033. SUBSCRIPTIONACTION sa,
  2034. LPCWSTR pszwURL,
  2035. XMLDOCTYPE xdt,
  2036. BSTR* pbstrSubscribedURL
  2037. )
  2038. {
  2039. ASSERT(pIXMLDocument);
  2040. BOOL bChannelInstalled = FALSE;
  2041. HRESULT hr;
  2042. IXMLElement* pIXMLElement;
  2043. LONG nIndex;
  2044. hr = XML_GetFirstChannelElement(pIXMLDocument, &pIXMLElement, &nIndex);
  2045. if (SUCCEEDED(hr))
  2046. {
  2047. ASSERT(pIXMLElement);
  2048. BSTR bstrURL = XML_GetAttribute(pIXMLElement, XML_SELF);
  2049. if ((NULL == bstrURL || 0 == *bstrURL) && pszwURL)
  2050. {
  2051. if (bstrURL)
  2052. SysFreeString(bstrURL);
  2053. bstrURL = SysAllocString(pszwURL);
  2054. }
  2055. if (bstrURL)
  2056. {
  2057. ISubscriptionMgr* pISubscriptionMgr = NULL;
  2058. #ifndef UNIX
  2059. hr = CoCreateInstance(CLSID_SubscriptionMgr, NULL,
  2060. CLSCTX_INPROC_SERVER, IID_ISubscriptionMgr,
  2061. (void**)&pISubscriptionMgr);
  2062. if (SUCCEEDED(hr))
  2063. {
  2064. ASSERT(pISubscriptionMgr);
  2065. //hr = pISubscriptionMgr->IsSubscribed(bstrURL, &bSubscribed);
  2066. bChannelInstalled = Channel_IsInstalled(bstrURL);
  2067. if (SUBSTYPE_DESKTOPCHANNEL == st && hwnd)
  2068. {
  2069. BOOL bSubscribed;
  2070. hr = pISubscriptionMgr->IsSubscribed(bstrURL, &bSubscribed);
  2071. if (bSubscribed)
  2072. {
  2073. TCHAR szText[MAX_PATH];
  2074. TCHAR szTitle[MAX_PATH];
  2075. MLLoadString(IDS_OVERWRITE_DLG_TEXT, szText,
  2076. ARRAYSIZE(szText));
  2077. MLLoadString(IDS_OVERWRITE_DLG_TITLE, szTitle,
  2078. ARRAYSIZE(szTitle));
  2079. if (IDYES == MessageBox(hwnd, szText, szTitle,
  2080. MB_YESNO | MB_ICONQUESTION))
  2081. {
  2082. pISubscriptionMgr->DeleteSubscription(bstrURL, NULL);
  2083. bChannelInstalled = FALSE;
  2084. }
  2085. }
  2086. }
  2087. #else
  2088. bChannelInstalled = Channel_IsInstalled(bstrURL);
  2089. #endif /* UNIX */
  2090. if (!bChannelInstalled)
  2091. {
  2092. BSTR bstrName;
  2093. if (SUBSTYPE_DESKTOPCHANNEL != st)
  2094. {
  2095. bstrName = XML_GetAttribute(pIXMLElement, XML_TITLE);
  2096. }
  2097. else
  2098. {
  2099. IXMLElement* pDskCmpIXMLElement;
  2100. if (SUCCEEDED(XML_GetFirstDesktopComponentElement(
  2101. pIXMLDocument,
  2102. &pDskCmpIXMLElement,
  2103. &nIndex)))
  2104. {
  2105. ASSERT(pDskCmpIXMLElement);
  2106. bstrName = XML_GetAttribute(pDskCmpIXMLElement,
  2107. XML_TITLE);
  2108. pDskCmpIXMLElement->Release();
  2109. }
  2110. else
  2111. {
  2112. bstrName = NULL;
  2113. }
  2114. }
  2115. if ((NULL == bstrName || 0 == *bstrName) && pszwURL)
  2116. {
  2117. WCHAR szwFilename[MAX_PATH];
  2118. if (StrCpyNW(szwFilename, PathFindFileNameW(pszwURL),
  2119. ARRAYSIZE(szwFilename)))
  2120. {
  2121. PathRemoveExtensionW(szwFilename);
  2122. if (bstrName)
  2123. SysFreeString(bstrName);
  2124. bstrName = SysAllocString(szwFilename);
  2125. }
  2126. }
  2127. if (bstrName)
  2128. {
  2129. TASK_TRIGGER tt = {0};
  2130. SUBSCRIPTIONINFO si = {0};
  2131. si.cbSize = sizeof(SUBSCRIPTIONINFO);
  2132. si.fUpdateFlags |= SUBSINFO_SCHEDULE;
  2133. si.schedule = SUBSSCHED_AUTO;
  2134. si.pTrigger = (LPVOID)&tt;
  2135. XML_GetSubscriptionInfo(pIXMLElement, &si);
  2136. bChannelInstalled = SubscribeToURL(pISubscriptionMgr,
  2137. bstrURL, bstrName, &si,
  2138. hwnd, st, (xdt==DOC_SOFTWAREUPDATE));
  2139. #ifndef UNIX
  2140. if (bChannelInstalled &&
  2141. SUBSACTION_ADDADDITIONALCOMPONENTS == sa)
  2142. {
  2143. if (SUBSTYPE_CHANNEL == st)
  2144. {
  2145. // Update the subscription if the user has
  2146. // choosen to view the screen saver item.
  2147. if (
  2148. SUCCEEDED(pISubscriptionMgr->GetSubscriptionInfo(bstrURL,
  2149. &si))
  2150. &&
  2151. (si.fChannelFlags & CHANNEL_AGENT_PRECACHE_SCRNSAVER)
  2152. )
  2153. {
  2154. pISubscriptionMgr->UpdateSubscription(bstrURL);
  2155. }
  2156. //t-mattgi: moved this to AddToFav code in shdocvw
  2157. //because there, we know what folder to add it to
  2158. //AddChannel(szName, szURL, NULL, NULL, NULL, xdt);
  2159. }
  2160. else if (SUBSTYPE_DESKTOPCHANNEL == st)
  2161. {
  2162. COMPONENT Info;
  2163. if(SUCCEEDED(XML_GetDesktopComponentInfo(
  2164. pIXMLDocument,
  2165. &Info)))
  2166. {
  2167. if(!Info.wszSubscribedURL[0])
  2168. {
  2169. // Since XML_GetDesktopComponentInfo did not fillout the SubscribedURL
  2170. // field (because the CDF file didn't have a SELF tag), we need to
  2171. // fill it with what was really subscribed to (the URL for CDF file itself)
  2172. StrCpyNW(Info.wszSubscribedURL, bstrURL, ARRAYSIZE(Info.wszSubscribedURL));
  2173. }
  2174. pISubscriptionMgr->UpdateSubscription(bstrURL);
  2175. AddDesktopComponent(&Info);
  2176. }
  2177. }
  2178. }
  2179. #endif /* !UNIX */
  2180. }
  2181. }
  2182. #ifndef UNIX
  2183. pISubscriptionMgr->Release();
  2184. }
  2185. #endif /* !UNIX */
  2186. if (pbstrSubscribedURL)
  2187. {
  2188. *pbstrSubscribedURL = bstrURL;
  2189. }
  2190. else
  2191. {
  2192. SysFreeString(bstrURL);
  2193. }
  2194. }
  2195. pIXMLElement->Release();
  2196. }
  2197. return bChannelInstalled;
  2198. }
  2199. //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
  2200. //
  2201. // *** SubscribeToURL ***
  2202. //
  2203. //
  2204. // Description:
  2205. // Takes the user to the subscription wizard for the given URL.
  2206. //
  2207. // Parameters:
  2208. // [In] ISubscriptionMgr - The subscription manager interface
  2209. // [In] bstrURL - The URL to subscribe.
  2210. // [In] bstrName - The name of the subscription.
  2211. // [In] psi - A subscription information structure.
  2212. // [In] hwnd - The owner hwnd.
  2213. // [In] st - The type of subsciption. SUBSTYPE_CHANNEL or
  2214. // SUSBSTYPE_DESKTOPCOMPONENT.
  2215. // [In] bIsSoftare - modifies SUBSTYPE_CHANNEL since software updates
  2216. // don't have their own subscriptiontype
  2217. //
  2218. // Return:
  2219. // TRUE if the user subscribe to the URL.
  2220. // FALSE if the user didn't subscribe to the URL.
  2221. //
  2222. // Comments:
  2223. // The subscription manager CreateSubscription function takes the user
  2224. // through the subscriptiopn wizard.
  2225. //
  2226. ////////////////////////////////////////////////////////////////////////////////
  2227. BOOL
  2228. SubscribeToURL(
  2229. ISubscriptionMgr* pISubscriptionMgr,
  2230. BSTR bstrURL,
  2231. BSTR bstrName,
  2232. SUBSCRIPTIONINFO* psi,
  2233. HWND hwnd,
  2234. SUBSCRIPTIONTYPE st,
  2235. BOOL bIsSoftware
  2236. )
  2237. {
  2238. #ifndef UNIX
  2239. ASSERT(pISubscriptionMgr);
  2240. #endif /* !UNIX */
  2241. ASSERT(bstrURL);
  2242. ASSERT(bstrName);
  2243. BOOL bSubscribed = FALSE;
  2244. DWORD dwFlags = 0;
  2245. if (Channel_IsInstalled(bstrURL))
  2246. {
  2247. dwFlags |= CREATESUBS_ACTIVATE | CREATESUBS_FROMFAVORITES;
  2248. }
  2249. else
  2250. {
  2251. dwFlags |= CREATESUBS_ADDTOFAVORITES;
  2252. }
  2253. if (bIsSoftware)
  2254. {
  2255. dwFlags |= CREATESUBS_SOFTWAREUPDATE;
  2256. }
  2257. #ifndef UNIX
  2258. HRESULT hr = pISubscriptionMgr->CreateSubscription(hwnd, bstrURL, bstrName,
  2259. dwFlags, st, psi);
  2260. #else
  2261. /* Unix does not have subscription support */
  2262. /* But, we want to add the channel to favorites */
  2263. HRESULT hr = E_FAIL;
  2264. if ((dwFlags & CREATESUBS_ADDTOFAVORITES) && (st == SUBSTYPE_CHANNEL || st == SUBSTYPE_URL))
  2265. hr = SHAddSubscribeFavorite(hwnd, bstrURL, bstrName, dwFlags, st, psi);
  2266. #endif /* UNIX */
  2267. #if 0
  2268. if (SUCCEEDED(hr))
  2269. {
  2270. pISubscriptionMgr->IsSubscribed(bstrURL, &bSubscribed);
  2271. }
  2272. #else
  2273. //t-mattgi: REVIEW with edwardP
  2274. //can't just check if subscribed -- they might choose to add to channel bar without
  2275. //subscribing, then we still want to return true. or do we?
  2276. bSubscribed = (hr == S_OK); //case where they clicked OK
  2277. #endif
  2278. return bSubscribed;
  2279. }
  2280. //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
  2281. //
  2282. // *** AddDesktopComponent ***
  2283. //
  2284. //
  2285. // Description:
  2286. // Calls the desktop component manager to add a new component.
  2287. //
  2288. // Parameters:
  2289. // [In] pInfo - Information about the new component to add.
  2290. //
  2291. // Return:
  2292. // S_OK if the component was added.
  2293. // E_FAIL otherwise.
  2294. //
  2295. // Comments:
  2296. //
  2297. //
  2298. ////////////////////////////////////////////////////////////////////////////////
  2299. HRESULT
  2300. AddDesktopComponent(
  2301. COMPONENT* pInfo
  2302. )
  2303. {
  2304. ASSERT(pInfo);
  2305. HRESULT hr = S_OK;
  2306. #ifndef UNIX
  2307. /* No Active Desktop on Unix */
  2308. IActiveDesktop* pIActiveDesktop;
  2309. hr = CoCreateInstance(CLSID_ActiveDesktop, NULL, CLSCTX_INPROC_SERVER,
  2310. IID_IActiveDesktop, (void**)&pIActiveDesktop);
  2311. if (SUCCEEDED(hr))
  2312. {
  2313. ASSERT(pIActiveDesktop);
  2314. // Assign a default position to the component
  2315. pInfo->cpPos.iLeft = COMPONENT_DEFAULT_LEFT;
  2316. pInfo->cpPos.iTop = COMPONENT_DEFAULT_TOP;
  2317. hr = pIActiveDesktop->AddDesktopItem(pInfo, 0);
  2318. //
  2319. // Apply all except refresh as this causes timing issues because the
  2320. // desktop is in offline mode but not in silent mode
  2321. //
  2322. if (SUCCEEDED(hr))
  2323. {
  2324. DWORD dwFlags = AD_APPLY_ALL;
  2325. // If the desktop component url is already in cache, we want to
  2326. // refresh right away - otherwise not
  2327. if(!(CDFIDL_IsCachedURL(pInfo->wszSubscribedURL)))
  2328. {
  2329. //It is not in cache, we want to wait until the download
  2330. // is done before refresh. So don't refresh right away
  2331. dwFlags &= ~(AD_APPLY_REFRESH);
  2332. }
  2333. else
  2334. dwFlags |= AD_APPLY_BUFFERED_REFRESH;
  2335. hr = pIActiveDesktop->ApplyChanges(dwFlags);
  2336. }
  2337. pIActiveDesktop->Release();
  2338. }
  2339. #endif /* UNIX */
  2340. return hr;
  2341. }
  2342. ////////////////////////////////////////////////////////////////////////////////
  2343. //
  2344. // *** Channel_CreateDirectory ***
  2345. //
  2346. // Description:
  2347. // creates a directory including any intermediate
  2348. // directories in the path.
  2349. //
  2350. // Parameters:
  2351. // LPCTSTR pszPath - path of directory to create
  2352. //
  2353. // Returns:
  2354. // 0 if function succeeded, else returns GetLastError()
  2355. //
  2356. // Comments:
  2357. // Copied from SHCreateDirectory. Can't use SHCreateDirectory directly
  2358. // because that fires off an SHChangeNotify msg immediately and need to
  2359. // fire it off only after the desktop.ini has been created in AddChannel().
  2360. // Also would have to do a runtime check for NT vs Win95 as this api doesn't
  2361. // have A & W versions.
  2362. //
  2363. ////////////////////////////////////////////////////////////////////////////////
  2364. int Channel_CreateDirectory(LPCTSTR pszPath)
  2365. {
  2366. int ret = 0;
  2367. if (!CreateDirectory(pszPath, NULL)) {
  2368. TCHAR *pSlash, szTemp[MAX_PATH + 1]; // +1 for PathAddBackslash()
  2369. TCHAR *pEnd;
  2370. ret = GetLastError();
  2371. // There are certain error codes that we should bail out here
  2372. // before going through and walking up the tree...
  2373. switch (ret)
  2374. {
  2375. case ERROR_FILENAME_EXCED_RANGE:
  2376. case ERROR_FILE_EXISTS:
  2377. return(ret);
  2378. }
  2379. StrCpyN(szTemp, pszPath, ARRAYSIZE(szTemp) - 1);
  2380. pEnd = PathAddBackslash(szTemp); // for the loop below
  2381. // assume we have 'X:\' to start this should even work
  2382. // on UNC names because will will ignore the first error
  2383. #ifndef UNIX
  2384. pSlash = szTemp + 3;
  2385. #else
  2386. /* absolute paths on unix start with / */
  2387. pSlash = szTemp + 1;
  2388. #endif /* UNIX */
  2389. // create each part of the dir in order
  2390. while (*pSlash) {
  2391. while (*pSlash && *pSlash != TEXT(FILENAME_SEPARATOR))
  2392. pSlash = CharNext(pSlash);
  2393. if (*pSlash) {
  2394. ASSERT(*pSlash == TEXT(FILENAME_SEPARATOR));
  2395. *pSlash = 0; // terminate path at seperator
  2396. if (pSlash + 1 == pEnd)
  2397. ret = CreateDirectory(szTemp, NULL) ? 0 : GetLastError();
  2398. else
  2399. ret = CreateDirectory(szTemp, NULL) ? 0 : GetLastError();
  2400. }
  2401. *pSlash++ = TEXT(FILENAME_SEPARATOR); // put the seperator back
  2402. }
  2403. }
  2404. return ret;
  2405. }
  2406. ////////////////////////////////////////////////////////////////////////////////
  2407. // PathCombineCleanPath
  2408. ////////////////////////////////////////////////////////////////////////////////
  2409. BOOL PathCombineCleanPath
  2410. (
  2411. LPTSTR pszCleanPath,
  2412. LPCTSTR pszPath
  2413. )
  2414. {
  2415. TCHAR szComponent[MAX_PATH];
  2416. TCHAR * pszComponent = szComponent;
  2417. BOOL bCleaned = FALSE;
  2418. if (*pszPath == TEXT(FILENAME_SEPARATOR))
  2419. pszPath++;
  2420. *pszComponent = TEXT('\0');
  2421. for (;;)
  2422. {
  2423. if (
  2424. (*pszPath == TEXT(FILENAME_SEPARATOR))
  2425. ||
  2426. (!*pszPath)
  2427. )
  2428. {
  2429. *pszComponent = TEXT('\0');
  2430. #ifdef UNICODE
  2431. PathCleanupSpec(NULL, szComponent);
  2432. #else
  2433. MyPathCleanupSpec(NULL, szComponent);
  2434. #endif
  2435. PathCombine(pszCleanPath, pszCleanPath, szComponent);
  2436. bCleaned = TRUE;
  2437. if (*pszPath)
  2438. {
  2439. // Reset for the next component
  2440. pszComponent = szComponent;
  2441. *pszComponent = TEXT('\0');
  2442. pszPath = CharNext(pszPath);
  2443. }
  2444. else
  2445. break;
  2446. }
  2447. else
  2448. {
  2449. LPTSTR pszNextChar = CharNext(pszPath);
  2450. while (pszPath < pszNextChar)
  2451. {
  2452. *pszComponent++ = *pszPath++;
  2453. }
  2454. }
  2455. }
  2456. return bCleaned;
  2457. }
  2458. #ifndef UNICODE
  2459. ////////////////////////////////////////////////////////////////////////////////
  2460. // MyPathCleanupPath
  2461. ////////////////////////////////////////////////////////////////////////////////
  2462. int MyPathCleanupSpec(LPCTSTR pszDir, LPTSTR pszSpec)
  2463. {
  2464. OSVERSIONINFO osvi;
  2465. osvi.dwOSVersionInfoSize = sizeof(osvi);
  2466. GetVersionEx(&osvi);
  2467. if ((VER_PLATFORM_WIN32_NT == osvi.dwPlatformId))
  2468. {
  2469. WCHAR wszDir[MAX_PATH];
  2470. WCHAR wszSpec[MAX_PATH];
  2471. LPWSTR pwszDir = wszDir;
  2472. int iRet;
  2473. if (pszDir)
  2474. EVAL(MultiByteToWideChar(CP_ACP, 0, pszDir, -1, wszDir, ARRAYSIZE(wszDir)) != 0);
  2475. else
  2476. pwszDir = NULL;
  2477. EVAL(MultiByteToWideChar(CP_ACP, 0, pszSpec, -1, wszSpec, ARRAYSIZE(wszSpec)) != 0);
  2478. iRet = PathCleanupSpec((LPTSTR)pwszDir, (LPTSTR)wszSpec);
  2479. EVAL(WideCharToMultiByte(CP_ACP, 0, wszSpec, -1, pszSpec, MAX_PATH, NULL, NULL) != 0);
  2480. return iRet;
  2481. }
  2482. else
  2483. return PathCleanupSpec(pszDir, pszSpec);
  2484. }
  2485. #endif
  2486. //
  2487. // Is the given path from the recycle bin?
  2488. //
  2489. BOOL IsRecycleBinPath(LPCTSTR pszPath)
  2490. {
  2491. ASSERT(pszPath);
  2492. //
  2493. // "RECYCLED" is hard coded in bitbuck.c in shell32
  2494. //
  2495. TCHAR* pszRootless = PathSkipRoot(pszPath);
  2496. return (pszRootless ? (0 == StrNCmpI(TEXT("RECYCLED"), pszRootless, 8)) : FALSE);
  2497. }
  2498. ////////////////////////////////////////////////////////////////////////////////
  2499. //
  2500. // ICopyHook::CopyCallback
  2501. //
  2502. // Either allows the shell to move, copy, delete, or rename a folder or printer
  2503. // object, or disallows the shell from carrying out the operation. The shell
  2504. // calls each copy hook handler registered for a folder or printer object until
  2505. // either all the handlers have been called or one of them returns IDCANCEL.
  2506. //
  2507. // RETURNS:
  2508. //
  2509. // IDYES - Allows the operation.
  2510. // IDNO - Prevents the operation on this file, but continues with any other
  2511. // operations (for example, a batch copy operation).
  2512. // IDCANCEL - Prevents the current operation and cancels any pending operations
  2513. //
  2514. ////////////////////////////////////////////////////////////////////////////////
  2515. UINT CChannelMgr::CopyCallback(
  2516. HWND hwnd, // Handle of the parent window for displaying UI objects
  2517. UINT wFunc, // Operation to perform.
  2518. UINT wFlags, // Flags that control the operation
  2519. LPCTSTR pszSrcFile, // Pointer to the source file
  2520. DWORD dwSrcAttribs, // Source file attributes
  2521. LPCTSTR pszDestFile, // Pointer to the destination file
  2522. DWORD dwDestAttribs // Destination file attributes
  2523. )
  2524. {
  2525. HRESULT hr;
  2526. //
  2527. // Return immediately if this isn't a delete of a system folder
  2528. // Redundant check as this should be made in shdocvw
  2529. //
  2530. if (!(dwSrcAttribs & FILE_ATTRIBUTE_SYSTEM) ||
  2531. !(dwSrcAttribs & FILE_ATTRIBUTE_DIRECTORY))
  2532. {
  2533. return IDYES;
  2534. }
  2535. //
  2536. // Build a string containing the guid to check for in the desktop.ini
  2537. //
  2538. TCHAR szFolderGUID[GUID_STR_LEN];
  2539. TCHAR szCDFViewGUID[GUID_STR_LEN];
  2540. SHStringFromGUID(CLSID_CDFINI, szCDFViewGUID, ARRAYSIZE(szCDFViewGUID));
  2541. //
  2542. // Build path to desktop.ini in folder
  2543. //
  2544. TCHAR szPath[MAX_PATH];
  2545. PathCombine(szPath, pszSrcFile, TEXT("desktop.ini"));
  2546. //
  2547. // Read CLSID from desktop.ini if present
  2548. //
  2549. GetPrivateProfileString(
  2550. TEXT(".ShellClassInfo"),
  2551. TEXT("CLSID"),
  2552. TEXT(""),
  2553. szFolderGUID,
  2554. GUID_STR_LEN,
  2555. szPath);
  2556. if (StrEql(szFolderGUID, szCDFViewGUID))
  2557. {
  2558. //
  2559. // We are deleting/renaming a folder that has the system bit set and
  2560. // desktop.ini that contains the CLSID for the CDFINI handler, so it
  2561. // must be a channel
  2562. //
  2563. //
  2564. // Find URL to CDF from desktop.ini
  2565. //
  2566. TCHAR szCDFURL[INTERNET_MAX_URL_LENGTH];
  2567. WCHAR wszCDFURL[INTERNET_MAX_URL_LENGTH];
  2568. GetPrivateProfileString(
  2569. TEXT("Channel"),
  2570. TEXT("CDFURL"),
  2571. TEXT(""),
  2572. szCDFURL,
  2573. INTERNET_MAX_URL_LENGTH,
  2574. szPath);
  2575. switch(wFunc)
  2576. {
  2577. case FO_RENAME:
  2578. //Reg_RemoveChannel(pszSrcFile);
  2579. //Reg_WriteChannel(pszDestFile, szCDFURL);
  2580. break;
  2581. case FO_COPY:
  2582. //Reg_WriteChannel(pszDestFile, szCDFURL);
  2583. break;
  2584. case FO_MOVE:
  2585. //Reg_RemoveChannel(pszSrcFile);
  2586. //Reg_WriteChannel(pszDestFile, szCDFURL);
  2587. break;
  2588. case FO_DELETE:
  2589. TraceMsg(TF_GENERAL, "Deleting a channel");
  2590. //
  2591. // Check if there is a shell restriction against remove channel(s)
  2592. //
  2593. if (SHRestricted2(REST_NoRemovingChannels, szCDFURL, 0) ||
  2594. SHRestricted2(REST_NoEditingChannels, szCDFURL, 0) )
  2595. {
  2596. TraceMsg(TF_GENERAL, "Channel Delete blocked by shell restriction");
  2597. return IDNO;
  2598. }
  2599. else if (!IsRecycleBinPath(pszSrcFile))
  2600. {
  2601. //
  2602. // Delete the in memory cache entry for this url.
  2603. //
  2604. Cache_RemoveItem(szCDFURL);
  2605. //
  2606. // Delete the wininet cache entry for this cdf.
  2607. //
  2608. DeleteUrlCacheEntry(szCDFURL);
  2609. //
  2610. // Remove the channel from the registry.
  2611. //
  2612. //Reg_RemoveChannel(pszSrcFile);
  2613. //
  2614. // Convert UrlToCdf to wide str, and then to bstr
  2615. //
  2616. SHTCharToUnicode(szCDFURL, wszCDFURL, INTERNET_MAX_URL_LENGTH);
  2617. BSTR bstrCDFURL = SysAllocString(wszCDFURL);
  2618. if (bstrCDFURL)
  2619. {
  2620. //
  2621. // Create the subscription manager
  2622. //
  2623. ISubscriptionMgr* pISubscriptionMgr = NULL;
  2624. hr = CoCreateInstance(CLSID_SubscriptionMgr, NULL,
  2625. CLSCTX_INPROC_SERVER, IID_ISubscriptionMgr,
  2626. (void**)&pISubscriptionMgr);
  2627. if (SUCCEEDED(hr))
  2628. {
  2629. //
  2630. // Delete the actual subscription to the CDF
  2631. //
  2632. hr = pISubscriptionMgr->DeleteSubscription(bstrCDFURL,NULL);
  2633. TraceMsg(TF_GENERAL,
  2634. SUCCEEDED(hr) ?
  2635. "DeleteSubscription Succeeded" :
  2636. "DeleteSubscription Failed");
  2637. pISubscriptionMgr->Release();
  2638. }
  2639. SysFreeString(bstrCDFURL);
  2640. }
  2641. }
  2642. break;
  2643. default:
  2644. break;
  2645. }
  2646. }
  2647. return IDYES;
  2648. }
  2649. #ifdef UNICODE
  2650. UINT CChannelMgr::CopyCallback(
  2651. HWND hwnd, // Handle of the parent window for displaying UI objects
  2652. UINT wFunc, // Operation to perform.
  2653. UINT wFlags, // Flags that control the operation
  2654. LPCSTR pszSrcFile, // Pointer to the source file
  2655. DWORD dwSrcAttribs, // Source file attributes
  2656. LPCSTR pszDestFile, // Pointer to the destination file
  2657. DWORD dwDestAttribs // Destination file attributes
  2658. )
  2659. {
  2660. WCHAR wszSrcFile[MAX_PATH];
  2661. WCHAR wszDestFile[MAX_PATH];
  2662. SHAnsiToUnicode(pszSrcFile, wszSrcFile, MAX_PATH);
  2663. SHAnsiToUnicode(pszDestFile, wszDestFile, MAX_PATH);
  2664. return CopyCallback(hwnd, wFunc, wFlags, wszSrcFile, dwSrcAttribs, wszDestFile, dwDestAttribs);
  2665. }
  2666. #endif
  2667. HRESULT Channel_CreateILFromPath(LPCTSTR pszPath, LPITEMIDLIST* ppidl)
  2668. {
  2669. ASSERT(pszPath);
  2670. ASSERT(ppidl);
  2671. HRESULT hr;
  2672. IShellFolder* pIShellFolder;
  2673. hr = SHGetDesktopFolder(&pIShellFolder);
  2674. if (SUCCEEDED(hr))
  2675. {
  2676. ASSERT(pIShellFolder);
  2677. WCHAR wszPath[MAX_PATH];
  2678. if (SHTCharToUnicode(pszPath, wszPath, ARRAYSIZE(wszPath)))
  2679. {
  2680. ULONG ucch;
  2681. hr = pIShellFolder->ParseDisplayName(NULL, NULL, wszPath, &ucch,
  2682. ppidl, NULL);
  2683. }
  2684. else
  2685. {
  2686. hr = E_FAIL;
  2687. }
  2688. pIShellFolder->Release();
  2689. }
  2690. return hr;
  2691. }
  2692. HRESULT GetChannelIconInfo(LPCTSTR pszPath, LPTSTR pszHashItem, int* piIndex,
  2693. UINT* puFlags)
  2694. {
  2695. ASSERT(pszPath);
  2696. ASSERT(pszHashItem);
  2697. ASSERT(piIndex);
  2698. ASSERT(puFlags);
  2699. HRESULT hr;
  2700. IShellFolder* pdsktopIShellFolder;
  2701. hr = SHGetDesktopFolder(&pdsktopIShellFolder);
  2702. if (SUCCEEDED(hr))
  2703. {
  2704. ASSERT(pdsktopIShellFolder);
  2705. LPITEMIDLIST pidl;
  2706. hr = Channel_CreateILFromPath(pszPath, &pidl);
  2707. if (SUCCEEDED(hr))
  2708. {
  2709. ASSERT(pidl);
  2710. ASSERT(!ILIsEmpty(pidl));
  2711. ASSERT(!ILIsEmpty(_ILNext(pidl)));
  2712. LPITEMIDLIST pidlLast = ILClone(ILFindLastID(pidl));
  2713. if (pidlLast)
  2714. {
  2715. if (ILRemoveLastID(pidl))
  2716. {
  2717. IShellFolder* pIShellFolder;
  2718. hr = pdsktopIShellFolder->BindToObject(pidl, NULL,
  2719. IID_IShellFolder,
  2720. (void**)&pIShellFolder);
  2721. if (SUCCEEDED(hr))
  2722. {
  2723. ASSERT(pIShellFolder);
  2724. IExtractIcon* pIExtractIcon;
  2725. hr = pIShellFolder->GetUIObjectOf(NULL, 1,
  2726. (LPCITEMIDLIST*)&pidlLast,
  2727. IID_IExtractIcon,
  2728. NULL,
  2729. (void**)&pIExtractIcon);
  2730. if (SUCCEEDED(hr))
  2731. {
  2732. ASSERT(pIExtractIcon);
  2733. hr = pIExtractIcon->GetIconLocation(0, pszHashItem,
  2734. MAX_PATH,
  2735. piIndex,
  2736. puFlags);
  2737. pIExtractIcon->Release();
  2738. }
  2739. pIShellFolder->Release();
  2740. }
  2741. }
  2742. ILFree(pidlLast);
  2743. }
  2744. ILFree(pidl);
  2745. }
  2746. pdsktopIShellFolder->Release();
  2747. }
  2748. return hr;
  2749. }
  2750. HRESULT PreUpdateChannelImage(LPCTSTR pszPath, LPTSTR pszHashItem, int* piIndex,
  2751. UINT* puFlags, int* piImageIndex)
  2752. {
  2753. ASSERT(pszPath);
  2754. ASSERT(pszHashItem);
  2755. ASSERT(piIndex);
  2756. ASSERT(puFlags);
  2757. ASSERT(piImageIndex);
  2758. HRESULT hr;
  2759. TraceMsg(TF_GLEAM, "Pre SHChangeNotify %s", pszPath);
  2760. hr = GetChannelIconInfo(pszPath, pszHashItem, piIndex, puFlags);
  2761. if (SUCCEEDED(hr))
  2762. {
  2763. SHFILEINFO fi = {0};
  2764. if (SHGetFileInfo(pszPath, 0, &fi, sizeof(SHFILEINFO),
  2765. SHGFI_SYSICONINDEX))
  2766. {
  2767. *piImageIndex = fi.iIcon;
  2768. }
  2769. else
  2770. {
  2771. *piImageIndex = -1;
  2772. }
  2773. }
  2774. return hr;
  2775. }
  2776. //
  2777. // UpdateChannelImage is a copy of _SHUpdateImageW found in shdocvw\util.cpp!
  2778. //
  2779. void UpdateChannelImage(LPCWSTR pszHashItem, int iIndex, UINT uFlags,
  2780. int iImageIndex)
  2781. {
  2782. SHChangeUpdateImageIDList rgPidl;
  2783. SHChangeDWORDAsIDList rgDWord;
  2784. int cLen = MAX_PATH - (lstrlenW( pszHashItem ) + 1);
  2785. cLen *= sizeof( WCHAR );
  2786. if ( cLen < 0 )
  2787. cLen = 0;
  2788. // make sure we send a valid index
  2789. if ( iImageIndex == -1 )
  2790. iImageIndex = II_DOCUMENT;
  2791. rgPidl.dwProcessID = GetCurrentProcessId();
  2792. rgPidl.iIconIndex = iIndex;
  2793. rgPidl.iCurIndex = iImageIndex;
  2794. rgPidl.uFlags = uFlags;
  2795. StrCpyNW( rgPidl.szName, pszHashItem, ARRAYSIZE(rgPidl.szName) );
  2796. rgPidl.cb = (USHORT)(sizeof( rgPidl ) - cLen);
  2797. _ILNext( (LPITEMIDLIST) &rgPidl )->mkid.cb = 0;
  2798. rgDWord.cb = sizeof( rgDWord) - sizeof(USHORT);
  2799. rgDWord.dwItem1 = (DWORD) iImageIndex;
  2800. rgDWord.dwItem2 = 0;
  2801. rgDWord.cbZero = 0;
  2802. TraceMsg(TF_GLEAM, "Sending SHChangeNotify %S,%d (image index %d)",
  2803. pszHashItem, iIndex, iImageIndex);
  2804. // pump it as an extended event
  2805. SHChangeNotify(SHCNE_UPDATEIMAGE, SHCNF_IDLIST | SHCNF_FLUSH, &rgDWord,
  2806. &rgPidl);
  2807. return;
  2808. }
  2809. HRESULT UpdateImage(LPCTSTR pszPath)
  2810. {
  2811. ASSERT(pszPath);
  2812. HRESULT hr;
  2813. TCHAR szHash[MAX_PATH];
  2814. int iIndex;
  2815. UINT uFlags;
  2816. int iImageIndex;
  2817. hr = PreUpdateChannelImage(pszPath, szHash, &iIndex, &uFlags, &iImageIndex);
  2818. if (SUCCEEDED(hr))
  2819. {
  2820. WCHAR wszHash[MAX_PATH];
  2821. SHTCharToUnicode(szHash, wszHash, ARRAYSIZE(wszHash));
  2822. UpdateChannelImage(wszHash, iIndex, uFlags, iImageIndex);
  2823. }
  2824. return hr;
  2825. }
  2826. //
  2827. // Determines if the channel is installed on the system.
  2828. //
  2829. BOOL
  2830. Channel_IsInstalled(
  2831. LPCWSTR pszURL
  2832. )
  2833. {
  2834. ASSERT(pszURL);
  2835. BOOL fRet = FALSE;
  2836. CChannelEnum* pCChannelEnum = new CChannelEnum(CHANENUM_CHANNELFOLDER |
  2837. CHANENUM_SOFTUPDATEFOLDER,
  2838. pszURL);
  2839. if (pCChannelEnum)
  2840. {
  2841. CHANNELENUMINFO ci;
  2842. fRet = (S_OK == pCChannelEnum->Next(1, &ci, NULL));
  2843. pCChannelEnum->Release();
  2844. }
  2845. return fRet;
  2846. }
  2847. HRESULT
  2848. Channel_WriteScreenSaverURL(
  2849. LPCWSTR pszURL,
  2850. LPCWSTR pszScreenSaverURL
  2851. )
  2852. {
  2853. ASSERT(pszURL);
  2854. HRESULT hr = S_OK;
  2855. #ifndef UNIX
  2856. CChannelEnum* pCChannelEnum = new CChannelEnum(CHANENUM_CHANNELFOLDER |
  2857. CHANENUM_SOFTUPDATEFOLDER |
  2858. CHANENUM_PATH,
  2859. pszURL);
  2860. if (pCChannelEnum)
  2861. {
  2862. CHANNELENUMINFO ci;
  2863. if (S_OK == pCChannelEnum->Next(1, &ci, NULL))
  2864. {
  2865. TCHAR szDesktopINI[MAX_PATH];
  2866. TCHAR szScreenSaverURL[INTERNET_MAX_URL_LENGTH];
  2867. ASSERT(ci.pszPath);
  2868. if (pszScreenSaverURL)
  2869. {
  2870. SHUnicodeToTChar(pszScreenSaverURL, szScreenSaverURL, ARRAYSIZE(szScreenSaverURL));
  2871. }
  2872. SHUnicodeToTChar(ci.pszPath, szDesktopINI, ARRAYSIZE(szDesktopINI));
  2873. PathCombine(szDesktopINI, szDesktopINI, c_szDesktopINI);
  2874. WritePrivateProfileString(c_szChannel,
  2875. c_szScreenSaverURL,
  2876. pszScreenSaverURL ? szScreenSaverURL : NULL,
  2877. szDesktopINI);
  2878. CoTaskMemFree(ci.pszPath);
  2879. }
  2880. else
  2881. {
  2882. hr = E_FAIL;
  2883. }
  2884. pCChannelEnum->Release();
  2885. }
  2886. else
  2887. {
  2888. hr = E_OUTOFMEMORY;
  2889. }
  2890. #endif /* !UNIX */
  2891. return hr;
  2892. }
  2893. HRESULT Channel_GetAndWriteScreenSaverURL(LPCTSTR pszURL, LPCTSTR pszDesktopINI)
  2894. {
  2895. HRESULT hr = S_OK;
  2896. #ifndef UNIX
  2897. CCdfView* pCCdfView = new CCdfView;
  2898. if (NULL != pCCdfView)
  2899. {
  2900. WCHAR wszURL[INTERNET_MAX_URL_LENGTH];
  2901. SHTCharToUnicode(pszURL, wszURL, ARRAYSIZE(wszURL));
  2902. if (SUCCEEDED(pCCdfView->Load(wszURL, 0)))
  2903. {
  2904. IXMLDocument* pIXMLDocument;
  2905. if (SUCCEEDED(pCCdfView->ParseCdf(NULL, &pIXMLDocument, PARSE_LOCAL)))
  2906. {
  2907. BSTR bstrSSUrl;
  2908. TCHAR szSSURL[INTERNET_MAX_URL_LENGTH];
  2909. TCHAR *pszScreenSaverURL = NULL;
  2910. ASSERT(NULL != pIXMLDocument);
  2911. if (SUCCEEDED(XML_GetScreenSaverURL(pIXMLDocument, &bstrSSUrl)))
  2912. {
  2913. SHUnicodeToTChar(bstrSSUrl, szSSURL, ARRAYSIZE(szSSURL));
  2914. pszScreenSaverURL = szSSURL;
  2915. TraceMsg(TF_GENERAL, "CDFVIEW: %ws has screensaver URL=%ws", wszURL, bstrSSUrl);
  2916. SysFreeString(bstrSSUrl);
  2917. }
  2918. else
  2919. {
  2920. TraceMsg(TF_GENERAL, "CDFVIEW: %ws has no screensaver URL", wszURL);
  2921. }
  2922. WritePrivateProfileString(c_szChannel,
  2923. c_szScreenSaverURL,
  2924. pszScreenSaverURL,
  2925. pszDesktopINI);
  2926. pIXMLDocument->Release();
  2927. }
  2928. else
  2929. {
  2930. TraceMsg(TF_GENERAL, "CDFVIEW: cdf parse failed %ws", wszURL);
  2931. }
  2932. }
  2933. else
  2934. {
  2935. TraceMsg(TF_GENERAL, "CDFVIEW: Couldn't load cdf %ws", wszURL);
  2936. }
  2937. pCCdfView->Release();
  2938. }
  2939. else
  2940. {
  2941. hr = E_OUTOFMEMORY;
  2942. }
  2943. #endif /* !UNIX */
  2944. return hr;
  2945. }
  2946. HRESULT Channel_RefreshScreenSaverURLs()
  2947. {
  2948. HRESULT hr = S_OK;
  2949. #ifndef UNIX
  2950. CChannelEnum* pCChannelEnum = new CChannelEnum(CHANENUM_CHANNELFOLDER |
  2951. CHANENUM_SOFTUPDATEFOLDER |
  2952. CHANENUM_PATH |
  2953. CHANENUM_URL,
  2954. NULL);
  2955. if (pCChannelEnum)
  2956. {
  2957. CHANNELENUMINFO ci;
  2958. while (S_OK == pCChannelEnum->Next(1, &ci, NULL))
  2959. {
  2960. TCHAR szDesktopINI[MAX_PATH];
  2961. TCHAR szURL[INTERNET_MAX_URL_LENGTH];
  2962. ASSERT(ci.pszPath);
  2963. ASSERT(ci.pszURL);
  2964. SHUnicodeToTChar(ci.pszPath, szDesktopINI, ARRAYSIZE(szDesktopINI));
  2965. SHUnicodeToTChar(ci.pszURL, szURL, ARRAYSIZE(szURL));
  2966. PathCombine(szDesktopINI, szDesktopINI, c_szDesktopINI);
  2967. Channel_GetAndWriteScreenSaverURL(szURL, szDesktopINI);
  2968. CoTaskMemFree(ci.pszPath);
  2969. CoTaskMemFree(ci.pszURL);
  2970. }
  2971. pCChannelEnum->Release();
  2972. }
  2973. else
  2974. {
  2975. hr = E_OUTOFMEMORY;
  2976. }
  2977. #endif /* !UNIX */
  2978. return hr;
  2979. }
  2980. //
  2981. // Finds the path of the channel in the channels folder that has the given url.
  2982. //
  2983. LPOLESTR
  2984. Channel_GetChannelPanePath(
  2985. LPCWSTR pszURL
  2986. )
  2987. {
  2988. ASSERT(pszURL);
  2989. LPOLESTR pstrRet = NULL;
  2990. CChannelEnum* pCChannelEnum = new CChannelEnum(CHANENUM_CHANNELFOLDER |
  2991. CHANENUM_PATH, pszURL);
  2992. if (pCChannelEnum)
  2993. {
  2994. CHANNELENUMINFO ci;
  2995. if (S_OK == pCChannelEnum->Next(1, &ci, NULL))
  2996. pstrRet = ci.pszPath;
  2997. pCChannelEnum->Release();
  2998. }
  2999. return pstrRet;
  3000. }
  3001. //
  3002. // Send SHChangeNotify for agiven URL.
  3003. //
  3004. void Channel_SendUpdateNotifications(LPCWSTR pwszURL)
  3005. {
  3006. CChannelEnum* pCChannelEnum = new CChannelEnum(
  3007. CHANENUM_CHANNELFOLDER |
  3008. CHANENUM_PATH,
  3009. pwszURL);
  3010. if (pCChannelEnum)
  3011. {
  3012. CHANNELENUMINFO ci;
  3013. while (S_OK == pCChannelEnum->Next(1, &ci, NULL))
  3014. {
  3015. TCHAR szPath[MAX_PATH];
  3016. if (SHUnicodeToTChar(ci.pszPath, szPath, ARRAYSIZE(szPath)))
  3017. {
  3018. //
  3019. // Clearing the gleam flag will result in a SHCNE_UPDATEIMAGE
  3020. // notification.
  3021. //
  3022. TCHAR szURL[INTERNET_MAX_URL_LENGTH];
  3023. if (SHUnicodeToTChar(pwszURL, szURL, ARRAYSIZE(szURL)))
  3024. ClearGleamFlag(szURL, szPath);
  3025. SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_PATH, (void*)szPath,
  3026. NULL);
  3027. }
  3028. CoTaskMemFree(ci.pszPath);
  3029. }
  3030. pCChannelEnum->Release();
  3031. }
  3032. return;
  3033. }