Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

497 lines
13 KiB

  1. /*****************************************************************************\
  2. FILE: ImageMenu.cpp
  3. DESCRIPTION:
  4. This code will display a submenu on the context menus for imagines.
  5. This will allow the conversion and manipulation of images.
  6. BryanSt 8/9/2000 Updated and Converted to C++
  7. Copyright (C) Microsoft Corp 2000-2000. All rights reserved.
  8. \*****************************************************************************/
  9. #include "priv.h"
  10. #include "imagemenu.h"
  11. //===========================
  12. // *** Structures ***
  13. //===========================
  14. struct VERBINFO
  15. {
  16. UINT idc;
  17. DWORD sfgao;
  18. LPCTSTR ptszCmd;
  19. LPCTSTR pszExt;
  20. }
  21. c_rgvi[] =
  22. {
  23. { IDC_IMAGEMENU_CONVERT_GIF, 0, TEXT("ImageMenu_Convert_ToGIF"), TEXT(".gif")},
  24. { IDC_IMAGEMENU_CONVERT_JPEG, 0, TEXT("ImageMenu_Convert_ToJPEG"), TEXT(".jpeg")},
  25. { IDC_IMAGEMENU_CONVERT_PNG, 0, TEXT("ImageMenu_Convert_ToPNG"), TEXT(".png")},
  26. { IDC_IMAGEMENU_CONVERT_TIFF, 0, TEXT("ImageMenu_Convert_ToTIFF"), TEXT(".tiff")},
  27. { IDC_IMAGEMENU_CONVERT_BMP, 0, TEXT("ImageMenu_Convert_ToBMP"), TEXT(".bmp")},
  28. };
  29. //===========================
  30. // *** Class Internals & Helpers ***
  31. //===========================
  32. HRESULT CImageMenu::_ConvertImage(IN HWND hwnd, IN UINT idc)
  33. {
  34. LPTSTR pszCurrFile = m_pszFileList;
  35. UINT nFileCount = m_nFileCount;
  36. HRESULT hr = S_OK;
  37. LPTSTR pszErrorMessage = NULL;
  38. if (pszCurrFile)
  39. {
  40. while (SUCCEEDED(hr) && nFileCount--)
  41. {
  42. TCHAR szSource[MAX_PATH];
  43. TCHAR szDest[MAX_PATH];
  44. StrCpyN(szSource, pszCurrFile, ARRAYSIZE(szSource));
  45. StrCpyN(szDest, pszCurrFile, ARRAYSIZE(szDest));
  46. LPTSTR pszExtension = PathFindExtension(szDest);
  47. if (pszExtension)
  48. {
  49. LPCTSTR pszNewExt = NULL;
  50. // Replace the extension with the target type.
  51. switch (idc)
  52. {
  53. case IDC_IMAGEMENU_CONVERT_GIF:
  54. pszNewExt = TEXT(".gif");
  55. break;
  56. case IDC_IMAGEMENU_CONVERT_JPEG:
  57. pszNewExt = TEXT(".jpeg");
  58. break;
  59. case IDC_IMAGEMENU_CONVERT_PNG:
  60. pszNewExt = TEXT(".png");
  61. break;
  62. case IDC_IMAGEMENU_CONVERT_BMP:
  63. pszNewExt = TEXT(".bmp");
  64. break;
  65. case IDC_IMAGEMENU_CONVERT_TIFF:
  66. pszNewExt = TEXT(".tiff");
  67. break;
  68. }
  69. if (pszNewExt)
  70. {
  71. StrCpy(pszExtension, pszNewExt);
  72. hr = SHConvertGraphicsFile(szSource, szDest, SHCGF_REPLACEFILE);
  73. }
  74. else
  75. {
  76. pszErrorMessage = TEXT("We don't support converting these types of files.");
  77. hr = E_FAIL;
  78. }
  79. }
  80. else
  81. {
  82. pszErrorMessage = TEXT("Couldn't find the file extension.");
  83. hr = E_FAIL;
  84. }
  85. pszCurrFile += (lstrlen(pszCurrFile) + 1);
  86. if (!pszCurrFile[0])
  87. {
  88. // We are done.
  89. break;
  90. }
  91. }
  92. }
  93. else
  94. {
  95. pszErrorMessage = TEXT("Someone didn't set our pidl.");
  96. hr = E_FAIL;
  97. }
  98. if (FAILED(hr))
  99. {
  100. ErrorMessageBox(hwnd, TEXT("Error"), IDS_ERROR_CONVERTIMAGEFAILED, hr, pszErrorMessage, 0);
  101. }
  102. return hr;
  103. }
  104. // Returns the submenu of the given menu and ID. Returns NULL if there
  105. // is no submenu
  106. int _MergePopupMenus(HMENU hmDest, HMENU hmSource, int idCmdFirst, int idCmdLast)
  107. {
  108. int i, idFinal = idCmdFirst;
  109. for (i = GetMenuItemCount(hmSource) - 1; i >= 0; --i)
  110. {
  111. MENUITEMINFO mii;
  112. mii.cbSize = SIZEOF(mii);
  113. mii.fMask = MIIM_ID|MIIM_SUBMENU;
  114. mii.cch = 0; // just in case
  115. if (EVAL(GetMenuItemInfo(hmSource, i, TRUE, &mii)))
  116. {
  117. HMENU hmDestSub = SHGetMenuFromID(hmDest, mii.wID);
  118. if (hmDestSub)
  119. {
  120. int idTemp = Shell_MergeMenus(hmDestSub, mii.hSubMenu, (UINT)0, idCmdFirst, idCmdLast, MM_ADDSEPARATOR | MM_SUBMENUSHAVEIDS);
  121. if (idFinal < idTemp)
  122. idFinal = idTemp;
  123. }
  124. }
  125. }
  126. return idFinal;
  127. }
  128. /*****************************************************************************\
  129. FUNCTION: AddToPopupMenu
  130. DESCRIPTION:
  131. Swiped from utils.c in RNAUI, in turn swiped from the ;Internal
  132. shell. ;Internal
  133. ;Internal
  134. Takes a destination menu and a (menu id, submenu index) pair,
  135. and inserts the items from the (menu id, submenu index) at location
  136. imi in the destination menu, with a separator, returning the number
  137. of items added. (imi = index to menu item)
  138. Returns the first the number of items added.
  139. hmenuDst - destination menu
  140. idMenuToAdd - menu resource identifier
  141. idSubMenuIndex - submenu from menu resource to act as template
  142. indexMenu - location at which menu items should be inserted
  143. idCmdFirst - first available menu identifier
  144. idCmdLast - first unavailable menu identifier
  145. uFlags - flags for Shell_MergeMenus
  146. \*****************************************************************************/
  147. #define FLAGS_MENUMERGE (MM_SUBMENUSHAVEIDS | MM_DONTREMOVESEPS)
  148. UINT AddToPopupMenu(HMENU hmenuDst, UINT idMenuToAdd, UINT idSubMenuIndex, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags)
  149. {
  150. UINT nLastItem = 0;
  151. HMENU hmenuSrc = LoadMenu(g_hinst, MAKEINTRESOURCE(idMenuToAdd));
  152. if (hmenuSrc)
  153. {
  154. nLastItem = Shell_MergeMenus(hmenuDst, GetSubMenu(hmenuSrc, idSubMenuIndex), indexMenu, idCmdFirst, idCmdLast, (uFlags | FLAGS_MENUMERGE));
  155. DestroyMenu(hmenuSrc);
  156. }
  157. return nLastItem;
  158. }
  159. UINT MergeInToPopupMenu(HMENU hmenuDst, UINT idMenuToMerge, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags)
  160. {
  161. UINT nLastItem = 0;
  162. HMENU hmenuSrc = LoadMenu(g_hinst, MAKEINTRESOURCE(idMenuToMerge));
  163. if (hmenuSrc)
  164. {
  165. nLastItem = _MergePopupMenus(hmenuDst, hmenuSrc, idCmdFirst, idCmdLast);
  166. DestroyMenu(hmenuSrc);
  167. }
  168. return nLastItem;
  169. }
  170. //===========================
  171. // *** IShellExtInit Interface ***
  172. //===========================
  173. HRESULT CImageMenu::Initialize(IN LPCITEMIDLIST pidlFolder, IN IDataObject *pdtobj, IN HKEY hkeyProgID)
  174. {
  175. HRESULT hr = S_OK;
  176. if (pdtobj)
  177. {
  178. hr = DataObj_QueryFileList(pdtobj, &m_pszFileList, &m_nFileCount);
  179. }
  180. else
  181. {
  182. MessageBox(NULL, TEXT("IShellExtInit::Initialize() was called but no IDataObject was provided."), TEXT("Error"), MB_OK);
  183. }
  184. return hr;
  185. }
  186. //===========================
  187. // *** IContextMenu Interface ***
  188. //===========================
  189. HRESULT CImageMenu::QueryContextMenu(IN HMENU hmenu, IN UINT indexMenu, IN UINT idCmdFirst, IN UINT idCmdLast, IN UINT uFlags)
  190. {
  191. HRESULT hr = S_OK;
  192. BOOL fAddMenu = TRUE;
  193. if (m_pszFileList)
  194. {
  195. LPTSTR pszCurrFile = m_pszFileList;
  196. for (UINT nIndex = 0; SUCCEEDED(hr) && fAddMenu && (nIndex < m_nFileCount); nIndex++)
  197. {
  198. LPTSTR pszExtension = PathFindExtension(pszCurrFile);
  199. if (pszExtension)
  200. {
  201. for (int nExtIndex = 0; SUCCEEDED(hr) && (nExtIndex < ARRAYSIZE(c_rgvi)); nExtIndex++)
  202. {
  203. if (StrCmpI(c_rgvi[nExtIndex].pszExt, pszExtension))
  204. {
  205. nExtIndex = ARRAYSIZE(c_rgvi);
  206. }
  207. else if (nExtIndex = ARRAYSIZE(c_rgvi) - 1)
  208. {
  209. fAddMenu = FALSE;
  210. break;
  211. }
  212. }
  213. }
  214. else
  215. {
  216. fAddMenu = FALSE;
  217. break;
  218. }
  219. pszCurrFile += (lstrlen(pszCurrFile) + 1);
  220. if (!pszCurrFile[0])
  221. {
  222. // We are done.
  223. break;
  224. }
  225. }
  226. }
  227. else
  228. {
  229. hr = E_FAIL;
  230. ErrorMessageBox(NULL, TEXT("Error"), IDS_ERROR_CONVERTIMAGEFAILED, hr, TEXT("Someone didn't set our pidl."), 0);
  231. }
  232. if (fAddMenu)
  233. {
  234. AddToPopupMenu(hmenu, IDM_IMAGEMENU, 0, indexMenu, idCmdFirst, idCmdLast, MM_ADDSEPARATOR);
  235. if (SUCCEEDED(hr))
  236. hr = ResultFromShort(ARRAYSIZE(c_rgvi)+1);
  237. }
  238. return hr;
  239. }
  240. HRESULT CImageMenu::InvokeCommand(IN LPCMINVOKECOMMANDINFO pici)
  241. {
  242. UINT idc;
  243. HRESULT hr = E_FAIL;
  244. if (pici->cbSize < sizeof(*pici))
  245. return E_INVALIDARG;
  246. if (HIWORD(pici->lpVerb))
  247. {
  248. int ivi;
  249. idc = (UINT)-1;
  250. for (ivi = 0; ivi < ARRAYSIZE(c_rgvi); ivi++)
  251. {
  252. TCHAR szVerb[MAX_PATH];
  253. SHAnsiToTChar(pici->lpVerb, szVerb, ARRAYSIZE(szVerb));
  254. if (!StrCmpI(c_rgvi[ivi].ptszCmd, szVerb))
  255. {
  256. // Yes, the command is equal to the verb str, so this is the one.
  257. idc = c_rgvi[ivi].idc;
  258. break;
  259. }
  260. }
  261. }
  262. else
  263. idc = LOWORD(pici->lpVerb);
  264. switch (idc)
  265. {
  266. case IDC_IMAGEMENU_CONVERT_GIF:
  267. case IDC_IMAGEMENU_CONVERT_JPEG:
  268. case IDC_IMAGEMENU_CONVERT_PNG:
  269. case IDC_IMAGEMENU_CONVERT_TIFF:
  270. case IDC_IMAGEMENU_CONVERT_BMP:
  271. hr = _ConvertImage(pici->hwnd, idc);
  272. break;
  273. default:
  274. ErrorMessageBox(pici->hwnd, TEXT("Error"), IDS_ERROR_MESSAGENUMBER, hr, NULL, 0);
  275. hr = E_INVALIDARG;
  276. break;
  277. }
  278. return hr;
  279. }
  280. HRESULT CImageMenu::GetCommandString(IN UINT_PTR idCmd, IN UINT uType, IN UINT * pwReserved, IN LPSTR pszName, IN UINT cchMax)
  281. {
  282. HRESULT hr = E_FAIL;
  283. BOOL fUnicode = FALSE;
  284. if (idCmd < ARRAYSIZE(c_rgvi))
  285. {
  286. switch (uType)
  287. {
  288. /*
  289. case GCS_HELPTEXTW:
  290. fUnicode = TRUE;
  291. // Fall thru...
  292. case GCS_HELPTEXTA:
  293. GetHelpText:
  294. if (EVAL(cchMax))
  295. {
  296. BOOL fResult;
  297. pszName[0] = '\0';
  298. if (fUnicode)
  299. fResult = LoadStringW(HINST_THISDLL, IDS_ITEM_HELP((UINT)idCmd), (LPWSTR)pszName, cchMax);
  300. else
  301. fResult = LoadStringA(HINST_THISDLL, IDS_ITEM_HELP((UINT)idCmd), pszName, cchMax);
  302. if (EVAL(fResult))
  303. hr = S_OK;
  304. else
  305. hr = E_INVALIDARG;
  306. }
  307. else
  308. hr = E_INVALIDARG;
  309. break;
  310. */
  311. case GCS_VALIDATEW:
  312. case GCS_VALIDATEA:
  313. hr = S_OK;
  314. break;
  315. case GCS_VERBW:
  316. fUnicode = TRUE;
  317. // Fall thru...
  318. case GCS_VERBA:
  319. {
  320. int ivi;
  321. for (ivi = 0; ivi < ARRAYSIZE(c_rgvi); ivi++)
  322. {
  323. if (c_rgvi[ivi].idc == idCmd)
  324. {
  325. if (fUnicode)
  326. SHTCharToUnicode(c_rgvi[ivi].ptszCmd, (LPWSTR)pszName, cchMax);
  327. else
  328. SHTCharToAnsi(c_rgvi[ivi].ptszCmd, pszName, cchMax);
  329. hr = S_OK;
  330. break;
  331. }
  332. }
  333. break;
  334. }
  335. default:
  336. hr = E_NOTIMPL;
  337. break;
  338. }
  339. }
  340. return hr;
  341. }
  342. //===========================
  343. // *** IUnknown Interface ***
  344. //===========================
  345. ULONG CImageMenu::AddRef()
  346. {
  347. m_cRef++;
  348. return m_cRef;
  349. }
  350. ULONG CImageMenu::Release()
  351. {
  352. ASSERT(m_cRef > 0);
  353. m_cRef--;
  354. if (m_cRef > 0)
  355. return m_cRef;
  356. delete this;
  357. return 0;
  358. }
  359. HRESULT CImageMenu::QueryInterface(REFIID riid, void **ppvObj)
  360. {
  361. HRESULT hr = E_NOINTERFACE;
  362. static const QITAB qit[] =
  363. {
  364. QITABENT(CImageMenu, IShellExtInit),
  365. QITABENT(CImageMenu, IContextMenu),
  366. { 0 },
  367. };
  368. return QISearch(this, qit, riid, ppvObj);
  369. }
  370. //===========================
  371. // *** Class Methods ***
  372. //===========================
  373. CImageMenu::CImageMenu() : m_cRef(1)
  374. {
  375. // This needs to be allocated in Zero Inited Memory.
  376. // Assert that all Member Variables are inited to Zero.
  377. m_pszFileList = FALSE;
  378. m_nFileCount = 0;
  379. }
  380. CImageMenu::~CImageMenu()
  381. {
  382. if (m_pszFileList)
  383. {
  384. DataObj_FreeList(m_pszFileList);
  385. }
  386. }
  387. HRESULT CImageMenu_CreateInstance(IN IUnknown * punkOuter, IN REFIID riid, OUT void **ppvObject)
  388. {
  389. HRESULT hr = E_INVALIDARG;
  390. if (!punkOuter && ppvObject)
  391. {
  392. CImageMenu * pThis = new CImageMenu();
  393. if (pThis)
  394. {
  395. hr = pThis->QueryInterface(riid, ppvObject);
  396. pThis->Release();
  397. }
  398. else
  399. {
  400. *ppvObject = NULL;
  401. hr = E_OUTOFMEMORY;
  402. }
  403. }
  404. return hr;
  405. }