mirror of
https://github.com/reactos/reactos.git
synced 2025-08-05 08:53:02 +00:00
[ATL] Make CImage thread-safe (#5553)
- Add CInitGDIPlus subclass in CImage. - Lock the CInitGDIPlus data by using a critical section. - Add CImage::InitGDIPlus and use it. CORE-19008
This commit is contained in:
parent
fa7d5dbf06
commit
485c03ad03
1 changed files with 181 additions and 154 deletions
|
@ -12,9 +12,6 @@
|
||||||
// See rostest/apitests/atl/CImage_WIP.txt for test results.
|
// See rostest/apitests/atl/CImage_WIP.txt for test results.
|
||||||
// !!!!
|
// !!!!
|
||||||
|
|
||||||
// TODO: CImage::Load, CImage::Save
|
|
||||||
// TODO: make CImage thread-safe
|
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <atlcore.h> // for ATL Core
|
#include <atlcore.h> // for ATL Core
|
||||||
|
@ -58,25 +55,26 @@ public:
|
||||||
m_rgbTransColor = CLR_INVALID;
|
m_rgbTransColor = CLR_INVALID;
|
||||||
ZeroMemory(&m_ds, sizeof(m_ds));
|
ZeroMemory(&m_ds, sizeof(m_ds));
|
||||||
|
|
||||||
if (GetCommon().AddRef() == 1)
|
s_gdiplus.IncreaseCImageCount();
|
||||||
{
|
|
||||||
GetCommon().LoadLib();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~CImage()
|
virtual ~CImage() throw()
|
||||||
{
|
{
|
||||||
Destroy();
|
Destroy();
|
||||||
ReleaseGDIPlus();
|
s_gdiplus.DecreaseCImageCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
operator HBITMAP()
|
operator HBITMAP() throw()
|
||||||
{
|
{
|
||||||
return m_hbm;
|
return m_hbm;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
static void ReleaseGDIPlus()
|
||||||
void Attach(HBITMAP hBitmap, DIBOrientation eOrientation = DIBOR_DEFAULT)
|
{
|
||||||
|
s_gdiplus.ReleaseGDIPlus();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Attach(HBITMAP hBitmap, DIBOrientation eOrientation = DIBOR_DEFAULT) throw()
|
||||||
{
|
{
|
||||||
AttachInternal(hBitmap, eOrientation, -1);
|
AttachInternal(hBitmap, eOrientation, -1);
|
||||||
}
|
}
|
||||||
|
@ -119,7 +117,6 @@ public:
|
||||||
m_hDC = NULL;
|
m_hDC = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
|
||||||
BOOL AlphaBlend(HDC hDestDC,
|
BOOL AlphaBlend(HDC hDestDC,
|
||||||
int xDest, int yDest, int nDestWidth, int nDestHeight,
|
int xDest, int yDest, int nDestWidth, int nDestHeight,
|
||||||
int xSrc, int ySrc, int nSrcWidth, int nSrcHeight,
|
int xSrc, int ySrc, int nSrcWidth, int nSrcHeight,
|
||||||
|
@ -376,13 +373,16 @@ public:
|
||||||
|
|
||||||
HRESULT Load(LPCTSTR pszFileName) throw()
|
HRESULT Load(LPCTSTR pszFileName) throw()
|
||||||
{
|
{
|
||||||
|
if (!InitGDIPlus())
|
||||||
|
return E_FAIL;
|
||||||
|
|
||||||
// convert the file name string into Unicode
|
// convert the file name string into Unicode
|
||||||
CStringW pszNameW(pszFileName);
|
CStringW pszNameW(pszFileName);
|
||||||
|
|
||||||
// create a GpBitmap object from file
|
// create a GpBitmap object from file
|
||||||
using namespace Gdiplus;
|
using namespace Gdiplus;
|
||||||
GpBitmap *pBitmap = NULL;
|
GpBitmap *pBitmap = NULL;
|
||||||
if (GetCommon().CreateBitmapFromFile(pszNameW, &pBitmap) != Ok)
|
if (s_gdiplus.CreateBitmapFromFile(pszNameW, &pBitmap) != Ok)
|
||||||
{
|
{
|
||||||
return E_FAIL;
|
return E_FAIL;
|
||||||
}
|
}
|
||||||
|
@ -390,10 +390,10 @@ public:
|
||||||
// get bitmap handle
|
// get bitmap handle
|
||||||
HBITMAP hbm = NULL;
|
HBITMAP hbm = NULL;
|
||||||
Color color(0xFF, 0xFF, 0xFF);
|
Color color(0xFF, 0xFF, 0xFF);
|
||||||
Status status = GetCommon().CreateHBITMAPFromBitmap(pBitmap, &hbm, color.GetValue());
|
Status status = s_gdiplus.CreateHBITMAPFromBitmap(pBitmap, &hbm, color.GetValue());
|
||||||
|
|
||||||
// delete GpBitmap
|
// delete GpBitmap
|
||||||
GetCommon().DisposeImage(pBitmap);
|
s_gdiplus.DisposeImage(pBitmap);
|
||||||
|
|
||||||
// attach it
|
// attach it
|
||||||
if (status == Ok)
|
if (status == Ok)
|
||||||
|
@ -402,10 +402,13 @@ public:
|
||||||
}
|
}
|
||||||
HRESULT Load(IStream* pStream) throw()
|
HRESULT Load(IStream* pStream) throw()
|
||||||
{
|
{
|
||||||
|
if (!InitGDIPlus())
|
||||||
|
return E_FAIL;
|
||||||
|
|
||||||
// create GpBitmap from stream
|
// create GpBitmap from stream
|
||||||
using namespace Gdiplus;
|
using namespace Gdiplus;
|
||||||
GpBitmap *pBitmap = NULL;
|
GpBitmap *pBitmap = NULL;
|
||||||
if (GetCommon().CreateBitmapFromStream(pStream, &pBitmap) != Ok)
|
if (s_gdiplus.CreateBitmapFromStream(pStream, &pBitmap) != Ok)
|
||||||
{
|
{
|
||||||
return E_FAIL;
|
return E_FAIL;
|
||||||
}
|
}
|
||||||
|
@ -413,10 +416,10 @@ public:
|
||||||
// get bitmap handle
|
// get bitmap handle
|
||||||
HBITMAP hbm = NULL;
|
HBITMAP hbm = NULL;
|
||||||
Color color(0xFF, 0xFF, 0xFF);
|
Color color(0xFF, 0xFF, 0xFF);
|
||||||
Status status = GetCommon().CreateHBITMAPFromBitmap(pBitmap, &hbm, color.GetValue());
|
Status status = s_gdiplus.CreateHBITMAPFromBitmap(pBitmap, &hbm, color.GetValue());
|
||||||
|
|
||||||
// delete Bitmap
|
// delete Bitmap
|
||||||
GetCommon().DisposeImage(pBitmap);
|
s_gdiplus.DisposeImage(pBitmap);
|
||||||
|
|
||||||
// attach it
|
// attach it
|
||||||
if (status == Ok)
|
if (status == Ok)
|
||||||
|
@ -502,18 +505,11 @@ public:
|
||||||
return PlgBlt(hDestDC, pPoints, rectSrc, hbmMask, pointMask);
|
return PlgBlt(hDestDC, pPoints, rectSrc, hbmMask, pointMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReleaseGDIPlus() throw()
|
|
||||||
{
|
|
||||||
COMMON*& pCommon = GetCommonPtr();
|
|
||||||
if (pCommon && pCommon->Release() == 0)
|
|
||||||
{
|
|
||||||
delete pCommon;
|
|
||||||
pCommon = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT Save(IStream* pStream, GUID *guidFileType) const throw()
|
HRESULT Save(IStream* pStream, GUID *guidFileType) const throw()
|
||||||
{
|
{
|
||||||
|
if (!InitGDIPlus())
|
||||||
|
return E_FAIL;
|
||||||
|
|
||||||
using namespace Gdiplus;
|
using namespace Gdiplus;
|
||||||
ATLASSERT(m_hbm);
|
ATLASSERT(m_hbm);
|
||||||
|
|
||||||
|
@ -527,14 +523,14 @@ public:
|
||||||
|
|
||||||
// create a GpBitmap from HBITMAP
|
// create a GpBitmap from HBITMAP
|
||||||
GpBitmap *pBitmap = NULL;
|
GpBitmap *pBitmap = NULL;
|
||||||
GetCommon().CreateBitmapFromHBITMAP(m_hbm, NULL, &pBitmap);
|
s_gdiplus.CreateBitmapFromHBITMAP(m_hbm, NULL, &pBitmap);
|
||||||
|
|
||||||
// save to stream
|
// save to stream
|
||||||
Status status;
|
Status status;
|
||||||
status = GetCommon().SaveImageToStream(pBitmap, pStream, &clsid, NULL);
|
status = s_gdiplus.SaveImageToStream(pBitmap, pStream, &clsid, NULL);
|
||||||
|
|
||||||
// destroy GpBitmap
|
// destroy GpBitmap
|
||||||
GetCommon().DisposeImage(pBitmap);
|
s_gdiplus.DisposeImage(pBitmap);
|
||||||
|
|
||||||
return (status == Ok ? S_OK : E_FAIL);
|
return (status == Ok ? S_OK : E_FAIL);
|
||||||
}
|
}
|
||||||
|
@ -542,6 +538,9 @@ public:
|
||||||
HRESULT Save(LPCTSTR pszFileName,
|
HRESULT Save(LPCTSTR pszFileName,
|
||||||
REFGUID guidFileType = GUID_NULL) const throw()
|
REFGUID guidFileType = GUID_NULL) const throw()
|
||||||
{
|
{
|
||||||
|
if (!InitGDIPlus())
|
||||||
|
return E_FAIL;
|
||||||
|
|
||||||
using namespace Gdiplus;
|
using namespace Gdiplus;
|
||||||
ATLASSERT(m_hbm);
|
ATLASSERT(m_hbm);
|
||||||
|
|
||||||
|
@ -567,13 +566,13 @@ public:
|
||||||
|
|
||||||
// create a GpBitmap from HBITMAP
|
// create a GpBitmap from HBITMAP
|
||||||
GpBitmap *pBitmap = NULL;
|
GpBitmap *pBitmap = NULL;
|
||||||
GetCommon().CreateBitmapFromHBITMAP(m_hbm, NULL, &pBitmap);
|
s_gdiplus.CreateBitmapFromHBITMAP(m_hbm, NULL, &pBitmap);
|
||||||
|
|
||||||
// save to file
|
// save to file
|
||||||
Status status = GetCommon().SaveImageToFile(pBitmap, pszNameW, &clsid, NULL);
|
Status status = s_gdiplus.SaveImageToFile(pBitmap, pszNameW, &clsid, NULL);
|
||||||
|
|
||||||
// destroy GpBitmap
|
// destroy GpBitmap
|
||||||
GetCommon().DisposeImage(pBitmap);
|
s_gdiplus.DisposeImage(pBitmap);
|
||||||
|
|
||||||
return (status == Ok ? S_OK : E_FAIL);
|
return (status == Ok ? S_OK : E_FAIL);
|
||||||
}
|
}
|
||||||
|
@ -689,7 +688,6 @@ public:
|
||||||
rectSrc.bottom - rectSrc.top, crTransparent);
|
rectSrc.bottom - rectSrc.top, crTransparent);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
|
||||||
static BOOL IsTransparencySupported() throw()
|
static BOOL IsTransparencySupported() throw()
|
||||||
{
|
{
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
@ -710,7 +708,7 @@ public:
|
||||||
excludeDefaultSave = excludeIcon | excludeEMF | excludeWMF
|
excludeDefaultSave = excludeIcon | excludeEMF | excludeWMF
|
||||||
};
|
};
|
||||||
|
|
||||||
protected:
|
private:
|
||||||
static bool ShouldExcludeFormat(REFGUID guidFileType, DWORD dwExclude)
|
static bool ShouldExcludeFormat(REFGUID guidFileType, DWORD dwExclude)
|
||||||
{
|
{
|
||||||
if (::IsEqualGUID(guidFileType, Gdiplus::ImageFormatGIF))
|
if (::IsEqualGUID(guidFileType, Gdiplus::ImageFormatGIF))
|
||||||
|
@ -811,7 +809,9 @@ public:
|
||||||
DWORD dwExclude = excludeDefaultLoad,
|
DWORD dwExclude = excludeDefaultLoad,
|
||||||
TCHAR chSeparator = TEXT('|'))
|
TCHAR chSeparator = TEXT('|'))
|
||||||
{
|
{
|
||||||
CImage dummy; // HACK: Initialize common
|
if (!InitGDIPlus())
|
||||||
|
return E_FAIL;
|
||||||
|
|
||||||
UINT cDecoders = 0;
|
UINT cDecoders = 0;
|
||||||
Gdiplus::ImageCodecInfo* pDecoders = _getAllDecoders(cDecoders);
|
Gdiplus::ImageCodecInfo* pDecoders = _getAllDecoders(cDecoders);
|
||||||
HRESULT hr = BuildCodecFilterString(pDecoders,
|
HRESULT hr = BuildCodecFilterString(pDecoders,
|
||||||
|
@ -832,7 +832,9 @@ public:
|
||||||
DWORD dwExclude = excludeDefaultSave,
|
DWORD dwExclude = excludeDefaultSave,
|
||||||
TCHAR chSeparator = TEXT('|'))
|
TCHAR chSeparator = TEXT('|'))
|
||||||
{
|
{
|
||||||
CImage dummy; // HACK: Initialize common
|
if (!InitGDIPlus())
|
||||||
|
return E_FAIL;
|
||||||
|
|
||||||
UINT cEncoders = 0;
|
UINT cEncoders = 0;
|
||||||
Gdiplus::ImageCodecInfo* pEncoders = _getAllEncoders(cEncoders);
|
Gdiplus::ImageCodecInfo* pEncoders = _getAllEncoders(cEncoders);
|
||||||
HRESULT hr = BuildCodecFilterString(pEncoders,
|
HRESULT hr = BuildCodecFilterString(pEncoders,
|
||||||
|
@ -846,153 +848,177 @@ public:
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
private:
|
||||||
// an extension of BITMAPINFO
|
// an extension of BITMAPINFO
|
||||||
struct MYBITMAPINFOEX : BITMAPINFO
|
struct MYBITMAPINFOEX : BITMAPINFO
|
||||||
{
|
{
|
||||||
RGBQUAD bmiColorsExtra[256 - 1];
|
RGBQUAD bmiColorsExtra[256 - 1];
|
||||||
};
|
};
|
||||||
|
|
||||||
// abbreviations of GDI+ basic types. FIXME: Delete us
|
class CInitGDIPlus
|
||||||
typedef Gdiplus::GpStatus St;
|
|
||||||
typedef Gdiplus::GpBitmap Bm;
|
|
||||||
typedef Gdiplus::GpImage Im;
|
|
||||||
|
|
||||||
// The common data of atlimage
|
|
||||||
struct COMMON
|
|
||||||
{
|
{
|
||||||
|
private:
|
||||||
// GDI+ function types
|
// GDI+ function types
|
||||||
using FUN_Startup = decltype(&Gdiplus::GdiplusStartup);
|
using FUN_Startup = decltype(&Gdiplus::GdiplusStartup);
|
||||||
using FUN_Shutdown = decltype(&Gdiplus::GdiplusShutdown);
|
using FUN_Shutdown = decltype(&Gdiplus::GdiplusShutdown);
|
||||||
using FUN_GetImageEncoderSize = decltype(&Gdiplus::DllExports::GdipGetImageEncodersSize);
|
|
||||||
using FUN_GetImageEncoder = decltype(&Gdiplus::DllExports::GdipGetImageEncoders);
|
|
||||||
using FUN_GetImageDecoderSize = decltype(&Gdiplus::DllExports::GdipGetImageDecodersSize);
|
|
||||||
using FUN_GetImageDecoder = decltype(&Gdiplus::DllExports::GdipGetImageDecoders);
|
|
||||||
using FUN_CreateBitmapFromFile = decltype(&Gdiplus::DllExports::GdipCreateBitmapFromFile);
|
using FUN_CreateBitmapFromFile = decltype(&Gdiplus::DllExports::GdipCreateBitmapFromFile);
|
||||||
using FUN_CreateHBITMAPFromBitmap = decltype(&Gdiplus::DllExports::GdipCreateHBITMAPFromBitmap);
|
|
||||||
using FUN_CreateBitmapFromStream = decltype(&Gdiplus::DllExports::GdipCreateBitmapFromStream);
|
|
||||||
using FUN_CreateBitmapFromHBITMAP = decltype(&Gdiplus::DllExports::GdipCreateBitmapFromHBITMAP);
|
using FUN_CreateBitmapFromHBITMAP = decltype(&Gdiplus::DllExports::GdipCreateBitmapFromHBITMAP);
|
||||||
using FUN_SaveImageToStream = decltype(&Gdiplus::DllExports::GdipSaveImageToStream);
|
using FUN_CreateBitmapFromStream = decltype(&Gdiplus::DllExports::GdipCreateBitmapFromStream);
|
||||||
using FUN_SaveImageToFile = decltype(&Gdiplus::DllExports::GdipSaveImageToFile);
|
using FUN_CreateHBITMAPFromBitmap = decltype(&Gdiplus::DllExports::GdipCreateHBITMAPFromBitmap);
|
||||||
using FUN_DisposeImage = decltype(&Gdiplus::DllExports::GdipDisposeImage);
|
using FUN_DisposeImage = decltype(&Gdiplus::DllExports::GdipDisposeImage);
|
||||||
|
using FUN_GetImageDecoder = decltype(&Gdiplus::DllExports::GdipGetImageDecoders);
|
||||||
|
using FUN_GetImageDecoderSize = decltype(&Gdiplus::DllExports::GdipGetImageDecodersSize);
|
||||||
|
using FUN_GetImageEncoder = decltype(&Gdiplus::DllExports::GdipGetImageEncoders);
|
||||||
|
using FUN_GetImageEncoderSize = decltype(&Gdiplus::DllExports::GdipGetImageEncodersSize);
|
||||||
|
using FUN_SaveImageToFile = decltype(&Gdiplus::DllExports::GdipSaveImageToFile);
|
||||||
|
using FUN_SaveImageToStream = decltype(&Gdiplus::DllExports::GdipSaveImageToStream);
|
||||||
|
|
||||||
// members
|
// members
|
||||||
int count = 0;
|
HINSTANCE m_hInst;
|
||||||
HINSTANCE hinstGdiPlus = NULL;
|
ULONG_PTR m_dwToken;
|
||||||
ULONG_PTR gdiplusToken = 0;
|
CRITICAL_SECTION m_sect;
|
||||||
|
LONG m_nCImageObjects;
|
||||||
|
DWORD m_dwLastError;
|
||||||
|
|
||||||
// GDI+ functions
|
void _clear_funs() throw()
|
||||||
FUN_Startup Startup = NULL;
|
|
||||||
FUN_Shutdown Shutdown = NULL;
|
|
||||||
FUN_GetImageEncoderSize GetImageEncodersSize = NULL;
|
|
||||||
FUN_GetImageEncoder GetImageEncoders = NULL;
|
|
||||||
FUN_GetImageDecoderSize GetImageDecodersSize = NULL;
|
|
||||||
FUN_GetImageDecoder GetImageDecoders = NULL;
|
|
||||||
FUN_CreateBitmapFromFile CreateBitmapFromFile = NULL;
|
|
||||||
FUN_CreateHBITMAPFromBitmap CreateHBITMAPFromBitmap = NULL;
|
|
||||||
FUN_CreateBitmapFromStream CreateBitmapFromStream = NULL;
|
|
||||||
FUN_CreateBitmapFromHBITMAP CreateBitmapFromHBITMAP = NULL;
|
|
||||||
FUN_SaveImageToStream SaveImageToStream = NULL;
|
|
||||||
FUN_SaveImageToFile SaveImageToFile = NULL;
|
|
||||||
FUN_DisposeImage DisposeImage = NULL;
|
|
||||||
|
|
||||||
COMMON()
|
|
||||||
{
|
{
|
||||||
|
Startup = NULL;
|
||||||
|
Shutdown = NULL;
|
||||||
|
CreateBitmapFromFile = NULL;
|
||||||
|
CreateBitmapFromHBITMAP = NULL;
|
||||||
|
CreateBitmapFromStream = NULL;
|
||||||
|
CreateHBITMAPFromBitmap = NULL;
|
||||||
|
DisposeImage = NULL;
|
||||||
|
GetImageDecoders = NULL;
|
||||||
|
GetImageDecodersSize = NULL;
|
||||||
|
GetImageEncoders = NULL;
|
||||||
|
GetImageEncodersSize = NULL;
|
||||||
|
SaveImageToFile = NULL;
|
||||||
|
SaveImageToStream = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
~COMMON()
|
template <typename T_FUN>
|
||||||
|
T_FUN _get_fun(T_FUN& fun, LPCSTR name) throw()
|
||||||
{
|
{
|
||||||
FreeLib();
|
if (!fun)
|
||||||
}
|
fun = reinterpret_cast<T_FUN>(::GetProcAddress(m_hInst, name));
|
||||||
|
|
||||||
ULONG AddRef()
|
|
||||||
{
|
|
||||||
return ++count;
|
|
||||||
}
|
|
||||||
ULONG Release()
|
|
||||||
{
|
|
||||||
return --count;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get procedure address of the DLL
|
|
||||||
template <typename FUN_T>
|
|
||||||
FUN_T _getFUN(FUN_T& fun, const char *name)
|
|
||||||
{
|
|
||||||
if (fun)
|
|
||||||
return fun;
|
|
||||||
fun = reinterpret_cast<FUN_T>(::GetProcAddress(hinstGdiPlus, name));
|
|
||||||
return fun;
|
return fun;
|
||||||
}
|
}
|
||||||
|
|
||||||
HINSTANCE LoadLib()
|
public:
|
||||||
|
// GDI+ functions
|
||||||
|
FUN_Startup Startup;
|
||||||
|
FUN_Shutdown Shutdown;
|
||||||
|
FUN_CreateBitmapFromFile CreateBitmapFromFile;
|
||||||
|
FUN_CreateBitmapFromHBITMAP CreateBitmapFromHBITMAP;
|
||||||
|
FUN_CreateBitmapFromStream CreateBitmapFromStream;
|
||||||
|
FUN_CreateHBITMAPFromBitmap CreateHBITMAPFromBitmap;
|
||||||
|
FUN_DisposeImage DisposeImage;
|
||||||
|
FUN_GetImageDecoder GetImageDecoders;
|
||||||
|
FUN_GetImageDecoderSize GetImageDecodersSize;
|
||||||
|
FUN_GetImageEncoder GetImageEncoders;
|
||||||
|
FUN_GetImageEncoderSize GetImageEncodersSize;
|
||||||
|
FUN_SaveImageToFile SaveImageToFile;
|
||||||
|
FUN_SaveImageToStream SaveImageToStream;
|
||||||
|
|
||||||
|
CInitGDIPlus() throw()
|
||||||
|
: m_hInst(NULL)
|
||||||
|
, m_dwToken(0)
|
||||||
|
, m_nCImageObjects(0)
|
||||||
|
, m_dwLastError(ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
if (hinstGdiPlus)
|
_clear_funs();
|
||||||
return hinstGdiPlus;
|
::InitializeCriticalSection(&m_sect);
|
||||||
|
}
|
||||||
|
|
||||||
hinstGdiPlus = ::LoadLibraryA("gdiplus.dll");
|
~CInitGDIPlus() throw()
|
||||||
|
{
|
||||||
|
ReleaseGDIPlus();
|
||||||
|
::DeleteCriticalSection(&m_sect);
|
||||||
|
}
|
||||||
|
|
||||||
_getFUN(Startup, "GdiplusStartup");
|
bool Init() throw()
|
||||||
_getFUN(Shutdown, "GdiplusShutdown");
|
{
|
||||||
_getFUN(GetImageEncodersSize, "GdipGetImageEncodersSize");
|
::EnterCriticalSection(&m_sect);
|
||||||
_getFUN(GetImageEncoders, "GdipGetImageEncoders");
|
|
||||||
_getFUN(GetImageDecodersSize, "GdipGetImageDecodersSize");
|
|
||||||
_getFUN(GetImageDecoders, "GdipGetImageDecoders");
|
|
||||||
_getFUN(CreateBitmapFromFile, "GdipCreateBitmapFromFile");
|
|
||||||
_getFUN(CreateHBITMAPFromBitmap, "GdipCreateHBITMAPFromBitmap");
|
|
||||||
_getFUN(CreateBitmapFromStream, "GdipCreateBitmapFromStream");
|
|
||||||
_getFUN(CreateBitmapFromHBITMAP, "GdipCreateBitmapFromHBITMAP");
|
|
||||||
_getFUN(SaveImageToStream, "GdipSaveImageToStream");
|
|
||||||
_getFUN(SaveImageToFile, "GdipSaveImageToFile");
|
|
||||||
_getFUN(DisposeImage, "GdipDisposeImage");
|
|
||||||
|
|
||||||
if (hinstGdiPlus && Startup)
|
if (m_dwToken == 0)
|
||||||
{
|
{
|
||||||
Gdiplus::GdiplusStartupInput gdiplusStartupInput;
|
if (!m_hInst)
|
||||||
Startup(&gdiplusToken, &gdiplusStartupInput, NULL);
|
m_hInst = ::LoadLibrary(TEXT("gdiplus.dll"));
|
||||||
|
|
||||||
|
if (m_hInst &&
|
||||||
|
_get_fun(Startup, "GdiplusStartup") &&
|
||||||
|
_get_fun(Shutdown, "GdiplusShutdown") &&
|
||||||
|
_get_fun(CreateBitmapFromFile, "GdipCreateBitmapFromFile") &&
|
||||||
|
_get_fun(CreateBitmapFromHBITMAP, "GdipCreateBitmapFromHBITMAP") &&
|
||||||
|
_get_fun(CreateBitmapFromStream, "GdipCreateBitmapFromStream") &&
|
||||||
|
_get_fun(CreateHBITMAPFromBitmap, "GdipCreateHBITMAPFromBitmap") &&
|
||||||
|
_get_fun(DisposeImage, "GdipDisposeImage") &&
|
||||||
|
_get_fun(GetImageDecoders, "GdipGetImageDecoders") &&
|
||||||
|
_get_fun(GetImageDecodersSize, "GdipGetImageDecodersSize") &&
|
||||||
|
_get_fun(GetImageEncoders, "GdipGetImageEncoders") &&
|
||||||
|
_get_fun(GetImageEncodersSize, "GdipGetImageEncodersSize") &&
|
||||||
|
_get_fun(SaveImageToFile, "GdipSaveImageToFile") &&
|
||||||
|
_get_fun(SaveImageToStream, "GdipSaveImageToStream"))
|
||||||
|
{
|
||||||
|
using namespace Gdiplus;
|
||||||
|
GdiplusStartupInput input;
|
||||||
|
GdiplusStartupOutput output;
|
||||||
|
Startup(&m_dwToken, &input, &output);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return hinstGdiPlus;
|
bool ret = (m_dwToken != 0);
|
||||||
|
::LeaveCriticalSection(&m_sect);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
void FreeLib()
|
|
||||||
|
void ReleaseGDIPlus() throw()
|
||||||
{
|
{
|
||||||
if (hinstGdiPlus)
|
::EnterCriticalSection(&m_sect);
|
||||||
|
if (m_dwToken)
|
||||||
{
|
{
|
||||||
Shutdown(gdiplusToken);
|
if (Shutdown)
|
||||||
|
Shutdown(m_dwToken);
|
||||||
|
|
||||||
Startup = NULL;
|
m_dwToken = 0;
|
||||||
Shutdown = NULL;
|
|
||||||
GetImageEncodersSize = NULL;
|
|
||||||
GetImageEncoders = NULL;
|
|
||||||
GetImageDecodersSize = NULL;
|
|
||||||
GetImageDecoders = NULL;
|
|
||||||
CreateBitmapFromFile = NULL;
|
|
||||||
CreateHBITMAPFromBitmap = NULL;
|
|
||||||
CreateBitmapFromStream = NULL;
|
|
||||||
CreateBitmapFromHBITMAP = NULL;
|
|
||||||
SaveImageToStream = NULL;
|
|
||||||
SaveImageToFile = NULL;
|
|
||||||
DisposeImage = NULL;
|
|
||||||
::FreeLibrary(hinstGdiPlus);
|
|
||||||
hinstGdiPlus = NULL;
|
|
||||||
}
|
}
|
||||||
|
if (m_hInst)
|
||||||
|
{
|
||||||
|
::FreeLibrary(m_hInst);
|
||||||
|
m_hInst = NULL;
|
||||||
|
}
|
||||||
|
_clear_funs();
|
||||||
|
::LeaveCriticalSection(&m_sect);
|
||||||
}
|
}
|
||||||
}; // struct COMMON
|
|
||||||
|
|
||||||
static COMMON*& GetCommonPtr()
|
void IncreaseCImageCount() throw()
|
||||||
|
{
|
||||||
|
::EnterCriticalSection(&m_sect);
|
||||||
|
++m_nCImageObjects;
|
||||||
|
::LeaveCriticalSection(&m_sect);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DecreaseCImageCount() throw()
|
||||||
|
{
|
||||||
|
::EnterCriticalSection(&m_sect);
|
||||||
|
if (--m_nCImageObjects == 0)
|
||||||
|
{
|
||||||
|
ReleaseGDIPlus();
|
||||||
|
}
|
||||||
|
::LeaveCriticalSection(&m_sect);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static CInitGDIPlus s_gdiplus;
|
||||||
|
|
||||||
|
static bool InitGDIPlus() throw()
|
||||||
{
|
{
|
||||||
static COMMON *s_pCommon = NULL;
|
return s_gdiplus.Init();
|
||||||
return s_pCommon;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static COMMON& GetCommon()
|
private:
|
||||||
{
|
|
||||||
COMMON*& pCommon = GetCommonPtr();
|
|
||||||
if (pCommon == NULL)
|
|
||||||
pCommon = new COMMON;
|
|
||||||
return *pCommon;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
HBITMAP m_hbm;
|
HBITMAP m_hbm;
|
||||||
mutable HGDIOBJ m_hbmOld;
|
mutable HGDIOBJ m_hbmOld;
|
||||||
mutable HDC m_hDC;
|
mutable HDC m_hDC;
|
||||||
|
@ -1070,7 +1096,7 @@ protected:
|
||||||
static Gdiplus::ImageCodecInfo* _getAllEncoders(UINT& cEncoders)
|
static Gdiplus::ImageCodecInfo* _getAllEncoders(UINT& cEncoders)
|
||||||
{
|
{
|
||||||
UINT total_size = 0;
|
UINT total_size = 0;
|
||||||
GetCommon().GetImageEncodersSize(&cEncoders, &total_size);
|
s_gdiplus.GetImageEncodersSize(&cEncoders, &total_size);
|
||||||
if (total_size == 0)
|
if (total_size == 0)
|
||||||
return NULL; // failure
|
return NULL; // failure
|
||||||
|
|
||||||
|
@ -1082,14 +1108,14 @@ protected:
|
||||||
return NULL; // failure
|
return NULL; // failure
|
||||||
}
|
}
|
||||||
|
|
||||||
GetCommon().GetImageEncoders(cEncoders, total_size, ret);
|
s_gdiplus.GetImageEncoders(cEncoders, total_size, ret);
|
||||||
return ret; // needs delete[]
|
return ret; // needs delete[]
|
||||||
}
|
}
|
||||||
|
|
||||||
static Gdiplus::ImageCodecInfo* _getAllDecoders(UINT& cDecoders)
|
static Gdiplus::ImageCodecInfo* _getAllDecoders(UINT& cDecoders)
|
||||||
{
|
{
|
||||||
UINT total_size = 0;
|
UINT total_size = 0;
|
||||||
GetCommon().GetImageDecodersSize(&cDecoders, &total_size);
|
s_gdiplus.GetImageDecodersSize(&cDecoders, &total_size);
|
||||||
if (total_size == 0)
|
if (total_size == 0)
|
||||||
return NULL; // failure
|
return NULL; // failure
|
||||||
|
|
||||||
|
@ -1101,12 +1127,12 @@ protected:
|
||||||
return NULL; // failure
|
return NULL; // failure
|
||||||
}
|
}
|
||||||
|
|
||||||
GetCommon().GetImageDecoders(cDecoders, total_size, ret);
|
s_gdiplus.GetImageDecoders(cDecoders, total_size, ret);
|
||||||
return ret; // needs delete[]
|
return ret; // needs delete[]
|
||||||
}
|
}
|
||||||
|
|
||||||
void AttachInternal(HBITMAP hBitmap, DIBOrientation eOrientation,
|
void AttachInternal(HBITMAP hBitmap, DIBOrientation eOrientation,
|
||||||
LONG iTransColor)
|
LONG iTransColor) throw()
|
||||||
{
|
{
|
||||||
Destroy();
|
Destroy();
|
||||||
|
|
||||||
|
@ -1187,11 +1213,12 @@ protected:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// NOTE: CImage is not copyable
|
CImage(const CImage&) = delete;
|
||||||
CImage(const CImage&);
|
CImage& operator=(const CImage&) = delete;
|
||||||
CImage& operator=(const CImage&);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
DECLSPEC_SELECTANY CImage::CInitGDIPlus CImage::s_gdiplus;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue