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.

284 lines
8.1 KiB

  1. #include "precomp.h"
  2. #include "shimgdata.h"
  3. #include <gdiplus.h>
  4. using namespace Gdiplus;
  5. #pragma hdrstop
  6. class CResizePhotos : public IShellExtInit, IContextMenu, INamespaceWalkCB
  7. {
  8. public:
  9. CResizePhotos();
  10. // IUnknown
  11. STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
  12. STDMETHODIMP_(ULONG) AddRef();
  13. STDMETHODIMP_(ULONG) Release();
  14. // IShellExtInit
  15. STDMETHODIMP Initialize(LPCITEMIDLIST pidlFolder, IDataObject *pdto, HKEY hkProgID);
  16. // IContextMenu
  17. STDMETHODIMP QueryContextMenu(HMENU hMenu, UINT uIndex, UINT uIDFirst, UINT uIDLast, UINT uFlags);
  18. STDMETHODIMP InvokeCommand(LPCMINVOKECOMMANDINFO pCMI);
  19. STDMETHODIMP GetCommandString(UINT_PTR uID, UINT uFlags, UINT *res, LPSTR pName, UINT ccMax)
  20. { return E_NOTIMPL; }
  21. // INamespaceWalkCB
  22. STDMETHODIMP FoundItem(IShellFolder *psf, LPCITEMIDLIST pidl);
  23. STDMETHODIMP EnterFolder(IShellFolder *psf, LPCITEMIDLIST pidl)
  24. { return S_FALSE; }
  25. STDMETHODIMP LeaveFolder(IShellFolder *psf, LPCITEMIDLIST pidl)
  26. { return S_OK; }
  27. STDMETHODIMP InitializeProgressDialog(LPWSTR *ppszTitle, LPWSTR *ppszCancel);
  28. private:
  29. ~CResizePhotos();
  30. HRESULT _ResizeItems(HWND hwnd, IDataObject *pdo);
  31. long _cRef;
  32. IDataObject *_pdo;
  33. int _iDestSize;
  34. };
  35. CResizePhotos::CResizePhotos() :
  36. _cRef(1), _iDestSize(0)
  37. {
  38. DllAddRef();
  39. }
  40. CResizePhotos::~CResizePhotos()
  41. {
  42. IUnknown_Set((IUnknown**)&_pdo, NULL);
  43. DllRelease();
  44. }
  45. STDAPI CResizePhotos_CreateInstance(IUnknown* pUnkOuter, IUnknown** ppunk, LPCOBJECTINFO poi)
  46. {
  47. CResizePhotos *prp = new CResizePhotos();
  48. if (!prp)
  49. {
  50. *ppunk = NULL; // incase of failure
  51. return E_OUTOFMEMORY;
  52. }
  53. HRESULT hr = prp->QueryInterface(IID_PPV_ARG(IUnknown, ppunk));
  54. prp->Release();
  55. return hr;
  56. }
  57. // IUnknown
  58. ULONG CResizePhotos::AddRef()
  59. {
  60. return InterlockedIncrement(&_cRef);
  61. }
  62. ULONG CResizePhotos::Release()
  63. {
  64. if (InterlockedDecrement(&_cRef))
  65. return _cRef;
  66. delete this;
  67. return 0;
  68. }
  69. HRESULT CResizePhotos::QueryInterface(REFIID riid, void **ppv)
  70. {
  71. static const QITAB qit[] =
  72. {
  73. QITABENT(CResizePhotos, IShellExtInit),
  74. QITABENT(CResizePhotos, IContextMenu),
  75. QITABENT(CResizePhotos, INamespaceWalkCB),
  76. {0, 0 },
  77. };
  78. return QISearch(this, qit, riid, ppv);
  79. }
  80. // IShellExtInit
  81. HRESULT CResizePhotos::Initialize(LPCITEMIDLIST pidlFolder, IDataObject *pdto, HKEY hkProgID)
  82. {
  83. IUnknown_Set((IUnknown**)&_pdo, pdto);
  84. return S_OK;
  85. }
  86. // IContextMenu
  87. HRESULT CResizePhotos::QueryContextMenu(HMENU hMenu, UINT uIndex, UINT uIDFirst, UINT uIDLast, UINT uFlags)
  88. {
  89. if (!_pdo)
  90. return E_UNEXPECTED;
  91. if (!(uFlags & CMF_DEFAULTONLY))
  92. {
  93. TCHAR szBuffer[64];
  94. LoadString(g_hinst, IDS_RESIZEPICTURES, szBuffer, ARRAYSIZE(szBuffer));
  95. InsertMenu(hMenu, uIndex++, MF_BYPOSITION|MF_STRING, uIDFirst + 0x0, szBuffer);
  96. }
  97. return MAKE_HRESULT(SEVERITY_SUCCESS, 0, 1);
  98. }
  99. HRESULT CResizePhotos::InvokeCommand(LPCMINVOKECOMMANDINFO pici)
  100. {
  101. HRESULT hr = E_FAIL;
  102. if (IS_INTRESOURCE(pici->lpVerb))
  103. {
  104. switch(LOWORD(pici->lpVerb))
  105. {
  106. case 0:
  107. hr = _ResizeItems(pici->hwnd, _pdo);
  108. break;
  109. }
  110. }
  111. return hr;
  112. }
  113. // Walk the list of files and generate resized versions of them
  114. struct
  115. {
  116. int cx, cy, idsSuffix;
  117. }
  118. _aSizes[] =
  119. {
  120. { 640, 480, IDS_RESIZESMALLSUFFIX },
  121. { 800, 600, IDS_RESIZEMEDIUMSUFFIX },
  122. { 1024, 768, IDS_RESIZELARGESUFFIX },
  123. };
  124. HRESULT CResizePhotos::FoundItem(IShellFolder *psf, LPCITEMIDLIST pidl)
  125. {
  126. TCHAR szName[MAX_PATH];
  127. HRESULT hr = DisplayNameOf(psf, pidl, SHGDN_FORPARSING, szName, ARRAYSIZE(szName));
  128. if (SUCCEEDED(hr) && PathIsImage(szName))
  129. {
  130. // create the decoder for this file and decode it so we know we can scale and
  131. // persist it again.
  132. IShellImageDataFactory *psidf;
  133. hr = CoCreateInstance(CLSID_ShellImageDataFactory, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IShellImageDataFactory, &psidf));
  134. if (SUCCEEDED(hr))
  135. {
  136. IShellImageData *psid;
  137. if (SUCCEEDED(psidf->CreateImageFromFile(szName, &psid)))
  138. {
  139. hr = psid->Decode(SHIMGDEC_DEFAULT, 0, 0);
  140. if (SUCCEEDED(hr))
  141. {
  142. SIZE szImage;
  143. hr = psid->GetSize(&szImage);
  144. if (SUCCEEDED(hr))
  145. {
  146. // lets scale based on the largest axis to keep its aspect ratio
  147. if (szImage.cx > szImage.cy)
  148. {
  149. if (szImage.cx >= _aSizes[_iDestSize].cx)
  150. hr = psid->Scale(_aSizes[_iDestSize].cx, 0, InterpolationModeHighQuality);
  151. }
  152. else
  153. {
  154. if (szImage.cy >= _aSizes[_iDestSize].cy)
  155. hr = psid->Scale(0, _aSizes[_iDestSize].cy, InterpolationModeHighQuality);
  156. }
  157. // format up a new name for the based on its current name, and the size we
  158. // are generating
  159. TCHAR szNewName[MAX_PATH];
  160. lstrcpyn(szNewName, szName, ARRAYSIZE(szNewName));
  161. TCHAR szSuffix[MAX_PATH];
  162. LoadString(g_hinst, _aSizes[_iDestSize].idsSuffix, szSuffix, ARRAYSIZE(szSuffix));
  163. PathRemoveExtension(szNewName);
  164. PathRemoveBlanks(szNewName);
  165. StrCatBuff(szNewName, szSuffix, ARRAYSIZE(szNewName));
  166. StrCatBuff(szNewName, PathFindExtension(szName), ARRAYSIZE(szNewName));
  167. PathYetAnotherMakeUniqueName(szNewName, szNewName, NULL, NULL);
  168. IPersistFile *ppf;
  169. hr = psid->QueryInterface(IID_PPV_ARG(IPersistFile, &ppf));
  170. if (SUCCEEDED(hr))
  171. {
  172. hr = ppf->Save(szNewName, FALSE);
  173. ppf->Release();
  174. }
  175. }
  176. }
  177. psid->Release();
  178. }
  179. psidf->Release();
  180. }
  181. }
  182. return hr;
  183. }
  184. HRESULT CResizePhotos::InitializeProgressDialog(LPWSTR *ppszTitle, LPWSTR *ppszCancel)
  185. {
  186. *ppszCancel = NULL; // use default
  187. TCHAR szMsg[128];
  188. LoadString(g_hinst, IDS_RESIZEPICTURES, szMsg, ARRAYSIZE(szMsg));
  189. return SHStrDup(szMsg, ppszTitle);
  190. }
  191. INT_PTR _ResizeDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  192. {
  193. switch (uMsg)
  194. {
  195. case WM_INITDIALOG:
  196. Button_SetCheck(GetDlgItem(hwnd, IDC_RESIZE_SMALL), BST_CHECKED);
  197. return TRUE;
  198. case WM_COMMAND:
  199. {
  200. switch (wParam)
  201. {
  202. case IDCANCEL:
  203. EndDialog(hwnd, -1);
  204. break;
  205. case IDOK:
  206. {
  207. int iResponse;
  208. if (IsDlgButtonChecked(hwnd, IDC_RESIZE_SMALL))
  209. iResponse = 0;
  210. else if (IsDlgButtonChecked(hwnd, IDC_RESIZE_MEDIUM))
  211. iResponse = 1;
  212. else
  213. iResponse = 2;
  214. EndDialog(hwnd, iResponse);
  215. }
  216. }
  217. }
  218. }
  219. return FALSE;
  220. }
  221. HRESULT CResizePhotos::_ResizeItems(HWND hwnd, IDataObject *pdo)
  222. {
  223. HRESULT hr = S_OK;
  224. _iDestSize = (int)DialogBox(g_hinst, MAKEINTRESOURCE(DLG_RESIZEPICTURES), hwnd, _ResizeDlgProc);
  225. if (_iDestSize >= 0)
  226. {
  227. INamespaceWalk *pnsw;
  228. hr = CoCreateInstance(CLSID_NamespaceWalker, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(INamespaceWalk, &pnsw));
  229. if (SUCCEEDED(hr))
  230. {
  231. hr = pnsw->Walk(pdo, NSWF_SHOW_PROGRESS|NSWF_DONT_ACCUMULATE_RESULT|NSWF_FILESYSTEM_ONLY|NSWF_FLAG_VIEWORDER, 1, SAFECAST(this, INamespaceWalkCB *));
  232. pnsw->Release();
  233. }
  234. }
  235. return hr;
  236. }