285 lines
8.1 KiB
C++
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;
|
||
|
}
|