chanmenu.cpp
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 21k
Category:

Windows Kernel

Development Platform:

Visual C++

  1. //\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\
  2. //
  3. // Chanmenu.cpp 
  4. //
  5. //   IConextMenu for folder items.
  6. //
  7. //   History:
  8. //
  9. //       6/12/97  edwardp   Created.
  10. //
  11. ////////////////////////////////////////////////////////////////////////////////
  12. //
  13. // Includes
  14. //
  15. #include "stdinc.h"
  16. #include "cdfidl.h"
  17. #include "xmlutil.h"
  18. #include "chanmenu.h"
  19. #include "dll.h"
  20. #include "persist.h"
  21. #include "resource.h"
  22. #include "chanapi.h"
  23. #include "chanmgrp.h"
  24. #include "chanmgri.h"
  25. #define _SHDOCVW_
  26. #include <shdocvw.h>
  27. #include <mluisupp.h>
  28. #ifdef UNIX
  29. EXTERN_C char *MwGetXDisplayString( void );
  30. #ifdef UNICODE
  31. #define unixInvokeEditor unixInvokeEditorW
  32. #else
  33. #define unixInvokeEditor unixInvokeEditorA
  34. #endif /* UNICODE */
  35. static void unixInvokeEditorA(LPCSTR lpszPath)
  36. {
  37.     HKEY  hkeyUnix;
  38.     CHAR  szCommand [2*MAX_PATH];
  39.     CHAR  szCmdTempl[MAX_PATH+1];
  40.     CHAR  szName    [MAX_PATH+1];
  41.     CHAR  hKeyName  [MAX_PATH+1];
  42.     STARTUPINFOA st;
  43.     PROCESS_INFORMATION pi;
  44.     BOOL  bIsKnownEdit  = FALSE;
  45.     char  displayString [2*MAX_PATH];
  46.     DWORD editors       = 0;
  47.     DWORD type          = REG_SZ;
  48.     DWORD dwLength      = sizeof(szCmdTempl);
  49.     if( MwGetXDisplayString() )
  50.         sprintf( displayString, "-display %s", MwGetXDisplayString() );
  51.     else
  52.         sprintf( displayString, " ");
  53.     // Get user preferred editor.
  54.     if( getenv("EDITOR" ) )
  55.        strcpy(szName, getenv("EDITOR") );
  56.     else
  57.        strcpy(szName, "vi");
  58.     // Check editor against the list of known editors in
  59.     // registry.
  60.     sprintf( hKeyName,
  61.              "Software\Microsoft\Internet Explorer\Unix\Editors\%s",
  62.              szName );
  63.     LONG lResult = RegOpenKeyExA(
  64.        HKEY_CURRENT_USER,
  65.        hKeyName,
  66.        0,
  67.        KEY_QUERY_VALUE,
  68.        &hkeyUnix);
  69.     // Create proper command and append dissplay string to make the
  70.     // editor appear on the same XServer as the Iexplorer.
  71.     if( !bIsKnownEdit )
  72.     {
  73.         // Default use vi
  74.         sprintf( szCommand, "xterm %s -e vi %s ", displayString, lpszPath  );
  75.     }
  76.     else
  77.     {
  78.         // Use template command from registry to create actual command.
  79.         sprintf( szCommand, szCmdTempl, displayString, lpszPath );
  80.     }
  81.     // Initialize startup info struct.
  82.     st.cb = sizeof(STARTUPINFO);
  83.     st.lpReserved = NULL;
  84.     st.lpDesktop  = NULL;
  85.     st.lpTitle    = NULL;
  86.     st.dwFlags    = 0;
  87.     st.wShowWindow= SW_SHOWNORMAL;
  88.     st.cbReserved2= 0;
  89.     st.lpReserved2= NULL;
  90.     // Launch the command
  91.     if ( CreateProcessA( NULL, szCommand, NULL, NULL, TRUE,
  92.                          CREATE_NEW_CONSOLE, NULL, NULL, &st, &pi ))
  93.     {
  94.         return;
  95.     }
  96.     return;
  97. }
  98. static void unixInvokeEditorW(LPCWSTR lpwszPath)
  99. {
  100.    char szFileName[MAX_PATH+2]; /* same as in ViewSource */
  101.    
  102.    SHUnicodeToAnsi(lpwszPath,szFileName, ARRAYSIZE(szFileName));
  103.    unixInvokeEditorA(szFileName);
  104.  
  105.    return;
  106. }
  107. #endif /* UNIX */
  108. //
  109. // Constructor and destructor.
  110. //
  111. //\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\
  112. //
  113. // *** CContextMenu::CContextMenu ***
  114. //
  115. //    Constructor for IContextMenu.
  116. //
  117. ////////////////////////////////////////////////////////////////////////////////
  118. CChannelMenu::CChannelMenu (
  119.     void
  120. )
  121. : m_cRef(1)
  122. {
  123.     TraceMsg(TF_OBJECTS, "+ IContextMenu (root)");
  124.     DllAddRef();
  125.     ASSERT(NULL == m_pSubscriptionMgr);
  126.     ASSERT(NULL == m_bstrURL);
  127.     ASSERT(NULL == m_bstrName);
  128.     return;
  129. }
  130. //\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\
  131. //
  132. // *** CContextMenu::~CContextMenu ***
  133. //
  134. //    Destructor.
  135. //
  136. ////////////////////////////////////////////////////////////////////////////////
  137. CChannelMenu::~CChannelMenu (
  138.     void
  139. )
  140. {
  141.     ASSERT(0 == m_cRef);
  142.     if (NULL != m_bstrURL)
  143.         SysFreeString(m_bstrURL);
  144.     if (NULL != m_bstrName)
  145.         SysFreeString(m_bstrName);
  146.         
  147.     if (NULL != m_pSubscriptionMgr)
  148.         m_pSubscriptionMgr->Release();
  149.     //
  150.     // Matching Release for the constructor Addref.
  151.     //
  152.     TraceMsg(TF_OBJECTS, "- IContextMenu (root)");
  153.     DllRelease();
  154.     return;
  155. }
  156. //
  157. // IUnknown methods.
  158. //
  159. //\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\
  160. //
  161. // *** CContextMenu::CContextMenu ***
  162. //
  163. //    CExtractIcon QI.
  164. //
  165. ////////////////////////////////////////////////////////////////////////////////
  166. STDMETHODIMP
  167. CChannelMenu::QueryInterface (
  168.     REFIID riid,
  169.     void **ppv
  170. )
  171. {
  172.     ASSERT(ppv);
  173.     HRESULT hr;
  174.     *ppv = NULL;
  175.     if (IID_IUnknown == riid || IID_IContextMenu == riid)
  176.     {
  177.         *ppv = (IContextMenu*)this;
  178.     }
  179.     else if (IID_IShellExtInit == riid)
  180.     {
  181.         *ppv = (IShellExtInit*)this;
  182.     }
  183.     if (*ppv)
  184.     {
  185.         ((IUnknown*)*ppv)->AddRef();
  186.         hr = S_OK;
  187.     }
  188.     else
  189.     {
  190.         hr = E_NOINTERFACE;
  191.     }
  192.     ASSERT((SUCCEEDED(hr) && *ppv) || (FAILED(hr) && NULL == *ppv));
  193.     return hr;
  194. }
  195. //\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\
  196. //
  197. // *** CContextMenu::AddRef ***
  198. //
  199. //    CContextMenu AddRef.
  200. //
  201. ////////////////////////////////////////////////////////////////////////////////
  202. STDMETHODIMP_(ULONG)
  203. CChannelMenu::AddRef (
  204.     void
  205. )
  206. {
  207.     ASSERT(m_cRef != 0);
  208.     ASSERT(m_cRef < (ULONG)-1);
  209.     return ++m_cRef;
  210. }
  211. //\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\
  212. //
  213. // *** CContextMenu::Release ***
  214. //
  215. //    CContextMenu Release.
  216. //
  217. ////////////////////////////////////////////////////////////////////////////////
  218. STDMETHODIMP_(ULONG)
  219. CChannelMenu::Release (
  220.     void
  221. )
  222. {
  223.     ASSERT (m_cRef != 0);
  224.     ULONG cRef = --m_cRef;
  225.     
  226.     if (0 == cRef)
  227.         delete this;
  228.     return cRef;
  229. }
  230. //
  231. // IContextMenu methods.
  232. //
  233. //\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\
  234. //
  235. // *** CContextMenu::QueryContextMenu ***
  236. //
  237. //
  238. // Description:
  239. //     Adds menu items to the given item's context menu.
  240. //
  241. // Parameters:
  242. //     [In Out]  hmenu      - A handle to the menu.  New items are inserted into
  243. //                            this menu  
  244. //     [In]      indexMenu  - Zero-based position at which to insert the first
  245. //                            menu item.
  246. //     [In]      idCmdFirst - Minimum value that can be used for a new menu item
  247. //                            identifier. 
  248. //     [In]      idCmdLast  - Maximum value the can be used for a menu item id.
  249. //     [In]      uFlags     - CMF_DEFAULTONLY, CMF_EXPLORE, CMF_NORMAL or
  250. //                            CMF_VERBSONLY.
  251. //
  252. // Return:
  253. //     On success the scode contains the the menu identifier offset of the last
  254. //     menu item added plus one.
  255. //
  256. // Comments:
  257. //     CMF_DEFAULTONLY flag indicates the user double-clicked on the item.  In
  258. //     this case no menu is displayed.  The shell is simply querying for the ID
  259. //     of the default action.
  260. //
  261. ////////////////////////////////////////////////////////////////////////////////
  262. STDMETHODIMP
  263. CChannelMenu::QueryContextMenu(
  264.     HMENU hmenu,
  265.     UINT indexMenu,
  266.     UINT idCmdFirst,
  267.     UINT idCmdLast,
  268.     UINT uFlags
  269. )
  270. {
  271.     HRESULT hr = S_OK;
  272.     BOOL fSubscribed;
  273.     HMENU hChannelMenu, hChannelSubMenu;
  274.     
  275.     ASSERT(hmenu);
  276.     ASSERT(idCmdFirst < idCmdLast);
  277.     if (!(CMF_DEFAULTONLY & uFlags))
  278.     {   
  279.         if (NULL != m_pSubscriptionMgr)
  280.         {
  281.             ASSERT(idCmdFirst + IDM_SUBSCRIBE < idCmdLast);
  282. #ifndef UNIX
  283.             if (CanSubscribe(m_bstrURL))
  284.             {
  285.                 m_pSubscriptionMgr->IsSubscribed(m_bstrURL, &fSubscribed);
  286.                 if (fSubscribed)
  287.                 {
  288.                     hChannelMenu = LoadMenu(MLGetHinst(), 
  289.                                            MAKEINTRESOURCE(IDM_SUBSCRIBEDMENU));
  290.                     if (SHRestricted2W(REST_NoRemovingSubscriptions, m_bstrURL, 0))
  291.                     {
  292.                         EnableMenuItem(hChannelMenu, IDM_SUBSCRIBE,
  293.                                        MF_BYCOMMAND | MF_GRAYED);
  294.                     }
  295.                     
  296.                     if (SHRestricted2W(REST_NoManualUpdates, m_bstrURL, 0))
  297.                     {
  298.                         EnableMenuItem(hChannelMenu, IDM_UPDATESUBSCRIPTION,
  299.                                        MF_BYCOMMAND | MF_GRAYED);
  300.                     }
  301.                 }
  302.                 else
  303.                 {
  304.                     int idMenu = !SHRestricted2W(REST_NoAddingSubscriptions, 
  305.                                                  m_bstrURL, 0) 
  306.                                  ? IDM_UNSUBSCRIBEDMENU : IDM_NOSUBSCRIBEMENU;
  307.                                   
  308.                     hChannelMenu = LoadMenu(MLGetHinst(), MAKEINTRESOURCE(idMenu));
  309.                 }
  310.             }
  311.             else
  312. #endif /* !UNIX */
  313.             {
  314.                 hChannelMenu = LoadMenu(MLGetHinst(),
  315.                                           MAKEINTRESOURCE(IDM_NOSUBSCRIBEMENU));
  316.             }
  317.             if (NULL != hChannelMenu)
  318.             {
  319.                 hChannelSubMenu = GetSubMenu(hChannelMenu, 0);
  320.                 if (NULL != hChannelSubMenu)
  321.                 {
  322.                     hr = Shell_MergeMenus(hmenu, hChannelSubMenu, indexMenu,
  323.                                           idCmdFirst, idCmdLast, MM_ADDSEPARATOR)
  324.                                           - idCmdFirst;
  325.                 }
  326.                 else
  327.                 {
  328.                     hr = E_FAIL;
  329.                 }
  330.                 DestroyMenu(hChannelMenu);
  331.             }
  332.             else
  333.             {
  334.                 hr = E_FAIL;
  335.             }
  336.         }
  337.         RemoveMenuItems(hmenu);
  338.     }
  339.     return hr;
  340. }
  341. //\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\
  342. //
  343. // *** CContextMenu::InvokeCommand ***
  344. //
  345. //
  346. // Description:
  347. //     Carries out the command for the given menu item id.
  348. //
  349. // Parameters:
  350. //     [In]  lpici - Structure containing the verb, hwnd, menu id, etc.
  351. //
  352. // Return:
  353. //     S_OK if the command was successful.
  354. //     E_FAIL otherwise.
  355. //
  356. // Comments:
  357. //
  358. //
  359. ////////////////////////////////////////////////////////////////////////////////
  360. STDMETHODIMP
  361. CChannelMenu::InvokeCommand(
  362.     LPCMINVOKECOMMANDINFO lpici
  363. )
  364. {
  365.     HRESULT hr = S_OK;
  366.     
  367.     ASSERT(lpici);
  368.     if (HIWORD(lpici->lpVerb) == 0)
  369.     {
  370.         switch (LOWORD(lpici->lpVerb))
  371.         {
  372.             case IDM_UPDATESUBSCRIPTION:
  373.                 ASSERT(NULL != m_pSubscriptionMgr);
  374.                 m_pSubscriptionMgr->UpdateSubscription(m_bstrURL);
  375.                 break;
  376.                            
  377.             case IDM_SUBSCRIBE:
  378.                 ASSERT(NULL != m_pSubscriptionMgr);
  379.                 ASSERT( sizeof(SUBSCRIPTIONINFO) == m_si.cbSize);
  380.                 hr = Subscribe(lpici->hwnd);
  381.                 break;
  382.                 
  383.             case IDM_UNSUBSCRIBE:
  384.                 ASSERT(NULL != m_pSubscriptionMgr);
  385.                 m_pSubscriptionMgr->DeleteSubscription(m_bstrURL, lpici->hwnd);
  386.                 break;
  387.             case IDM_EDITSUBSCRIPTION:
  388.                 ASSERT(NULL != m_pSubscriptionMgr);
  389.                 m_pSubscriptionMgr->ShowSubscriptionProperties(m_bstrURL,
  390.                                                                lpici->hwnd);
  391.                 break;
  392.             case IDM_REFRESHCHANNEL:
  393.                 Refresh(lpici->hwnd);
  394.                 break;
  395.             case IDM_VIEWSOURCE:
  396.                 ViewSource(lpici->hwnd);
  397.                 break;
  398.         }
  399.     }
  400.     
  401.     return hr;
  402. }
  403. //\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\
  404. //
  405. // *** CContextMenu::GetCommandString ***
  406. //
  407. //
  408. // Description:
  409. //
  410. //
  411. // Parameters:
  412. //
  413. //
  414. // Return:
  415. //
  416. //
  417. // Comments:
  418. //
  419. //
  420. ////////////////////////////////////////////////////////////////////////////////
  421. STDMETHODIMP
  422. CChannelMenu::GetCommandString(
  423.     UINT_PTR idCommand,
  424.     UINT uFLags,
  425.     UINT *pwReserved,
  426.     LPSTR pszName,
  427.     UINT cchMax
  428. )
  429. {
  430.     return E_NOTIMPL;
  431. }
  432. //
  433. //
  434. //
  435. STDMETHODIMP
  436. CChannelMenu::Initialize(
  437.     LPCITEMIDLIST pidl,
  438.     LPDATAOBJECT pdobj,
  439.     HKEY hkey
  440. )
  441. {
  442.     HRESULT hr;
  443.     
  444.     STGMEDIUM stgmed;
  445.     FORMATETC fmtetc = {CF_HDROP, NULL, DVASPECT_CONTENT, -1,
  446.                         TYMED_HGLOBAL};
  447.     ASSERT(pdobj);
  448.     
  449.     hr = pdobj->GetData(&fmtetc, &stgmed);
  450.     if (SUCCEEDED(hr))
  451.     {
  452.         if (DragQueryFile((HDROP)stgmed.hGlobal, 0, m_szPath, 
  453.                           ARRAYSIZE(m_szPath)))
  454.         {
  455.             m_tt.cbTriggerSize = sizeof(TASK_TRIGGER);
  456.             m_si.cbSize        = sizeof(SUBSCRIPTIONINFO);
  457.             m_si.fUpdateFlags |= SUBSINFO_SCHEDULE;
  458.             m_si.schedule      = SUBSSCHED_AUTO;
  459.             m_si.pTrigger = &m_tt;
  460.             hr = GetNameAndURLAndSubscriptionInfo(m_szPath, &m_bstrName, &m_bstrURL,
  461.                                                   &m_si);
  462.             ASSERT((SUCCEEDED(hr) && m_bstrName && m_bstrURL) || FAILED(hr));
  463.         }
  464.         else
  465.         {
  466.             hr = E_FAIL;
  467.         }
  468.         ReleaseStgMedium(&stgmed);
  469.         if (SUCCEEDED(hr))
  470.         {
  471.             hr = CoCreateInstance(CLSID_SubscriptionMgr, NULL,
  472.                                   CLSCTX_INPROC_SERVER, IID_ISubscriptionMgr,
  473.                                   (void**)&m_pSubscriptionMgr);
  474.         }
  475.     }
  476.     //  Return S_OK even if things didn't go as planned so that
  477.     //  RemoveMenus will get called.
  478.     return S_OK;
  479. }
  480. //
  481. // Helper functions
  482. //
  483. //\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\
  484. //
  485. // *** Name ***
  486. //
  487. //
  488. // Description:
  489. //
  490. //
  491. // Parameters:
  492. //
  493. //
  494. // Return:
  495. //
  496. //
  497. // Comments:
  498. //
  499. //
  500. ////////////////////////////////////////////////////////////////////////////////
  501. void
  502. CChannelMenu::RemoveMenuItems(
  503.     HMENU hmenu
  504. )
  505. {
  506.     TCHAR aszRemove[4][62] = {{0}, {0}, {0}, {0}};
  507.     MLLoadString(IDS_SHARING, aszRemove[0], ARRAYSIZE(aszRemove[0]));
  508.     MLLoadString(IDS_RENAME,  aszRemove[1], ARRAYSIZE(aszRemove[1]));
  509.     MLLoadString(IDS_SENDTO,  aszRemove[2], ARRAYSIZE(aszRemove[2]));
  510.     if (SHRestricted2W(REST_NoEditingChannels, NULL, 0))
  511.         MLLoadString(IDS_PROPERTIES, aszRemove[3], ARRAYSIZE(aszRemove[3]));
  512.     TCHAR           szBuffer[62];
  513.     MENUITEMINFO    mii;
  514.     mii.cbSize     = sizeof(MENUITEMINFO);
  515.     mii.fMask      = MIIM_TYPE;
  516.     for (int i = GetMenuItemCount(hmenu) - 1; i >= 0; i--)
  517.     {
  518.         mii.dwTypeData = szBuffer;
  519.         mii.cch = ARRAYSIZE(szBuffer);
  520.         if (GetMenuItemInfo(hmenu, i, TRUE, &mii) && mii.cch)
  521.         {
  522.             for (int j = 0; j < ARRAYSIZE(aszRemove); j++)
  523.             {
  524.                 if (StrEql(aszRemove[j], mii.dwTypeData))
  525.                 {
  526.                     DeleteMenu(hmenu, i, MF_BYPOSITION);
  527.                     break;
  528.                 }
  529.             }
  530.         }
  531.     }
  532.     return;
  533. }
  534. void CChannelMenu::Refresh(HWND hwnd)
  535. {
  536.     IXMLDocument* pIXMLDocument;
  537.     DLL_ForcePreloadDlls(PRELOAD_MSXML);
  538.     
  539.     HRESULT hr = CoCreateInstance(CLSID_XMLDocument, NULL, CLSCTX_INPROC_SERVER,
  540.                                   IID_IXMLDocument, (void**)&pIXMLDocument);
  541.     if (SUCCEEDED(hr))
  542.     {
  543.         ASSERT(pIXMLDocument);
  544.         if (DownloadCdfUI(hwnd, m_bstrURL, pIXMLDocument))
  545.         {
  546.             UpdateImage(m_szPath);
  547.             SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_PATH | SHCNF_FLUSH,
  548.                            (void*)m_szPath, NULL);
  549.         }
  550.         pIXMLDocument->Release();
  551.     }
  552. }
  553. static TCHAR c_szFileProtocol[] = TEXT("file:");
  554. static TCHAR c_szCDFExtension[] = TEXT(".cdf");
  555. static TCHAR c_szShellEdit[] = TEXT("\shell\edit\command");
  556. static TCHAR c_szEditVerb[] = TEXT("edit");
  557. static TCHAR c_szChannelFile[] = TEXT("ChannelFile");
  558. static TCHAR c_szChannelFileEdit[] = TEXT("ChannelFile\shell\edit\command");
  559. static TCHAR c_szNotepad[] = TEXT("notepad.exe");
  560. void CChannelMenu::ViewSource(HWND hwnd)
  561. {
  562.     TCHAR szProgId[64] = TEXT("");
  563.     TCHAR szBuf[INTERNET_MAX_URL_LENGTH];
  564.     TCHAR szFile[MAX_PATH + 2]; // Leave room for quotes
  565.     DWORD cch, dwType;
  566.     SHELLEXECUTEINFO sei;
  567.     BOOL fFoundProg = FALSE;
  568.     TraceMsg(TF_OBJECTS, "+ IContextMenu ViewSource %ls", m_bstrURL);
  569.     if (SHUnicodeToTChar(m_bstrURL, szBuf, ARRAYSIZE(szBuf)))
  570.     {
  571.         if (SUCCEEDED(URLGetLocalFileName(szBuf, szFile, ARRAYSIZE(szFile),
  572.                                           NULL)))
  573.         {
  574.             if (StrCmpNI(szFile, c_szFileProtocol, 5) == 0)
  575.             {
  576.                 ASSERT(ARRAYSIZE(szFile) < ARRAYSIZE(szBuf));
  577.                 StrCpy(szBuf, szFile);
  578.                 cch = ARRAYSIZE(szFile) - 2;
  579.                 PathCreateFromUrl(szBuf, szFile, &cch, 0);
  580.             }
  581.             PathQuoteSpaces(szFile);
  582.             //  
  583.             //  We don't just call ShellExec with edit verb since
  584.             //  who knows what the file extension will be.
  585.             //
  586.             cch = ARRAYSIZE(szProgId);
  587.             if (ERROR_SUCCESS == SHGetValue(HKEY_CLASSES_ROOT, 
  588.                                             c_szCDFExtension, 
  589.                                             NULL, &dwType, 
  590.                                             szProgId, &cch)
  591.                 )
  592.             {
  593.                 ASSERT(ARRAYSIZE(szProgId) < ARRAYSIZE(szBuf));
  594.                 StrCpy(szBuf, szProgId);
  595.                 ASSERT(ARRAYSIZE(szProgId) + ARRAYSIZE(c_szShellEdit) <
  596.                        ARRAYSIZE(szBuf));
  597.                 StrCat(szBuf, c_szShellEdit);
  598.                 cch = ARRAYSIZE(szBuf);
  599.                                     
  600.                 if (ERROR_SUCCESS == SHGetValue(HKEY_CLASSES_ROOT, szBuf, 
  601.                                                 NULL, &dwType, szBuf, &cch)
  602.                     )
  603.                 {
  604.                     //
  605.                     // Getting here means they have an edit verb for CDF files
  606.                     //
  607.                     fFoundProg = TRUE;
  608.                 }
  609.             }
  610.             //  
  611.             //  If we haven't found a class key yet and the CDF ProgID 
  612.             //  isn't ours, then fall back to our edit verb.
  613.             //
  614.             if (!fFoundProg && StrCmpI(szProgId, c_szChannelFile))
  615.             {
  616.                 cch = ARRAYSIZE(szBuf);
  617.                 if (ERROR_SUCCESS == SHGetValue(HKEY_CLASSES_ROOT, 
  618.                                                 c_szChannelFileEdit, 
  619.                                                 NULL, &dwType, 
  620.                                                 szBuf, &cch)
  621.                    )
  622.                 {
  623.                     fFoundProg = TRUE;
  624.                     ASSERT(ARRAYSIZE(c_szChannelFile) < ARRAYSIZE(szProgId));
  625.                     StrCpy(szProgId, c_szChannelFile);
  626.                 }
  627.             }
  628.             memset(&sei, 0, sizeof(sei));
  629.             sei.cbSize = sizeof(sei);
  630.             sei.hwnd = hwnd;
  631.             sei.nShow = SW_SHOW;
  632.             
  633.             if (fFoundProg)
  634.             {
  635.                 sei.fMask = SEE_MASK_CLASSNAME;
  636.                 sei.lpVerb = c_szEditVerb;
  637.                 sei.lpFile = szFile;
  638.                 sei.lpClass = szProgId;
  639.                 TraceMsg(TF_OBJECTS, "IContextMenu ViewSource progid=%s file=%s", szProgId, szFile);
  640.             }
  641.             else
  642.             {
  643.                 sei.lpFile = c_szNotepad;
  644.                 sei.lpParameters = szFile;
  645.                 TraceMsg(TF_OBJECTS, "IContextMenu ViewSource Notepad file=%s", szFile);
  646.             }
  647. #ifndef UNIX
  648.             ShellExecuteEx(&sei);
  649. #else
  650.             unixInvokeEditor(szFile);
  651. #endif /* UNIX */
  652.         }
  653.         else
  654.         {
  655.             CDFMessageBox(hwnd, IDS_ERROR_NO_CACHE_ENTRY, IDS_ERROR_DLG_TITLE,
  656.                             MB_OK | MB_ICONEXCLAMATION, szBuf);
  657.         }
  658.     }
  659.     else
  660.     {
  661.         TraceMsg(TF_OBJECTS, "IContextMenu ViewSource couldn't convert to TSTR");
  662.     }
  663.     TraceMsg(TF_OBJECTS, "- IContextMenu ViewSource");
  664. }
  665. HRESULT CChannelMenu::Subscribe(HWND hwnd)
  666. {
  667.     HRESULT hr = S_OK;
  668.     CChannelMgr *pChannelMgr = new CChannelMgr;
  669.     if (pChannelMgr)
  670.     {
  671.         hr = pChannelMgr->AddAndSubscribeEx2(hwnd, m_bstrURL, m_pSubscriptionMgr, TRUE);
  672.         pChannelMgr->Release();
  673.         if (SUCCEEDED(hr) && (NULL != m_pSubscriptionMgr))
  674.         {
  675.             hr = m_pSubscriptionMgr->UpdateSubscription(m_bstrURL);
  676.         }
  677.     }
  678.     else
  679.     {
  680.         hr = E_OUTOFMEMORY;
  681.     }
  682.     return hr;
  683. }