2011-03-24 28 views
3

我一直在嘗試添加資源並在Windows Mobile 6.x應用程序中使用一些半透明的PNG文件。在環顧四周並嘗試不同的方法之後,我決定動態加載和使用gdiplus.dll並使用平面API。一切正常,除了函數GdipCreateHBITMAPFromBitmap返回NotImplemented(6)。任何想法如何解決這個問題?我有3個文件,我在這裏附上。使用C++在Windows mobile 6.x中使用透明PNG

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); 
}; 

回答

3

您可以使用IImagingFactory服務,而不是GDI + 這項服務可以使PNG,帶alpha通道的bmp。

下,我們的Windows Mobile 6.x的使用真正的項目該服務

此代碼樣機:

CComPtr<IImagingFactory> spImageFactory; 
spImageFactory.CoCreateInstance(__uuidof(ImagingFactory); 

HRSRC hRes = FindResource(hInstance, MAKEINTRESOURCE(resID), _T("PNG")); 
DWORD imageSize = SizeOfResource(hInstance, hRes); 
HGLOBAL hGlobal = LoadResource(hInstance, hRes); 

CComPtr<IImage> spImage; 
spImageFactory->CreateImageFromBuffer(LockResource(hGlobal, imageSize), BufferDisposalFlagNone, &spImage); 

ImageInfo info = {0}; 
spImage->GetImageInfo(&info); 

CRect rect(x, y, x+info.Width, y+info.Height); 
spImage->Draw(hDc, &rect, NULL); 
+0

你能告訴我,你將如何使用IImageFactory從PNG獲得HBITMAP句柄存儲在資源? – Sam 2011-03-24 19:30:31

+0

查看更新答案。在你的問題中你談論繪製PNG。我認爲以上樣本可以幫助你。 – Victor 2011-03-24 22:28:10

+0

謝謝。這工作。 – Sam 2011-03-25 17:22:13