Creating HBITMAP from memory buffer
Solution 1:
I'd use CreateCompatibleBitmap
, and then call SetDIBits
to fill it with your data. These are functions I have seen to work, and SetDIBits is quite flexible, although verbose.
In my MFC years, CreateBitmap
was avoided due to suspected performance issues.
Solution 2:
Using GdiPlus I got something that works pretty well and doesn't involve pulling any teeth!
Gdiplus::Bitmap* pBitmap = NULL;
IStream* pStream = NULL;
HRESULT hResult = ::CreateStreamOnHGlobal( NULL, TRUE, &pStream );
if(hResult == S_OK && pStream)
{
hResult = pStream->Write(&bits[0], ULONG(bits.size()), NULL);
if(hResult == S_OK)
pBitmap = Gdiplus::Bitmap::FromStream(pStream);
pStream->Release();
}
Edit: Changed per Jegatheesh
Solution 3:
A slight variation on the answer provided by AJG85, that employs SHCreateMemStream in place of CreateStreamOnHGlobal
. SHCreateMemStream
was introduced as a public API in Windows Vista, and provides the benefit of creating an IStream
over an existing region in memory, thus avoiding an additional memory allocation:
#include <Shlwapi.h>
#include <atlimage.h>
#include <comdef.h>
#include <comip.h>
#include <vector>
#pragma comment(lib, "Shlwapi.lib")
#if defined(_DEBUG)
# pragma comment(lib, "comsuppwd.lib")
#else
# pragma comment(lib, "comsuppw.lib")
#endif
HBITMAP from_data(std::vector<unsigned char> const& data)
{
if (data.empty())
{
_com_issue_error(E_INVALIDARG);
}
auto const stream { ::SHCreateMemStream(&data[0], static_cast<UINT>(data.size())) };
if (!stream)
{
_com_issue_error(E_OUTOFMEMORY);
}
_COM_SMARTPTR_TYPEDEF(IStream, __uuidof(IStream));
IStreamPtr sp_stream { stream, false };
CImage img {};
_com_util::CheckError(img.Load(sp_stream));
return img.Detach();
}
This implementation either throws a _com_error
, or returns an HBITMAP
that refers to the image constructed from the in-memory data.
When the function returns, the memory buffer can be safely freed. The returned HBITMAP
is owned by the caller, and needs to be released with a call to DeleteObject.