Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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