Я пытался добавить ресурс и использовать некоторые полупрозрачные файлы PNG в своем приложении для Windows Mobile 6.x.После нескольких дней осмотра и экспериментов с различными методами, я решил динамически загружать и использовать gdiplus.dll и использовать плоские API.все работает, кроме функции GdipCreateHBITMAPFromBitmap возвращает NotImplemented (6).Есть идеи, как решить эту проблему?У меня есть 3 файла, которые я прилагаю здесь.
GdiPlusDynamic.cpp:
#include "GdiPlusDynamic.h"
#include "GdiPlusDynamicTools.h"
#include <string>
TAutoStream::TAutoStream(HGLOBAL m_hBuffer)
{
pStream = NULL;
switch(::CreateStreamOnHGlobal(m_hBuffer, TRUE, &pStream))
{
case E_NOINTERFACE:
throw std::wstring(L"The specified interface is not supported");
break;
case E_OUTOFMEMORY:
throw std::wstring(L"Not enough memory");
break;
default:
break;
}
}
TAutoStream::~TAutoStream(void)
{
if(NULL != pStream)
pStream->Release();
}
IStream* TAutoStream::get(void)
{
return pStream;
}
AutoGlobal::AutoGlobal(UINT uFlags, SIZE_T dwBytes) : len(0)
{
m_hBuffer = ::GlobalAlloc(uFlags, dwBytes);
if(IsOk())
{
memset(m_hBuffer, 0, dwBytes);
len = dwBytes;
}
}
AutoGlobal::~AutoGlobal(void)
{
if(IsOk())
::GlobalFree(m_hBuffer);
}
bool AutoGlobal::IsOk(void)
{
return (NULL != m_hBuffer);
}
HGLOBAL AutoGlobal::get(void)
{
return m_hBuffer;
}
TAutoLockedBuff::TAutoLockedBuff(UINT uFlags, SIZE_T dwBytes) : AutoGlobal(uFlags, dwBytes)
{
pBuffer = NULL;
if(AutoGlobal::IsOk())
pBuffer = GlobalLock(m_hBuffer);
}
TAutoLockedBuff::~TAutoLockedBuff(void)
{
if(IsOk())
GlobalUnlock(m_hBuffer);
}
bool TAutoLockedBuff::IsOk(void)
{
return (AutoGlobal::IsOk() && (NULL != pBuffer));
}
void TAutoLockedBuff::CopyFrom(const void* pSrcData, SIZE_T srcLen)
{
if(IsOk())
CopyMemory(pBuffer, pSrcData, min(srcLen, len));
}
TDynamicGdiPlus::TDynamicGdiPlus(void) : everythigOK(false)
{
GdiplusStartupInput dpStartupInfo;
token = 0;
pGdiplusStartup = NULL;
pGdiplusShutdown = NULL;
pGdipCreateBitmapFromStream = NULL;
pGdipCreateHBITMAPFromBitmap = NULL;
pGdipFree = NULL;
hGdiPlus = ::LoadLibrary(L"gdiplus.dll");
if(NULL == hGdiPlus)
throw std::wstring(L"Unable to load 'gdiplus.dll'");
pGdiplusStartup = (TGdiplusStartup)GetProcAddress(hGdiPlus, L"GdiplusStartup");
if(NULL == pGdiplusStartup)
throw std::wstring(L"Unable to get the address of 'GdiplusStartup'");
pGdiplusShutdown = (TGdiplusShutdown)GetProcAddress(hGdiPlus, L"GdiplusShutdown");
if(NULL == pGdiplusShutdown)
throw std::wstring(L"Unable to get the address of 'GdiplusShutdown'");
pGdipCreateBitmapFromStream = (TGdipCreateBitmapFromStream)GetProcAddress(hGdiPlus, L"GdipCreateBitmapFromStreamICM");
if(NULL == pGdipCreateBitmapFromStream)
throw std::wstring(L"Unable to get the address of 'GdipCreateBitmapFromStreamICM'");
pGdipCreateHBITMAPFromBitmap = (TGdipCreateHBITMAPFromBitmap)GetProcAddress(hGdiPlus, L"GdipCreateHBITMAPFromBitmap");
if(NULL == pGdipCreateHBITMAPFromBitmap)
throw std::wstring(L"Unable to get the address of 'GdipCreateHBITMAPFromBitmap'");
pGdipFree = (TGdipFree)GetProcAddress(hGdiPlus, L"GdipFree");
if(NULL == pGdipFree)
throw std::wstring(L"Unable to get the address of 'GdipFree'");
if(Status::Ok != pGdiplusStartup(&token, &dpStartupInfo, NULL))
throw std::wstring(L"Unable to start 'GDI Plus'");
else
everythigOK = true;
}
TDynamicGdiPlus::~TDynamicGdiPlus(void)
{
if((0 != token) && (NULL != pGdiplusShutdown))
pGdiplusShutdown(token);
if(NULL != hGdiPlus)
FreeLibrary(hGdiPlus);
}
HBITMAP TDynamicGdiPlus::LoadImageFromResource(HINSTANCE hInst, LPCTSTR lpName, LPCTSTR lpType)
{
HBITMAP retVal = NULL;
if(everythigOK)
{
HRSRC hResource = ::FindResource(hInst, lpName, lpType);
if (NULL != hResource)
{
DWORD imageSize = ::SizeofResource(hInst, hResource);
if (0 < imageSize)
{
const void* pResourceData = ::LockResource(::LoadResource(hInst, hResource));
if (NULL != pResourceData)
{
TAutoLockedBuff m_Buffer(GMEM_MOVEABLE, imageSize + 1);
void* pBmp;
m_Buffer.CopyFrom(pResourceData, imageSize);
TAutoStream m_Stream(m_Buffer.get());
pGdipCreateBitmapFromStream(m_Stream.get(), &pBmp);
if (NULL != pBmp)
{
pGdipCreateHBITMAPFromBitmap(pBmp, &retVal, 0x00FFFFFF); // this returns NotImplemented
pGdipFree(pBmp);
if(NULL == retVal)
throw std::wstring(L"Unable to extract HBITMAP from Gdiplus::Bitmap");
}
else
throw std::wstring(L"Unable to extract Gdiplus::Bitmap from stream");
}
else
throw std::wstring(L"Unable to lock resource");
}
else
throw std::wstring(L"Size of resource is 0");
}
else
throw std::wstring(L"Unable to find resource");
}
return retVal;
}
GdiPlusDynamic.h
#pragma once
typedef enum {
Ok = 0,
GenericError = 1,
InvalidParameter = 2,
OutOfMemory = 3,
ObjectBusy = 4,
InsufficientBuffer = 5,
NotImplemented = 6,
Win32Error = 7,
WrongState = 8,
Aborted = 9,
FileNotFound = 10,
ValueOverflow = 11,
AccessDenied = 12,
UnknownImageFormat = 13,
FontFamilyNotFound = 14,
FontStyleNotFound = 15,
NotTrueTypeFont = 16,
UnsupportedGdiplusVersion = 17,
GdiplusNotInitialized = 18,
PropertyNotFound = 19,
PropertyNotSupported = 20,
ProfileNotFound = 21
} Status;
enum DebugEventLevel
{
DebugEventLevelFatal,
DebugEventLevelWarning
};
// Callback function that GDI+ can call, on debug builds, for assertions
// and warnings.
typedef VOID (WINAPI *DebugEventProc)(DebugEventLevel level, CHAR *message);
// Notification functions which the user must call appropriately if
// "SuppressBackgroundThread" (below) is set.
typedef Status (WINAPI *NotificationHookProc)(OUT ULONG_PTR *token);
typedef VOID (WINAPI *NotificationUnhookProc)(ULONG_PTR token);
struct GdiplusStartupInput
{
UINT32 GdiplusVersion; // Must be 1 (or 2 for the Ex version)
DebugEventProc DebugEventCallback; // Ignored on free builds
BOOL SuppressBackgroundThread; // FALSE unless you're prepared to call
// the hook/unhook functions properly
BOOL SuppressExternalCodecs; // FALSE unless you want GDI+ only to use
// its internal image codecs.
GdiplusStartupInput(
DebugEventProc debugEventCallback = NULL,
BOOL suppressBackgroundThread = FALSE,
BOOL suppressExternalCodecs = FALSE)
{
GdiplusVersion = 1;
DebugEventCallback = debugEventCallback;
SuppressBackgroundThread = suppressBackgroundThread;
SuppressExternalCodecs = suppressExternalCodecs;
}
};
struct GdiplusStartupOutput
{
// The following 2 fields are NULL if SuppressBackgroundThread is FALSE.
// Otherwise, they are functions which must be called appropriately to
// replace the background thread.
//
// These should be called on the application's main message loop - i.e.
// a message loop which is active for the lifetime of GDI+.
// "NotificationHook" should be called before starting the loop,
// and "NotificationUnhook" should be called after the loop ends.
NotificationHookProc NotificationHook;
NotificationUnhookProc NotificationUnhook;
};
typedef Status (WINAPI *TGdiplusStartup)(ULONG_PTR* token, const GdiplusStartupInput *input, GdiplusStartupOutput *output);
typedef void (WINAPI *TGdiplusShutdown)(ULONG_PTR token);
typedef Status (WINAPI *TGdipCreateBitmapFromStream)(IStream* stream, void **bitmap);
typedef Status (WINAPI *TGdipCreateHBITMAPFromBitmap)(void* bitmap, HBITMAP* hbmReturn, DWORD background);
typedef void (WINAPI *TGdipFree)(void* ptr);
class TDynamicGdiPlus
{
private:
bool everythigOK;
protected:
HMODULE hGdiPlus;
TGdiplusStartup pGdiplusStartup;
TGdiplusShutdown pGdiplusShutdown;
TGdipCreateBitmapFromStream pGdipCreateBitmapFromStream;
TGdipCreateHBITMAPFromBitmap pGdipCreateHBITMAPFromBitmap;
TGdipFree pGdipFree;
ULONG_PTR token;
public:
TDynamicGdiPlus(void);
virtual ~TDynamicGdiPlus(void);
HBITMAP LoadImageFromResource(HINSTANCE hInst, LPCTSTR lpName, LPCTSTR lpType);
};
и GdiPlusDynamicTools.h
#pragma once
class TAutoStream
{
protected:
IStream* pStream;
public:
TAutoStream(HGLOBAL m_hBuffer);
virtual ~TAutoStream(void);
IStream* get(void);
};
class AutoGlobal
{
protected:
HGLOBAL m_hBuffer;
SIZE_T len;
public:
AutoGlobal(UINT uFlags, SIZE_T dwBytes);
virtual ~AutoGlobal(void);
bool IsOk(void);
HGLOBAL get(void);
};
class TAutoLockedBuff : public AutoGlobal
{
protected:
void* pBuffer;
public:
TAutoLockedBuff(UINT uFlags, SIZE_T dwBytes);
virtual ~TAutoLockedBuff(void);
bool IsOk(void);
void CopyFrom(const void* pSrcData, SIZE_T srcLen);
};