windows-nt/Source/XPSP1/NT/shell/tools/starbuck/imagemenu.cpp
2020-09-26 16:20:57 +08:00

498 lines
13 KiB
C++

/*****************************************************************************\
FILE: ImageMenu.cpp
DESCRIPTION:
This code will display a submenu on the context menus for imagines.
This will allow the conversion and manipulation of images.
BryanSt 8/9/2000 Updated and Converted to C++
Copyright (C) Microsoft Corp 2000-2000. All rights reserved.
\*****************************************************************************/
#include "priv.h"
#include "imagemenu.h"
//===========================
// *** Structures ***
//===========================
struct VERBINFO
{
UINT idc;
DWORD sfgao;
LPCTSTR ptszCmd;
LPCTSTR pszExt;
}
c_rgvi[] =
{
{ IDC_IMAGEMENU_CONVERT_GIF, 0, TEXT("ImageMenu_Convert_ToGIF"), TEXT(".gif")},
{ IDC_IMAGEMENU_CONVERT_JPEG, 0, TEXT("ImageMenu_Convert_ToJPEG"), TEXT(".jpeg")},
{ IDC_IMAGEMENU_CONVERT_PNG, 0, TEXT("ImageMenu_Convert_ToPNG"), TEXT(".png")},
{ IDC_IMAGEMENU_CONVERT_TIFF, 0, TEXT("ImageMenu_Convert_ToTIFF"), TEXT(".tiff")},
{ IDC_IMAGEMENU_CONVERT_BMP, 0, TEXT("ImageMenu_Convert_ToBMP"), TEXT(".bmp")},
};
//===========================
// *** Class Internals & Helpers ***
//===========================
HRESULT CImageMenu::_ConvertImage(IN HWND hwnd, IN UINT idc)
{
LPTSTR pszCurrFile = m_pszFileList;
UINT nFileCount = m_nFileCount;
HRESULT hr = S_OK;
LPTSTR pszErrorMessage = NULL;
if (pszCurrFile)
{
while (SUCCEEDED(hr) && nFileCount--)
{
TCHAR szSource[MAX_PATH];
TCHAR szDest[MAX_PATH];
StrCpyN(szSource, pszCurrFile, ARRAYSIZE(szSource));
StrCpyN(szDest, pszCurrFile, ARRAYSIZE(szDest));
LPTSTR pszExtension = PathFindExtension(szDest);
if (pszExtension)
{
LPCTSTR pszNewExt = NULL;
// Replace the extension with the target type.
switch (idc)
{
case IDC_IMAGEMENU_CONVERT_GIF:
pszNewExt = TEXT(".gif");
break;
case IDC_IMAGEMENU_CONVERT_JPEG:
pszNewExt = TEXT(".jpeg");
break;
case IDC_IMAGEMENU_CONVERT_PNG:
pszNewExt = TEXT(".png");
break;
case IDC_IMAGEMENU_CONVERT_BMP:
pszNewExt = TEXT(".bmp");
break;
case IDC_IMAGEMENU_CONVERT_TIFF:
pszNewExt = TEXT(".tiff");
break;
}
if (pszNewExt)
{
StrCpy(pszExtension, pszNewExt);
hr = SHConvertGraphicsFile(szSource, szDest, SHCGF_REPLACEFILE);
}
else
{
pszErrorMessage = TEXT("We don't support converting these types of files.");
hr = E_FAIL;
}
}
else
{
pszErrorMessage = TEXT("Couldn't find the file extension.");
hr = E_FAIL;
}
pszCurrFile += (lstrlen(pszCurrFile) + 1);
if (!pszCurrFile[0])
{
// We are done.
break;
}
}
}
else
{
pszErrorMessage = TEXT("Someone didn't set our pidl.");
hr = E_FAIL;
}
if (FAILED(hr))
{
ErrorMessageBox(hwnd, TEXT("Error"), IDS_ERROR_CONVERTIMAGEFAILED, hr, pszErrorMessage, 0);
}
return hr;
}
// Returns the submenu of the given menu and ID. Returns NULL if there
// is no submenu
int _MergePopupMenus(HMENU hmDest, HMENU hmSource, int idCmdFirst, int idCmdLast)
{
int i, idFinal = idCmdFirst;
for (i = GetMenuItemCount(hmSource) - 1; i >= 0; --i)
{
MENUITEMINFO mii;
mii.cbSize = SIZEOF(mii);
mii.fMask = MIIM_ID|MIIM_SUBMENU;
mii.cch = 0; // just in case
if (EVAL(GetMenuItemInfo(hmSource, i, TRUE, &mii)))
{
HMENU hmDestSub = SHGetMenuFromID(hmDest, mii.wID);
if (hmDestSub)
{
int idTemp = Shell_MergeMenus(hmDestSub, mii.hSubMenu, (UINT)0, idCmdFirst, idCmdLast, MM_ADDSEPARATOR | MM_SUBMENUSHAVEIDS);
if (idFinal < idTemp)
idFinal = idTemp;
}
}
}
return idFinal;
}
/*****************************************************************************\
FUNCTION: AddToPopupMenu
DESCRIPTION:
Swiped from utils.c in RNAUI, in turn swiped from the ;Internal
shell. ;Internal
;Internal
Takes a destination menu and a (menu id, submenu index) pair,
and inserts the items from the (menu id, submenu index) at location
imi in the destination menu, with a separator, returning the number
of items added. (imi = index to menu item)
Returns the first the number of items added.
hmenuDst - destination menu
idMenuToAdd - menu resource identifier
idSubMenuIndex - submenu from menu resource to act as template
indexMenu - location at which menu items should be inserted
idCmdFirst - first available menu identifier
idCmdLast - first unavailable menu identifier
uFlags - flags for Shell_MergeMenus
\*****************************************************************************/
#define FLAGS_MENUMERGE (MM_SUBMENUSHAVEIDS | MM_DONTREMOVESEPS)
UINT AddToPopupMenu(HMENU hmenuDst, UINT idMenuToAdd, UINT idSubMenuIndex, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags)
{
UINT nLastItem = 0;
HMENU hmenuSrc = LoadMenu(g_hinst, MAKEINTRESOURCE(idMenuToAdd));
if (hmenuSrc)
{
nLastItem = Shell_MergeMenus(hmenuDst, GetSubMenu(hmenuSrc, idSubMenuIndex), indexMenu, idCmdFirst, idCmdLast, (uFlags | FLAGS_MENUMERGE));
DestroyMenu(hmenuSrc);
}
return nLastItem;
}
UINT MergeInToPopupMenu(HMENU hmenuDst, UINT idMenuToMerge, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags)
{
UINT nLastItem = 0;
HMENU hmenuSrc = LoadMenu(g_hinst, MAKEINTRESOURCE(idMenuToMerge));
if (hmenuSrc)
{
nLastItem = _MergePopupMenus(hmenuDst, hmenuSrc, idCmdFirst, idCmdLast);
DestroyMenu(hmenuSrc);
}
return nLastItem;
}
//===========================
// *** IShellExtInit Interface ***
//===========================
HRESULT CImageMenu::Initialize(IN LPCITEMIDLIST pidlFolder, IN IDataObject *pdtobj, IN HKEY hkeyProgID)
{
HRESULT hr = S_OK;
if (pdtobj)
{
hr = DataObj_QueryFileList(pdtobj, &m_pszFileList, &m_nFileCount);
}
else
{
MessageBox(NULL, TEXT("IShellExtInit::Initialize() was called but no IDataObject was provided."), TEXT("Error"), MB_OK);
}
return hr;
}
//===========================
// *** IContextMenu Interface ***
//===========================
HRESULT CImageMenu::QueryContextMenu(IN HMENU hmenu, IN UINT indexMenu, IN UINT idCmdFirst, IN UINT idCmdLast, IN UINT uFlags)
{
HRESULT hr = S_OK;
BOOL fAddMenu = TRUE;
if (m_pszFileList)
{
LPTSTR pszCurrFile = m_pszFileList;
for (UINT nIndex = 0; SUCCEEDED(hr) && fAddMenu && (nIndex < m_nFileCount); nIndex++)
{
LPTSTR pszExtension = PathFindExtension(pszCurrFile);
if (pszExtension)
{
for (int nExtIndex = 0; SUCCEEDED(hr) && (nExtIndex < ARRAYSIZE(c_rgvi)); nExtIndex++)
{
if (StrCmpI(c_rgvi[nExtIndex].pszExt, pszExtension))
{
nExtIndex = ARRAYSIZE(c_rgvi);
}
else if (nExtIndex = ARRAYSIZE(c_rgvi) - 1)
{
fAddMenu = FALSE;
break;
}
}
}
else
{
fAddMenu = FALSE;
break;
}
pszCurrFile += (lstrlen(pszCurrFile) + 1);
if (!pszCurrFile[0])
{
// We are done.
break;
}
}
}
else
{
hr = E_FAIL;
ErrorMessageBox(NULL, TEXT("Error"), IDS_ERROR_CONVERTIMAGEFAILED, hr, TEXT("Someone didn't set our pidl."), 0);
}
if (fAddMenu)
{
AddToPopupMenu(hmenu, IDM_IMAGEMENU, 0, indexMenu, idCmdFirst, idCmdLast, MM_ADDSEPARATOR);
if (SUCCEEDED(hr))
hr = ResultFromShort(ARRAYSIZE(c_rgvi)+1);
}
return hr;
}
HRESULT CImageMenu::InvokeCommand(IN LPCMINVOKECOMMANDINFO pici)
{
UINT idc;
HRESULT hr = E_FAIL;
if (pici->cbSize < sizeof(*pici))
return E_INVALIDARG;
if (HIWORD(pici->lpVerb))
{
int ivi;
idc = (UINT)-1;
for (ivi = 0; ivi < ARRAYSIZE(c_rgvi); ivi++)
{
TCHAR szVerb[MAX_PATH];
SHAnsiToTChar(pici->lpVerb, szVerb, ARRAYSIZE(szVerb));
if (!StrCmpI(c_rgvi[ivi].ptszCmd, szVerb))
{
// Yes, the command is equal to the verb str, so this is the one.
idc = c_rgvi[ivi].idc;
break;
}
}
}
else
idc = LOWORD(pici->lpVerb);
switch (idc)
{
case IDC_IMAGEMENU_CONVERT_GIF:
case IDC_IMAGEMENU_CONVERT_JPEG:
case IDC_IMAGEMENU_CONVERT_PNG:
case IDC_IMAGEMENU_CONVERT_TIFF:
case IDC_IMAGEMENU_CONVERT_BMP:
hr = _ConvertImage(pici->hwnd, idc);
break;
default:
ErrorMessageBox(pici->hwnd, TEXT("Error"), IDS_ERROR_MESSAGENUMBER, hr, NULL, 0);
hr = E_INVALIDARG;
break;
}
return hr;
}
HRESULT CImageMenu::GetCommandString(IN UINT_PTR idCmd, IN UINT uType, IN UINT * pwReserved, IN LPSTR pszName, IN UINT cchMax)
{
HRESULT hr = E_FAIL;
BOOL fUnicode = FALSE;
if (idCmd < ARRAYSIZE(c_rgvi))
{
switch (uType)
{
/*
case GCS_HELPTEXTW:
fUnicode = TRUE;
// Fall thru...
case GCS_HELPTEXTA:
GetHelpText:
if (EVAL(cchMax))
{
BOOL fResult;
pszName[0] = '\0';
if (fUnicode)
fResult = LoadStringW(HINST_THISDLL, IDS_ITEM_HELP((UINT)idCmd), (LPWSTR)pszName, cchMax);
else
fResult = LoadStringA(HINST_THISDLL, IDS_ITEM_HELP((UINT)idCmd), pszName, cchMax);
if (EVAL(fResult))
hr = S_OK;
else
hr = E_INVALIDARG;
}
else
hr = E_INVALIDARG;
break;
*/
case GCS_VALIDATEW:
case GCS_VALIDATEA:
hr = S_OK;
break;
case GCS_VERBW:
fUnicode = TRUE;
// Fall thru...
case GCS_VERBA:
{
int ivi;
for (ivi = 0; ivi < ARRAYSIZE(c_rgvi); ivi++)
{
if (c_rgvi[ivi].idc == idCmd)
{
if (fUnicode)
SHTCharToUnicode(c_rgvi[ivi].ptszCmd, (LPWSTR)pszName, cchMax);
else
SHTCharToAnsi(c_rgvi[ivi].ptszCmd, pszName, cchMax);
hr = S_OK;
break;
}
}
break;
}
default:
hr = E_NOTIMPL;
break;
}
}
return hr;
}
//===========================
// *** IUnknown Interface ***
//===========================
ULONG CImageMenu::AddRef()
{
m_cRef++;
return m_cRef;
}
ULONG CImageMenu::Release()
{
ASSERT(m_cRef > 0);
m_cRef--;
if (m_cRef > 0)
return m_cRef;
delete this;
return 0;
}
HRESULT CImageMenu::QueryInterface(REFIID riid, void **ppvObj)
{
HRESULT hr = E_NOINTERFACE;
static const QITAB qit[] =
{
QITABENT(CImageMenu, IShellExtInit),
QITABENT(CImageMenu, IContextMenu),
{ 0 },
};
return QISearch(this, qit, riid, ppvObj);
}
//===========================
// *** Class Methods ***
//===========================
CImageMenu::CImageMenu() : m_cRef(1)
{
// This needs to be allocated in Zero Inited Memory.
// Assert that all Member Variables are inited to Zero.
m_pszFileList = FALSE;
m_nFileCount = 0;
}
CImageMenu::~CImageMenu()
{
if (m_pszFileList)
{
DataObj_FreeList(m_pszFileList);
}
}
HRESULT CImageMenu_CreateInstance(IN IUnknown * punkOuter, IN REFIID riid, OUT void **ppvObject)
{
HRESULT hr = E_INVALIDARG;
if (!punkOuter && ppvObject)
{
CImageMenu * pThis = new CImageMenu();
if (pThis)
{
hr = pThis->QueryInterface(riid, ppvObject);
pThis->Release();
}
else
{
*ppvObject = NULL;
hr = E_OUTOFMEMORY;
}
}
return hr;
}