windows-nt/Source/XPSP1/NT/shell/ext/powertoy/resize.cpp
2020-09-26 16:20:57 +08:00

285 lines
8.1 KiB
C++

#include "precomp.h"
#include "shimgdata.h"
#include <gdiplus.h>
using namespace Gdiplus;
#pragma hdrstop
class CResizePhotos : public IShellExtInit, IContextMenu, INamespaceWalkCB
{
public:
CResizePhotos();
// IUnknown
STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
STDMETHODIMP_(ULONG) AddRef();
STDMETHODIMP_(ULONG) Release();
// IShellExtInit
STDMETHODIMP Initialize(LPCITEMIDLIST pidlFolder, IDataObject *pdto, HKEY hkProgID);
// IContextMenu
STDMETHODIMP QueryContextMenu(HMENU hMenu, UINT uIndex, UINT uIDFirst, UINT uIDLast, UINT uFlags);
STDMETHODIMP InvokeCommand(LPCMINVOKECOMMANDINFO pCMI);
STDMETHODIMP GetCommandString(UINT_PTR uID, UINT uFlags, UINT *res, LPSTR pName, UINT ccMax)
{ return E_NOTIMPL; }
// INamespaceWalkCB
STDMETHODIMP FoundItem(IShellFolder *psf, LPCITEMIDLIST pidl);
STDMETHODIMP EnterFolder(IShellFolder *psf, LPCITEMIDLIST pidl)
{ return S_FALSE; }
STDMETHODIMP LeaveFolder(IShellFolder *psf, LPCITEMIDLIST pidl)
{ return S_OK; }
STDMETHODIMP InitializeProgressDialog(LPWSTR *ppszTitle, LPWSTR *ppszCancel);
private:
~CResizePhotos();
HRESULT _ResizeItems(HWND hwnd, IDataObject *pdo);
long _cRef;
IDataObject *_pdo;
int _iDestSize;
};
CResizePhotos::CResizePhotos() :
_cRef(1), _iDestSize(0)
{
DllAddRef();
}
CResizePhotos::~CResizePhotos()
{
IUnknown_Set((IUnknown**)&_pdo, NULL);
DllRelease();
}
STDAPI CResizePhotos_CreateInstance(IUnknown* pUnkOuter, IUnknown** ppunk, LPCOBJECTINFO poi)
{
CResizePhotos *prp = new CResizePhotos();
if (!prp)
{
*ppunk = NULL; // incase of failure
return E_OUTOFMEMORY;
}
HRESULT hr = prp->QueryInterface(IID_PPV_ARG(IUnknown, ppunk));
prp->Release();
return hr;
}
// IUnknown
ULONG CResizePhotos::AddRef()
{
return InterlockedIncrement(&_cRef);
}
ULONG CResizePhotos::Release()
{
if (InterlockedDecrement(&_cRef))
return _cRef;
delete this;
return 0;
}
HRESULT CResizePhotos::QueryInterface(REFIID riid, void **ppv)
{
static const QITAB qit[] =
{
QITABENT(CResizePhotos, IShellExtInit),
QITABENT(CResizePhotos, IContextMenu),
QITABENT(CResizePhotos, INamespaceWalkCB),
{0, 0 },
};
return QISearch(this, qit, riid, ppv);
}
// IShellExtInit
HRESULT CResizePhotos::Initialize(LPCITEMIDLIST pidlFolder, IDataObject *pdto, HKEY hkProgID)
{
IUnknown_Set((IUnknown**)&_pdo, pdto);
return S_OK;
}
// IContextMenu
HRESULT CResizePhotos::QueryContextMenu(HMENU hMenu, UINT uIndex, UINT uIDFirst, UINT uIDLast, UINT uFlags)
{
if (!_pdo)
return E_UNEXPECTED;
if (!(uFlags & CMF_DEFAULTONLY))
{
TCHAR szBuffer[64];
LoadString(g_hinst, IDS_RESIZEPICTURES, szBuffer, ARRAYSIZE(szBuffer));
InsertMenu(hMenu, uIndex++, MF_BYPOSITION|MF_STRING, uIDFirst + 0x0, szBuffer);
}
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, 1);
}
HRESULT CResizePhotos::InvokeCommand(LPCMINVOKECOMMANDINFO pici)
{
HRESULT hr = E_FAIL;
if (IS_INTRESOURCE(pici->lpVerb))
{
switch(LOWORD(pici->lpVerb))
{
case 0:
hr = _ResizeItems(pici->hwnd, _pdo);
break;
}
}
return hr;
}
// Walk the list of files and generate resized versions of them
struct
{
int cx, cy, idsSuffix;
}
_aSizes[] =
{
{ 640, 480, IDS_RESIZESMALLSUFFIX },
{ 800, 600, IDS_RESIZEMEDIUMSUFFIX },
{ 1024, 768, IDS_RESIZELARGESUFFIX },
};
HRESULT CResizePhotos::FoundItem(IShellFolder *psf, LPCITEMIDLIST pidl)
{
TCHAR szName[MAX_PATH];
HRESULT hr = DisplayNameOf(psf, pidl, SHGDN_FORPARSING, szName, ARRAYSIZE(szName));
if (SUCCEEDED(hr) && PathIsImage(szName))
{
// create the decoder for this file and decode it so we know we can scale and
// persist it again.
IShellImageDataFactory *psidf;
hr = CoCreateInstance(CLSID_ShellImageDataFactory, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IShellImageDataFactory, &psidf));
if (SUCCEEDED(hr))
{
IShellImageData *psid;
if (SUCCEEDED(psidf->CreateImageFromFile(szName, &psid)))
{
hr = psid->Decode(SHIMGDEC_DEFAULT, 0, 0);
if (SUCCEEDED(hr))
{
SIZE szImage;
hr = psid->GetSize(&szImage);
if (SUCCEEDED(hr))
{
// lets scale based on the largest axis to keep its aspect ratio
if (szImage.cx > szImage.cy)
{
if (szImage.cx >= _aSizes[_iDestSize].cx)
hr = psid->Scale(_aSizes[_iDestSize].cx, 0, InterpolationModeHighQuality);
}
else
{
if (szImage.cy >= _aSizes[_iDestSize].cy)
hr = psid->Scale(0, _aSizes[_iDestSize].cy, InterpolationModeHighQuality);
}
// format up a new name for the based on its current name, and the size we
// are generating
TCHAR szNewName[MAX_PATH];
lstrcpyn(szNewName, szName, ARRAYSIZE(szNewName));
TCHAR szSuffix[MAX_PATH];
LoadString(g_hinst, _aSizes[_iDestSize].idsSuffix, szSuffix, ARRAYSIZE(szSuffix));
PathRemoveExtension(szNewName);
PathRemoveBlanks(szNewName);
StrCatBuff(szNewName, szSuffix, ARRAYSIZE(szNewName));
StrCatBuff(szNewName, PathFindExtension(szName), ARRAYSIZE(szNewName));
PathYetAnotherMakeUniqueName(szNewName, szNewName, NULL, NULL);
IPersistFile *ppf;
hr = psid->QueryInterface(IID_PPV_ARG(IPersistFile, &ppf));
if (SUCCEEDED(hr))
{
hr = ppf->Save(szNewName, FALSE);
ppf->Release();
}
}
}
psid->Release();
}
psidf->Release();
}
}
return hr;
}
HRESULT CResizePhotos::InitializeProgressDialog(LPWSTR *ppszTitle, LPWSTR *ppszCancel)
{
*ppszCancel = NULL; // use default
TCHAR szMsg[128];
LoadString(g_hinst, IDS_RESIZEPICTURES, szMsg, ARRAYSIZE(szMsg));
return SHStrDup(szMsg, ppszTitle);
}
INT_PTR _ResizeDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_INITDIALOG:
Button_SetCheck(GetDlgItem(hwnd, IDC_RESIZE_SMALL), BST_CHECKED);
return TRUE;
case WM_COMMAND:
{
switch (wParam)
{
case IDCANCEL:
EndDialog(hwnd, -1);
break;
case IDOK:
{
int iResponse;
if (IsDlgButtonChecked(hwnd, IDC_RESIZE_SMALL))
iResponse = 0;
else if (IsDlgButtonChecked(hwnd, IDC_RESIZE_MEDIUM))
iResponse = 1;
else
iResponse = 2;
EndDialog(hwnd, iResponse);
}
}
}
}
return FALSE;
}
HRESULT CResizePhotos::_ResizeItems(HWND hwnd, IDataObject *pdo)
{
HRESULT hr = S_OK;
_iDestSize = (int)DialogBox(g_hinst, MAKEINTRESOURCE(DLG_RESIZEPICTURES), hwnd, _ResizeDlgProc);
if (_iDestSize >= 0)
{
INamespaceWalk *pnsw;
hr = CoCreateInstance(CLSID_NamespaceWalker, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(INamespaceWalk, &pnsw));
if (SUCCEEDED(hr))
{
hr = pnsw->Walk(pdo, NSWF_SHOW_PROGRESS|NSWF_DONT_ACCUMULATE_RESULT|NSWF_FILESYSTEM_ONLY|NSWF_FLAG_VIEWORDER, 1, SAFECAST(this, INamespaceWalkCB *));
pnsw->Release();
}
}
return hr;
}