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.

775 lines
22 KiB

  1. #include "shellprv.h"
  2. #include "ids.h"
  3. #include <shlwapi.h>
  4. #include "openwith.h"
  5. #include "uemapp.h"
  6. #include "mtpt.h"
  7. #include "fassoc.h"
  8. #include "filetbl.h"
  9. #include "datautil.h"
  10. #include <dpa.h>
  11. #include "defcm.h"
  12. #define TF_OPENWITHMENU 0x00000000
  13. #define SZOPENWITHLIST TEXT("OpenWithList")
  14. #define REGSTR_PATH_EXPLORER_FILEEXTS TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts")
  15. #define OPEN_WITH_LIST_MAX_ITEMS 10
  16. //
  17. // OpenWithListOpen()
  18. // allocates and initializes the state for the openwithlist
  19. //
  20. HRESULT OpenWithListOpen(IN LPCTSTR pszExt, HANDLE *phmru)
  21. {
  22. *phmru = 0;
  23. if (pszExt && *pszExt)
  24. {
  25. TCHAR szSubKey[MAX_PATH];
  26. // Build up the subkey string.
  27. wnsprintf(szSubKey, SIZECHARS(szSubKey), TEXT("%s\\%s\\%s"), REGSTR_PATH_EXPLORER_FILEEXTS, pszExt, SZOPENWITHLIST);
  28. MRUINFO mi = {sizeof(mi), OPEN_WITH_LIST_MAX_ITEMS, 0, HKEY_CURRENT_USER, szSubKey, NULL};
  29. *phmru = CreateMRUList(&mi);
  30. }
  31. return *phmru ? S_OK : E_OUTOFMEMORY;
  32. }
  33. HRESULT _AddItem(HANDLE hmru, LPCTSTR pszName)
  34. {
  35. HRESULT hr = S_OK;
  36. if (hmru)
  37. {
  38. int cItems = EnumMRUList(hmru, -1, NULL, 0);
  39. // just trim us down to make room...
  40. while (cItems >= OPEN_WITH_LIST_MAX_ITEMS)
  41. DelMRUString(hmru, --cItems);
  42. if (0 > AddMRUString(hmru, pszName))
  43. hr = E_UNEXPECTED;
  44. }
  45. return hr;
  46. }
  47. void _DeleteItem(HANDLE hmru, LPCTSTR pszName)
  48. {
  49. int iItem = FindMRUString(hmru, pszName, NULL);
  50. if (0 <= iItem)
  51. {
  52. DelMRUString(hmru, iItem);
  53. }
  54. }
  55. void _AddProgidForExt(LPCWSTR pszExt);
  56. STDAPI OpenWithListRegister(DWORD dwFlags, LPCTSTR pszExt, LPCTSTR pszVerb, HKEY hkProgid)
  57. {
  58. //
  59. // ----> Peruser entries are stored here
  60. // HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts
  61. // \.Ext
  62. // Application = "foo.exe"
  63. // \OpenWithList
  64. // MRUList = "ab"
  65. // a = "App.exe"
  66. // b = "foo.exe"
  67. //
  68. // ----> for permanent entries are stored un HKCR
  69. // HKCR
  70. // \.Ext
  71. // \OpenWithList
  72. // \app.exe
  73. //
  74. // ----> and applications or the system can write app association here
  75. // \Applications
  76. // \APP.EXE
  77. // \shell...
  78. // \foo.exe
  79. // \shell...
  80. //
  81. //
  82. HANDLE hmru;
  83. HRESULT hr = OpenWithListOpen(pszExt, &hmru);
  84. if (SUCCEEDED(hr))
  85. {
  86. TCHAR szPath[MAX_PATH];
  87. hr = AssocQueryStringByKey(ASSOCF_VERIFY, ASSOCSTR_EXECUTABLE, hkProgid, pszVerb, szPath, (LPDWORD)MAKEINTRESOURCE(SIZECHARS(szPath)));
  88. if (SUCCEEDED(hr))
  89. {
  90. LPCTSTR pszExe = PathFindFileName(szPath);
  91. if (IsPathInOpenWithKillList(pszExe))
  92. hr = E_ACCESSDENIED;
  93. else
  94. hr = AssocMakeApplicationByKey(ASSOCMAKEF_VERIFY, hkProgid, pszVerb);
  95. if (SUCCEEDED(hr))
  96. {
  97. TraceMsg(TF_OPENWITHMENU, "[%X] OpenWithListRegister() adding %s",hmru, pszExe);
  98. hr = _AddItem(hmru, pszExe);
  99. }
  100. if (FAILED(hr))
  101. _DeleteItem(hmru, pszExe);
  102. }
  103. FreeMRUList(hmru);
  104. }
  105. _AddProgidForExt(pszExt);
  106. return hr;
  107. }
  108. STDAPI_(void) OpenWithListSoftRegisterProcess(DWORD dwFlags, LPCTSTR pszExt, LPCTSTR pszProcess)
  109. {
  110. HANDLE hmru;
  111. if (SUCCEEDED(OpenWithListOpen(pszExt, &hmru)))
  112. {
  113. TCHAR szApp[MAX_PATH];
  114. if (!pszProcess)
  115. {
  116. if (GetModuleFileName(NULL, szApp, SIZECHARS(szApp)))
  117. pszProcess = szApp;
  118. }
  119. if (pszProcess && !IsPathInOpenWithKillList(pszProcess))
  120. _AddItem(hmru, PathFindFileName(pszProcess));
  121. FreeMRUList(hmru);
  122. }
  123. }
  124. class COpenWithArray : public CDPA<CAppInfo>
  125. {
  126. public:
  127. ~COpenWithArray();
  128. HRESULT FillArray(PCWSTR pszExt);
  129. private:
  130. static int CALLBACK _DeleteAppInfo(CAppInfo *pai, void *pv)
  131. { if (pai) delete pai; return 1; }
  132. };
  133. COpenWithArray::~COpenWithArray()
  134. {
  135. if ((HDPA)this)
  136. DestroyCallback(_DeleteAppInfo, NULL);
  137. }
  138. HRESULT COpenWithArray::FillArray(PCWSTR pszExt)
  139. {
  140. IEnumAssocHandlers *penum;
  141. HRESULT hr = SHAssocEnumHandlers(pszExt, &penum);
  142. if (SUCCEEDED(hr))
  143. {
  144. IAssocHandler *pah;
  145. while (S_OK == penum->Next(1, &pah, NULL))
  146. {
  147. // we only want the best
  148. if (S_OK == pah->IsRecommended())
  149. {
  150. CAppInfo *pai = new CAppInfo(pah);
  151. if (pai)
  152. {
  153. if (pai->Init())
  154. {
  155. // Trim duplicate items before we add them for other programs
  156. int i = 0;
  157. for (; i < GetPtrCount(); i++)
  158. {
  159. if (0 == lstrcmpi(pai->Name(), GetPtr(i)->Name()))
  160. {
  161. // its a match
  162. break;
  163. }
  164. }
  165. // if we dont add this to the dpa
  166. // then we need to clean it up
  167. if (i == GetPtrCount() && -1 != AppendPtr(pai))
  168. pai = NULL;
  169. }
  170. if (pai)
  171. delete pai;
  172. }
  173. }
  174. pah->Release();
  175. }
  176. penum->Release();
  177. }
  178. return hr;
  179. }
  180. class COpenWithMenu : public IContextMenu3, IShellExtInit
  181. {
  182. // IUnknown
  183. STDMETHOD(QueryInterface)(REFIID riid, void **ppvObj);
  184. STDMETHOD_(ULONG,AddRef)(void);
  185. STDMETHOD_(ULONG,Release)(void);
  186. // IContextMenu
  187. STDMETHOD(QueryContextMenu)(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags);
  188. STDMETHOD(InvokeCommand)(LPCMINVOKECOMMANDINFO lpici);
  189. STDMETHOD(GetCommandString)(UINT_PTR idCmd, UINT uType, UINT *pRes, LPSTR pszName, UINT cchMax);
  190. // IContextMenu2
  191. STDMETHOD(HandleMenuMsg)(UINT uMsg, WPARAM wParam, LPARAM lParam);
  192. // IContextMenu3
  193. STDMETHOD(HandleMenuMsg2)(UINT uMsg, WPARAM wParam, LPARAM lParam,LRESULT *lResult);
  194. // IShellExtInit
  195. STDMETHOD(Initialize)(LPCITEMIDLIST pidlFolder, IDataObject *pdtobj, HKEY hkeyProgID);
  196. friend HRESULT COpenWithMenu_CreateInstance(IUnknown* pUnkOuter, REFIID riid, void **ppvOut);
  197. protected: // methods
  198. COpenWithMenu();
  199. ~COpenWithMenu();
  200. //Handle Menu messages submitted to HandleMenuMsg
  201. void DrawItem(DRAWITEMSTRUCT *lpdi);
  202. LRESULT MeasureItem(MEASUREITEMSTRUCT *lpmi);
  203. BOOL InitMenuPopup(HMENU hMenu);
  204. //Internal Helpers
  205. HRESULT _GetHelpText(UINT_PTR idCmd, LPSTR pszName, UINT cchMax, BOOL fUnicode);
  206. HRESULT _MatchMenuItem(TCHAR ch, LRESULT* plRes);
  207. protected: // members
  208. LONG _cRef;
  209. HMENU _hMenu;
  210. BOOL _fMenuNeedsInit;
  211. UINT _idCmdFirst;
  212. COpenWithArray _owa;
  213. int _nItems;
  214. UINT _uFlags;
  215. IDataObject *_pdtobj;
  216. TCHAR _szPath[MAX_PATH];
  217. };
  218. COpenWithMenu::COpenWithMenu() : _cRef(1)
  219. {
  220. TraceMsg(TF_OPENWITHMENU, "ctor COpenWithMenu %x", this);
  221. }
  222. COpenWithMenu::~COpenWithMenu()
  223. {
  224. TraceMsg(TF_OPENWITHMENU, "dtor COpenWithMenu %x", this);
  225. if (_pdtobj)
  226. _pdtobj->Release();
  227. if (_hMenu)
  228. {
  229. ASSERT(_nItems);
  230. DestroyMenu(_hMenu);
  231. }
  232. }
  233. STDAPI COpenWithMenu_CreateInstance(IUnknown* pUnkOuter, REFIID riid, void **ppvOut)
  234. {
  235. *ppvOut = NULL;
  236. if (pUnkOuter)
  237. return CLASS_E_NOAGGREGATION;
  238. COpenWithMenu * powm = new COpenWithMenu();
  239. if (!powm)
  240. return E_OUTOFMEMORY;
  241. HRESULT hr = powm->QueryInterface(riid, ppvOut);
  242. powm->Release();
  243. return hr;
  244. }
  245. HRESULT COpenWithMenu::QueryInterface(REFIID riid, void **ppvObj)
  246. {
  247. static const QITAB qit[] = {
  248. QITABENTMULTI(COpenWithMenu, IContextMenu, IContextMenu3),
  249. QITABENTMULTI(COpenWithMenu, IContextMenu2, IContextMenu3),
  250. QITABENT(COpenWithMenu, IContextMenu3),
  251. QITABENT(COpenWithMenu, IShellExtInit),
  252. { 0 },
  253. };
  254. return QISearch(this, qit, riid, ppvObj);
  255. }
  256. ULONG COpenWithMenu::AddRef()
  257. {
  258. return InterlockedIncrement(&_cRef);
  259. }
  260. ULONG COpenWithMenu::Release()
  261. {
  262. ASSERT( 0 != _cRef );
  263. ULONG cRef = InterlockedDecrement(&_cRef);
  264. if ( 0 == cRef )
  265. {
  266. delete this;
  267. }
  268. return cRef;
  269. }
  270. /*
  271. Purpose:
  272. Add Open/Edit/Default verb to extension app list
  273. */
  274. HRESULT AddVerbItems(LPCTSTR pszExt)
  275. {
  276. IQueryAssociations *pqa;
  277. HRESULT hr = AssocCreate(CLSID_QueryAssociations, IID_PPV_ARG(IQueryAssociations, &pqa));
  278. if (SUCCEEDED(hr))
  279. {
  280. hr = pqa->Init(0, pszExt, NULL, NULL);
  281. if (SUCCEEDED(hr))
  282. {
  283. HKEY hkeyClass;
  284. hr = pqa->GetKey(0, ASSOCKEY_SHELLEXECCLASS, NULL, &hkeyClass);
  285. if (SUCCEEDED(hr))
  286. {
  287. OpenWithListRegister(0, pszExt, NULL, hkeyClass);
  288. RegCloseKey(hkeyClass);
  289. }
  290. // we add in the editor too
  291. if (SUCCEEDED(pqa->GetKey(0, ASSOCKEY_SHELLEXECCLASS, L"Edit", &hkeyClass)))
  292. {
  293. OpenWithListRegister(0, pszExt, NULL, hkeyClass);
  294. RegCloseKey(hkeyClass);
  295. }
  296. hr = S_OK;
  297. }
  298. pqa->Release();
  299. }
  300. return hr;
  301. }
  302. //
  303. // Our context menu IDs are assigned like this
  304. //
  305. // idCmdFirst = Open With Custom Program (either on main menu or on popup)
  306. // idCmdFirst+1 through idCmdFirst+_nItems = Open With program in OpenWithList
  307. #define OWMENU_BROWSE 0
  308. #define OWMENU_APPFIRST 1
  309. HRESULT COpenWithMenu::QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags)
  310. {
  311. MENUITEMINFO mii;
  312. LPTSTR pszExt;
  313. TCHAR szOpenWithMenu[80];
  314. _idCmdFirst = idCmdFirst;
  315. _uFlags = uFlags;
  316. if (SUCCEEDED(PathFromDataObject(_pdtobj, _szPath, ARRAYSIZE(_szPath))))
  317. {
  318. // No openwith context menu for executables.
  319. if (PathIsExe(_szPath))
  320. return S_OK;
  321. pszExt = PathFindExtension(_szPath);
  322. if (pszExt && *pszExt)
  323. {
  324. // Add Open/Edit/Default verb to extension app list
  325. if (SUCCEEDED(AddVerbItems(pszExt)))
  326. {
  327. // Do this only if AddVerbItems succeeded; otherwise,
  328. // we would create an empty MRU for a nonexisting class,
  329. // causing the class to spring into existence and cause
  330. // the "Open With" dialog to think we are overriding
  331. // rather than creating new.
  332. // get extension app list
  333. if (_owa.Create(4) && SUCCEEDED(_owa.FillArray(pszExt)))
  334. {
  335. _nItems = _owa.GetPtrCount();
  336. if (1 == _nItems)
  337. {
  338. // For known file type(there is at least one verb under its progid),
  339. // if there is only one item in its openwithlist, don't show open with sub menu
  340. _nItems = 0;
  341. }
  342. }
  343. }
  344. }
  345. }
  346. LoadString(g_hinst, (_nItems ? IDS_OPENWITH : IDS_OPENWITHNEW), szOpenWithMenu, ARRAYSIZE(szOpenWithMenu));
  347. if (_nItems)
  348. {
  349. // we need to create a submenu
  350. // with all of our goodies
  351. _hMenu = CreatePopupMenu();
  352. if (_hMenu)
  353. {
  354. _fMenuNeedsInit = TRUE;
  355. mii.cbSize = sizeof(MENUITEMINFO);
  356. mii.fMask = MIIM_ID|MIIM_TYPE|MIIM_DATA;
  357. mii.wID = idCmdFirst+OWMENU_APPFIRST;
  358. mii.fType = MFT_STRING;
  359. mii.dwTypeData = szOpenWithMenu;
  360. mii.dwItemData = 0;
  361. InsertMenuItem(_hMenu,0,TRUE,&mii);
  362. mii.fMask = MIIM_ID|MIIM_SUBMENU|MIIM_TYPE;
  363. mii.fType = MFT_STRING;
  364. mii.wID = idCmdFirst+OWMENU_BROWSE;
  365. mii.hSubMenu = _hMenu;
  366. mii.dwTypeData = szOpenWithMenu;
  367. InsertMenuItem(hmenu,indexMenu,TRUE,&mii);
  368. }
  369. }
  370. else
  371. {
  372. mii.cbSize = sizeof(MENUITEMINFO);
  373. mii.fMask = MIIM_ID|MIIM_TYPE|MIIM_DATA;
  374. mii.fType = MFT_STRING;
  375. mii.wID = idCmdFirst+OWMENU_BROWSE;
  376. mii.dwTypeData = szOpenWithMenu;
  377. mii.dwItemData = 0;
  378. InsertMenuItem(hmenu,indexMenu,TRUE,&mii);
  379. }
  380. return ResultFromShort(_nItems + 1);
  381. }
  382. HRESULT COpenWithMenu::InvokeCommand(LPCMINVOKECOMMANDINFO pici)
  383. {
  384. HRESULT hr = E_OUTOFMEMORY;
  385. CMINVOKECOMMANDINFOEX ici;
  386. void * pvFree;
  387. // maybe these two routines should be collapsed into one?
  388. if ((IS_INTRESOURCE(pici->lpVerb) || 0 == lstrcmpiA(pici->lpVerb, "openas"))
  389. && SUCCEEDED(ICI2ICIX(pici, &ici, &pvFree)))
  390. {
  391. BOOL fOpenAs = TRUE;
  392. if (pici->lpVerb && IS_INTRESOURCE(pici->lpVerb))
  393. {
  394. int i = LOWORD(pici->lpVerb) - OWMENU_APPFIRST;
  395. if (i < _owa.GetPtrCount())
  396. {
  397. hr = _owa.GetPtr(i)->Handler()->Invoke(&ici, _szPath);
  398. fOpenAs = FALSE;
  399. }
  400. }
  401. if (fOpenAs)
  402. {
  403. SHELLEXECUTEINFO ei = {0};
  404. hr = ICIX2SEI(&ici, &ei);
  405. if (SUCCEEDED(hr))
  406. {
  407. // use the "Unknown" key so we get the openwith prompt
  408. ei.lpFile = _szPath;
  409. // dont do the zone check before the user picks the app.
  410. // wait until they actually try to invoke the file.
  411. ei.fMask |= SEE_MASK_NOZONECHECKS;
  412. RegOpenKeyEx(HKEY_CLASSES_ROOT, TEXT("Unknown"), 0, MAXIMUM_ALLOWED, &ei.hkeyClass);
  413. if (!(_uFlags & CMF_DEFAULTONLY))
  414. {
  415. // defview sets CFM_DEFAULTONLY when the user is double-clicking. We check it
  416. // here since we want do NOT want to query the class store if the user explicitly
  417. // right-clicked on the menu and choo se openwith.
  418. // pop up open with dialog without querying class store
  419. ei.fMask |= SEE_MASK_NOQUERYCLASSSTORE;
  420. }
  421. if (ei.hkeyClass)
  422. {
  423. ei.fMask |= SEE_MASK_CLASSKEY;
  424. if (ShellExecuteEx(&ei))
  425. {
  426. hr = S_OK;
  427. if (UEMIsLoaded())
  428. {
  429. // note that we already got a UIBL_DOTASSOC (from
  430. // OpenAs_RunDLL or whatever it is that 'Unknown'
  431. // runs). so the Uassist analysis app will have to
  432. // subtract it off
  433. UEMFireEvent(&UEMIID_SHELL, UEME_INSTRBROWSER, UEMF_INSTRUMENT, UIBW_RUNASSOC, UIBL_DOTNOASSOC);
  434. }
  435. }
  436. else
  437. {
  438. hr = HRESULT_FROM_WIN32(GetLastError());
  439. }
  440. RegCloseKey(ei.hkeyClass);
  441. }
  442. else
  443. hr = E_FAIL;
  444. }
  445. }
  446. LocalFree(pvFree); // accepts NULL
  447. }
  448. return hr;
  449. }
  450. HRESULT COpenWithMenu::_GetHelpText(UINT_PTR idCmd, LPSTR pszName, UINT cchMax, BOOL fUnicode)
  451. {
  452. UINT ids;
  453. LPCTSTR pszFriendly = NULL;
  454. if (idCmd == OWMENU_BROWSE)
  455. {
  456. ids = IDS_OPENWITHHELP;
  457. pszFriendly = TEXT("");
  458. }
  459. else if ((idCmd-OWMENU_APPFIRST) < (UINT_PTR)_owa.GetPtrCount())
  460. {
  461. ids = IDS_OPENWITHAPPHELP;
  462. pszFriendly = _owa.GetPtr(idCmd-OWMENU_APPFIRST)->UIName();
  463. }
  464. if (!pszFriendly)
  465. return E_FAIL;
  466. if (fUnicode)
  467. {
  468. WCHAR wszFormat[80];
  469. LoadStringW(HINST_THISDLL, ids, wszFormat, ARRAYSIZE(wszFormat));
  470. wnsprintfW((LPWSTR)pszName, cchMax, wszFormat, pszFriendly);
  471. }
  472. else
  473. {
  474. CHAR szFormat[80];
  475. LoadStringA(HINST_THISDLL, ids, szFormat, ARRAYSIZE(szFormat));
  476. wnsprintfA(pszName, cchMax, szFormat, pszFriendly);
  477. }
  478. return S_OK;
  479. }
  480. const ICIVERBTOIDMAP c_sIDVerbMap[] =
  481. {
  482. { L"openas", "openas", OWMENU_BROWSE, OWMENU_BROWSE, },
  483. };
  484. HRESULT COpenWithMenu::GetCommandString(UINT_PTR idCmd, UINT uType, UINT *pRes, LPSTR pszName, UINT cchMax)
  485. {
  486. switch (uType)
  487. {
  488. case GCS_VERBA:
  489. case GCS_VERBW:
  490. return SHMapCmdIDToVerb(idCmd, c_sIDVerbMap, ARRAYSIZE(c_sIDVerbMap), pszName, cchMax, GCS_VERBW == uType);
  491. case GCS_HELPTEXTA:
  492. case GCS_HELPTEXTW:
  493. return _GetHelpText(idCmd, pszName, cchMax, uType == GCS_HELPTEXTW);
  494. }
  495. return E_NOTIMPL;
  496. }
  497. HRESULT COpenWithMenu::HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam)
  498. {
  499. return HandleMenuMsg2(uMsg,wParam,lParam,NULL);
  500. }
  501. // Defined in fsmenu.cpp
  502. BOOL _MenuCharMatch(LPCTSTR lpsz, TCHAR ch, BOOL fIgnoreAmpersand);
  503. HRESULT COpenWithMenu::_MatchMenuItem(TCHAR ch, LRESULT* plRes)
  504. {
  505. if (plRes == NULL)
  506. return S_FALSE;
  507. int iLastSelectedItem = -1;
  508. int iNextMatch = -1;
  509. BOOL fMoreThanOneMatch = FALSE;
  510. int c = GetMenuItemCount(_hMenu);
  511. // Pass 1: Locate the Selected Item
  512. for (int i = 0; i < c; i++)
  513. {
  514. MENUITEMINFO mii = {0};
  515. mii.cbSize = sizeof(mii);
  516. mii.fMask = MIIM_STATE;
  517. if (GetMenuItemInfo(_hMenu, i, MF_BYPOSITION, &mii))
  518. {
  519. if (mii.fState & MFS_HILITE)
  520. {
  521. iLastSelectedItem = i;
  522. break;
  523. }
  524. }
  525. }
  526. // Pass 2: Starting from the selected item, locate the first item with the matching name.
  527. for (int i = iLastSelectedItem + 1; i < c; i++)
  528. {
  529. if (i < _owa.GetPtrCount()
  530. && _MenuCharMatch(_owa.GetPtr(i)->UIName(), ch, FALSE))
  531. {
  532. if (iNextMatch != -1)
  533. {
  534. fMoreThanOneMatch = TRUE;
  535. break; // We found all the info we need
  536. }
  537. else
  538. {
  539. iNextMatch = i;
  540. }
  541. }
  542. }
  543. // Pass 3: If we did not find a match, or if there was only one match
  544. // Search from the first item, to the Selected Item
  545. if (iNextMatch == -1 || fMoreThanOneMatch == FALSE)
  546. {
  547. for (int i = 0; i <= iLastSelectedItem; i++)
  548. {
  549. if (i < _owa.GetPtrCount()
  550. && _MenuCharMatch(_owa.GetPtr(i)->UIName(), ch, FALSE))
  551. {
  552. if (iNextMatch != -1)
  553. {
  554. fMoreThanOneMatch = TRUE;
  555. break;
  556. }
  557. else
  558. {
  559. iNextMatch = i;
  560. }
  561. }
  562. }
  563. }
  564. if (iNextMatch != -1)
  565. {
  566. *plRes = MAKELONG(iNextMatch, fMoreThanOneMatch? MNC_SELECT : MNC_EXECUTE);
  567. }
  568. else
  569. {
  570. *plRes = MAKELONG(0, MNC_IGNORE);
  571. }
  572. return S_OK;
  573. }
  574. HRESULT COpenWithMenu::HandleMenuMsg2(UINT uMsg, WPARAM wParam, LPARAM lParam,LRESULT *plResult)
  575. {
  576. LRESULT lResult = 0;
  577. HRESULT hr = S_OK;
  578. switch (uMsg)
  579. {
  580. case WM_INITMENUPOPUP:
  581. InitMenuPopup(_hMenu);
  582. break;
  583. case WM_DRAWITEM:
  584. DrawItem((DRAWITEMSTRUCT *)lParam);
  585. break;
  586. case WM_MEASUREITEM:
  587. lResult = MeasureItem((MEASUREITEMSTRUCT *)lParam);
  588. break;
  589. case WM_MENUCHAR:
  590. hr = _MatchMenuItem((TCHAR)LOWORD(wParam), &lResult);
  591. break;
  592. default:
  593. hr = E_NOTIMPL;
  594. break;
  595. }
  596. if (plResult)
  597. *plResult = lResult;
  598. return hr;
  599. }
  600. HRESULT COpenWithMenu::Initialize(LPCITEMIDLIST pidlFolder, IDataObject *pdtobj, HKEY hkeyProgID)
  601. {
  602. IUnknown_Set((IUnknown **)&_pdtobj, pdtobj);
  603. return S_OK;
  604. }
  605. #define CXIMAGEGAP 6
  606. #define SRCSTENCIL 0x00B8074AL
  607. void COpenWithMenu::DrawItem(DRAWITEMSTRUCT *lpdi)
  608. {
  609. CAppInfo *pai = _owa.GetPtr(lpdi->itemData);
  610. DrawMenuItem(lpdi, pai->UIName(), pai->IconIndex());
  611. }
  612. LRESULT COpenWithMenu::MeasureItem(MEASUREITEMSTRUCT *pmi)
  613. {
  614. CAppInfo *pai = _owa.GetPtr(pmi->itemData);
  615. return MeasureMenuItem(pmi, pai->UIName());
  616. }
  617. BOOL COpenWithMenu::InitMenuPopup(HMENU hmenu)
  618. {
  619. TraceMsg(TF_OPENWITHMENU, "COpenWithMenu::InitMenuPopup");
  620. if (_fMenuNeedsInit)
  621. {
  622. TCHAR szMenuText[80];
  623. MENUITEMINFO mii;
  624. // remove the place holder.
  625. DeleteMenu(hmenu,0,MF_BYPOSITION);
  626. // add app's in mru list to context menu
  627. for (int i = 0; i < _owa.GetPtrCount(); i++)
  628. {
  629. mii.cbSize = sizeof(MENUITEMINFO);
  630. mii.fMask = MIIM_ID|MIIM_TYPE|MIIM_DATA;
  631. mii.wID = _idCmdFirst + OWMENU_APPFIRST + i;
  632. mii.fType = MFT_OWNERDRAW;
  633. mii.dwItemData = i;
  634. InsertMenuItem(hmenu,GetMenuItemCount(hmenu),TRUE,&mii);
  635. }
  636. // add seperator
  637. AppendMenu(hmenu,MF_SEPARATOR,0,NULL);
  638. // add "Choose Program..."
  639. LoadString(g_hinst, IDS_OPENWITHBROWSE, szMenuText, ARRAYSIZE(szMenuText));
  640. mii.cbSize = sizeof(MENUITEMINFO);
  641. mii.fMask = MIIM_ID|MIIM_TYPE|MIIM_DATA;
  642. mii.wID = _idCmdFirst + OWMENU_BROWSE;
  643. mii.fType = MFT_STRING;
  644. mii.dwTypeData = szMenuText;
  645. mii.dwItemData = 0;
  646. InsertMenuItem(hmenu,GetMenuItemCount(hmenu),TRUE,&mii);
  647. _fMenuNeedsInit = FALSE;
  648. return TRUE;
  649. }
  650. return FALSE;
  651. }