简体   繁体   English

使用C ++在Windows Mobile 6.x中使用透明PNG

[英]Working with transparent PNG in Windows mobile 6.x using C++

I have been trying to add to resource and use some semi transparent PNG files in my windows mobile 6.x application. 我一直在尝试添加资源,并在我的Windows Mobile 6.x应用程序中使用一些半透明的PNG文件。 After days of looking around and experimenting with different methods, I decided to dynamically load and use gdiplus.dll and use the flat APIs. 经过几天的环顾四周并尝试不同的方法,我决定动态加载和使用gdiplus.dll并使用平面API。 everything works except function GdipCreateHBITMAPFromBitmap returns NotImplemented (6). 一切正常,除了函数GdipCreateHBITMAPFromBitmap返回NotImplemented(6)。 any idea how to fix this problem? 任何想法如何解决这个问题? I have 3 files that I am attaching here. 我有三个文件,我附在这里。

GdiPlusDynamic.cpp: 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 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);
};

and GdiPlusDynamicTools.h 和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);
};

You can use IImagingFactory service instead GDI+ This service can render png, bmp with alpha channel. 您可以使用IImagingFactory服务代替GDI +此服务可以使用alpha通道渲染png,bmp。

We use this service for real project under Windows Mobile 6.x 我们在Windows Mobile 6.x下将此服务用于实际项目

This code mockup: 这个代码模型:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM