[MSPAINT][ATL] Delete deprecated functions (#5542)

- Rewrite CImageDx to reduce improper dependency with CImage.
- Check if the filename extension is supported before saving the files.
- Delete deprecated functions in CImage.
CORE-19094
This commit is contained in:
Katayama Hirofumi MZ 2023-08-09 08:17:07 +09:00 committed by GitHub
parent 8532f1874a
commit 70e05170cf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 290 additions and 127 deletions

View file

@ -7,135 +7,340 @@
#pragma once
class CImageDx : public CImage
#include <atlimage.h>
namespace GPDE = Gdiplus::DllExports;
class CImageDx
{
protected:
HBITMAP m_hBitmap = NULL;
public:
CImageDx() : CImage()
CImageDx()
{
GetImageHorizontalResolution = NULL;
GetImageVerticalResolution = NULL;
BitmapSetResolution = NULL;
_shared()->AddRef();
}
~CImageDx()
{
if (m_hBitmap)
::DeleteObject(m_hBitmap);
_shared()->Release();
}
void Attach(HBITMAP hbm)
{
if (m_hBitmap)
::DeleteObject(m_hBitmap);
m_hBitmap = hbm;
}
HBITMAP Detach()
{
HBITMAP hbmOld = m_hBitmap;
m_hBitmap = NULL;
return hbmOld;
}
BOOL GetResolution(Gdiplus::GpImage *pImage, float *pxDpi, float *pyDpi)
{
*pxDpi = 96;
*pyDpi = 96;
if (GetImageHorizontalResolution == NULL || GetImageVerticalResolution == NULL)
if (!get_fn(_shared()->m_GetImageHorizontalResolution, "GdipGetImageHorizontalResolution") ||
!get_fn(_shared()->m_GetImageVerticalResolution, "GdipGetImageVerticalResolution"))
{
GetImageHorizontalResolution =
AddrOf<GETIMAGEHORIZONTALRESOLUTION>("GdipGetImageHorizontalResolution");
GetImageVerticalResolution =
AddrOf<GETIMAGEVERTICALRESOLUTION>("GdipGetImageVerticalResolution");
return FALSE;
}
if (GetImageHorizontalResolution == NULL || GetImageVerticalResolution == NULL)
return FALSE;
if (pxDpi)
_shared()->m_GetImageHorizontalResolution(pImage, pxDpi);
if (pyDpi)
_shared()->m_GetImageVerticalResolution(pImage, pyDpi);
GetImageHorizontalResolution(pImage, pxDpi);
GetImageVerticalResolution(pImage, pyDpi);
return TRUE;
}
BOOL SetResolution(Gdiplus::GpBitmap *pBitmap, float xDpi, float yDpi) const
BOOL SetResolution(Gdiplus::GpBitmap *pBitmap, float xDpi, float yDpi)
{
if (BitmapSetResolution == NULL)
BitmapSetResolution = AddrOf<BITMAPSETRESOLUTION>("GdipBitmapSetResolution");
if (BitmapSetResolution == NULL)
if (!get_fn(_shared()->m_BitmapSetResolution, "GdipBitmapSetResolution"))
return FALSE;
BitmapSetResolution(pBitmap, xDpi, yDpi);
_shared()->m_BitmapSetResolution(pBitmap, xDpi, yDpi);
return TRUE;
}
HRESULT LoadDx(LPCTSTR pszFileName, float *pxDpi, float *pyDpi) throw()
{
// convert the file name string into Unicode
CStringW pszNameW(pszFileName);
// create a GpBitmap object from file
using namespace Gdiplus;
GpBitmap *pBitmap = NULL;
if (GetCommon().CreateBitmapFromFile(pszNameW, &pBitmap) != Ok)
_shared()->AddRef();
if (!get_fn(_shared()->m_CreateBitmapFromFile, "GdipCreateBitmapFromFile") ||
!get_fn(_shared()->m_CreateHBITMAPFromBitmap, "GdipCreateHBITMAPFromBitmap") ||
!get_fn(_shared()->m_DisposeImage, "GdipDisposeImage"))
{
_shared()->Release();
return E_FAIL;
}
// get bitmap handle
// create a GpBitmap object from file
GpBitmap *pBitmap = NULL;
if (_shared()->m_CreateBitmapFromFile(pszFileName, &pBitmap) != Ok)
{
_shared()->Release();
return E_FAIL;
}
// get an HBITMAP
HBITMAP hbm = NULL;
Color color(0xFF, 0xFF, 0xFF);
Gdiplus::Status status;
status = GetCommon().CreateHBITMAPFromBitmap(pBitmap, &hbm, color.GetValue());
Status status = _shared()->m_CreateHBITMAPFromBitmap(pBitmap, &hbm, color.GetValue());
// get the resolution
GetResolution((Gdiplus::GpImage*)pBitmap, pxDpi, pyDpi);
if (pxDpi || pyDpi)
GetResolution((GpImage*)pBitmap, pxDpi, pyDpi);
// delete GpBitmap
GetCommon().DisposeImage(pBitmap);
_shared()->m_DisposeImage(pBitmap);
// attach it
if (status == Ok)
Attach(hbm);
_shared()->Release();
return (status == Ok ? S_OK : E_FAIL);
}
HRESULT SaveDx(LPCTSTR pszFileName, REFGUID guidFileType = GUID_NULL,
float xDpi = 0, float yDpi = 0) const throw()
float xDpi = 0, float yDpi = 0) throw()
{
using namespace Gdiplus;
ATLASSERT(m_hbm);
// TODO & FIXME: set parameters (m_rgbTransColor etc.)
_shared()->AddRef();
// convert the file name string into Unicode
CStringW pszNameW(pszFileName);
// if the file type is null, get the file type from extension
const GUID *FileType = &guidFileType;
if (::IsEqualGUID(guidFileType, GUID_NULL))
if (!get_fn(_shared()->m_CreateBitmapFromHBITMAP, "GdipCreateBitmapFromHBITMAP") ||
!get_fn(_shared()->m_SaveImageToFile, "GdipSaveImageToFile") ||
!get_fn(_shared()->m_DisposeImage, "GdipDisposeImage"))
{
LPCWSTR pszExt = GetFileExtension(pszNameW);
FileType = FileTypeFromExtension(pszExt);
}
// get CLSID from file type
CLSID clsid;
if (!GetClsidFromFileType(&clsid, FileType))
_shared()->Release();
return E_FAIL;
}
// create a GpBitmap from HBITMAP
GpBitmap *pBitmap = NULL;
GetCommon().CreateBitmapFromHBITMAP(m_hbm, NULL, &pBitmap);
_shared()->m_CreateBitmapFromHBITMAP(m_hBitmap, NULL, &pBitmap);
// set the resolution
SetResolution(pBitmap, xDpi, yDpi);
// Get encoders
UINT cEncoders = 0;
ImageCodecInfo* pEncoders = GetAllEncoders(cEncoders);
// if the file type is null, get the file type from extension
CLSID clsid;
if (::IsEqualGUID(guidFileType, GUID_NULL))
{
CString strExt(PathFindExtension(pszFileName));
clsid = FindCodecForExtension(strExt, pEncoders, cEncoders);
}
else
{
clsid = FindCodecForFileType(guidFileType, pEncoders, cEncoders);
}
delete[] pEncoders;
// save to file
Status status;
status = GetCommon().SaveImageToFile(pBitmap, pszNameW, &clsid, NULL);
Status status = _shared()->m_SaveImageToFile(pBitmap, pszFileName, &clsid, NULL);
// destroy GpBitmap
GetCommon().DisposeImage(pBitmap);
_shared()->m_DisposeImage(pBitmap);
_shared()->Release();
return (status == Ok ? S_OK : E_FAIL);
}
protected:
// get procedure address of the DLL
template <typename TYPE>
TYPE AddrOf(const char *name) const
static BOOL IsExtensionSupported(PWCHAR pchDotExt)
{
FARPROC proc = ::GetProcAddress(GetCommon().hinstGdiPlus, name);
return reinterpret_cast<TYPE>(proc);
_shared()->AddRef();
UINT cEncoders;
Gdiplus::ImageCodecInfo* pEncoders = GetAllEncoders(cEncoders);
CLSID clsid = FindCodecForExtension(pchDotExt, pEncoders, cEncoders);
BOOL ret = !::IsEqualGUID(clsid, CLSID_NULL);
delete[] pEncoders;
_shared()->Release();
return ret;
}
typedef St (WINGDIPAPI *GETIMAGEHORIZONTALRESOLUTION)(Im *, float*);
typedef St (WINGDIPAPI *GETIMAGEVERTICALRESOLUTION)(Im *, float*);
typedef St (WINGDIPAPI *BITMAPSETRESOLUTION)(Bm *, float, float);
protected:
using FN_Startup = decltype(&Gdiplus::GdiplusStartup);
using FN_Shutdown = decltype(&Gdiplus::GdiplusShutdown);
using FN_GetImageHorizontalResolution = decltype(&GPDE::GdipGetImageHorizontalResolution);
using FN_GetImageVerticalResolution = decltype(&GPDE::GdipGetImageVerticalResolution);
using FN_BitmapSetResolution = decltype(&GPDE::GdipBitmapSetResolution);
using FN_CreateBitmapFromHBITMAP = decltype(&GPDE::GdipCreateBitmapFromHBITMAP);
using FN_CreateBitmapFromFile = decltype(&GPDE::GdipCreateBitmapFromFile);
using FN_CreateHBITMAPFromBitmap = decltype(&GPDE::GdipCreateHBITMAPFromBitmap);
using FN_SaveImageToFile = decltype(&GPDE::GdipSaveImageToFile);
using FN_DisposeImage = decltype(&GPDE::GdipDisposeImage);
using FN_GetImageEncodersSize = decltype(&GPDE::GdipGetImageEncodersSize);
using FN_GetImageEncoders = decltype(&GPDE::GdipGetImageEncoders);
GETIMAGEHORIZONTALRESOLUTION GetImageHorizontalResolution;
GETIMAGEVERTICALRESOLUTION GetImageVerticalResolution;
mutable BITMAPSETRESOLUTION BitmapSetResolution;
struct SHARED
{
HINSTANCE m_hGdiPlus = NULL;
LONG m_cRefs = 0;
ULONG_PTR m_dwToken = 0;
FN_Shutdown m_Shutdown = NULL;
FN_GetImageHorizontalResolution m_GetImageHorizontalResolution = NULL;
FN_GetImageVerticalResolution m_GetImageVerticalResolution = NULL;
FN_BitmapSetResolution m_BitmapSetResolution = NULL;
FN_CreateBitmapFromHBITMAP m_CreateBitmapFromHBITMAP = NULL;
FN_CreateBitmapFromFile m_CreateBitmapFromFile = NULL;
FN_CreateHBITMAPFromBitmap m_CreateHBITMAPFromBitmap = NULL;
FN_SaveImageToFile m_SaveImageToFile = NULL;
FN_DisposeImage m_DisposeImage = NULL;
FN_GetImageEncodersSize m_GetImageEncodersSize = NULL;
FN_GetImageEncoders m_GetImageEncoders = NULL;
HINSTANCE Init()
{
if (m_hGdiPlus)
return m_hGdiPlus;
m_hGdiPlus = ::LoadLibraryW(L"gdiplus.dll");
if (!m_hGdiPlus)
return NULL;
FN_Startup Startup = (FN_Startup)GetProcAddress(m_hGdiPlus, "GdiplusStartup");
m_Shutdown = (FN_Shutdown)GetProcAddress(m_hGdiPlus, "GdiplusShutdown");
if (!Startup || !m_Shutdown)
{
::FreeLibrary(m_hGdiPlus);
m_hGdiPlus = NULL;
return NULL;
}
Gdiplus::GdiplusStartupInput gdiplusStartupInput;
Startup(&m_dwToken, &gdiplusStartupInput, NULL);
return m_hGdiPlus;
}
void Free()
{
::FreeLibrary(m_hGdiPlus);
ZeroMemory(this, sizeof(*this));
}
LONG AddRef()
{
return ++m_cRefs;
}
LONG Release()
{
if (--m_cRefs == 0)
{
Free();
return 0;
}
return m_cRefs;
}
};
static SHARED* _shared()
{
static SHARED s_shared;
return &s_shared;
}
static Gdiplus::ImageCodecInfo* GetAllEncoders(UINT& cEncoders)
{
Gdiplus::ImageCodecInfo *ret = NULL;
UINT total_size;
if (!get_fn(_shared()->m_GetImageEncodersSize, "GdipGetImageEncodersSize") ||
!get_fn(_shared()->m_GetImageEncoders, "GdipGetImageEncoders"))
{
cEncoders = 0;
return NULL;
}
_shared()->m_GetImageEncodersSize(&cEncoders, &total_size);
if (total_size == 0)
return NULL;
ret = new Gdiplus::ImageCodecInfo[total_size / sizeof(ret[0])];
if (ret == NULL)
{
cEncoders = 0;
return NULL;
}
_shared()->m_GetImageEncoders(cEncoders, total_size, ret);
return ret; // needs delete[]
}
template <typename FN_T>
static bool get_fn(FN_T& fn, const char *name)
{
if (fn)
return true;
HINSTANCE hGdiPlus = _shared()->Init();
fn = reinterpret_cast<FN_T>(::GetProcAddress(hGdiPlus, name));
return fn != NULL;
}
// CImage::FindCodecForExtension is private. We have to duplicate it at here...
static CLSID
FindCodecForExtension(LPCTSTR dotext, const Gdiplus::ImageCodecInfo *pCodecs, UINT nCodecs)
{
for (UINT i = 0; i < nCodecs; ++i)
{
CString strSpecs(pCodecs[i].FilenameExtension);
int ichOld = 0, ichSep;
for (;;)
{
ichSep = strSpecs.Find(TEXT(';'), ichOld);
CString strSpec;
if (ichSep < 0)
strSpec = strSpecs.Mid(ichOld);
else
strSpec = strSpecs.Mid(ichOld, ichSep - ichOld);
int ichDot = strSpec.ReverseFind(TEXT('.'));
if (ichDot >= 0)
strSpec = strSpec.Mid(ichDot);
if (!dotext || strSpec.CompareNoCase(dotext) == 0)
return pCodecs[i].Clsid;
if (ichSep < 0)
break;
ichOld = ichSep + 1;
}
}
return CLSID_NULL;
}
// CImage::FindCodecForFileType is private. We have to duplicate it at here...
static CLSID
FindCodecForFileType(REFGUID guidFileType, const Gdiplus::ImageCodecInfo *pCodecs, UINT nCodecs)
{
for (UINT iInfo = 0; iInfo < nCodecs; ++iInfo)
{
if (::IsEqualGUID(pCodecs[iInfo].FormatID, guidFileType))
return pCodecs[iInfo].Clsid;
}
return CLSID_NULL;
}
};

View file

@ -262,7 +262,7 @@ HBITMAP DoLoadImageFile(HWND hwnd, LPCWSTR name, BOOL fIsMainFile)
// load the image
CImageDx img;
float xDpi, yDpi;
float xDpi = 0, yDpi = 0;
HRESULT hr = img.LoadDx(name, &xDpi, &yDpi);
if (FAILED(hr))
{
@ -274,12 +274,16 @@ HBITMAP DoLoadImageFile(HWND hwnd, LPCWSTR name, BOOL fIsMainFile)
if (!fIsMainFile)
return hBitmap;
if (xDpi <= 0 || yDpi <= 0)
{
HDC hDC = ::GetDC(NULL);
xDpi = ::GetDeviceCaps(hDC, LOGPIXELSX);
yDpi = ::GetDeviceCaps(hDC, LOGPIXELSY);
::ReleaseDC(NULL, hDC);
}
g_xDpi = xDpi;
g_yDpi = yDpi;
if (g_xDpi <= 0)
g_xDpi = 96;
if (g_yDpi <= 0)
g_yDpi = 96;
SetBitmapAndInfo(hBitmap, name, &find, TRUE);
return hBitmap;

View file

@ -13,7 +13,6 @@
#include <tchar.h>
#include <atlbase.h>
#include <atlcom.h>
#include <atlimage.h>
#include <atlpath.h>
#include <atlstr.h>
#include <atlwin.h>

View file

@ -141,6 +141,16 @@ void CMainWindow::saveImage(BOOL overwrite)
{
canvasWindow.finishDrawing();
// Is the extension not supported?
PWCHAR pchDotExt = PathFindExtensionW(g_szFileName);
if (pchDotExt && *pchDotExt && !CImageDx::IsExtensionSupported(pchDotExt))
{
// Remove the extension
PathRemoveExtensionW(g_szFileName);
// No overwrite
overwrite = FALSE;
}
if (g_isAFile && overwrite)
{
imageModel.SaveImage(g_szFileName);

View file

@ -1056,50 +1056,6 @@ protected:
return CLSID_NULL;
}
// Deprecated. Don't use this
static const GUID *FileTypeFromExtension(LPCTSTR dotext)
{
CImage dummy; // HACK: Initialize common
UINT cEncoders = 0;
Gdiplus::ImageCodecInfo* pEncoders = _getAllEncoders(cEncoders);
for (UINT i = 0; i < cEncoders; ++i)
{
CString strSpecs(pEncoders[i].FilenameExtension);
int ichOld = 0, ichSep;
for (;;)
{
ichSep = strSpecs.Find(TEXT(';'), ichOld);
CString strSpec;
if (ichSep < 0)
strSpec = strSpecs.Mid(ichOld);
else
strSpec = strSpecs.Mid(ichOld, ichSep - ichOld);
int ichDot = strSpec.ReverseFind(TEXT('.'));
if (ichDot >= 0)
strSpec = strSpec.Mid(ichDot);
if (!dotext || strSpec.CompareNoCase(dotext) == 0)
{
static GUID s_guid;
s_guid = pEncoders[i].FormatID;
delete[] pEncoders;
return &s_guid;
}
if (ichSep < 0)
break;
ichOld = ichSep + 1;
}
}
delete[] pEncoders;
return NULL;
}
static CLSID
FindCodecForFileType(REFGUID guidFileType, const Gdiplus::ImageCodecInfo *pCodecs, UINT nCodecs)
{
@ -1111,17 +1067,6 @@ protected:
return CLSID_NULL;
}
// Deprecated. Don't use this
static bool GetClsidFromFileType(CLSID *clsid, const GUID *guid)
{
CImage dummy; // HACK: Initialize common
UINT cEncoders = 0;
Gdiplus::ImageCodecInfo* pEncoders = _getAllEncoders(cEncoders);
*clsid = FindCodecForFileType(*guid, pEncoders, cEncoders);
delete[] pEncoders;
return true;
}
static Gdiplus::ImageCodecInfo* _getAllEncoders(UINT& cEncoders)
{
UINT total_size = 0;