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.

695 lines
19 KiB

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