I'm trying to write a function to read images copied to the clipboard with Windows Imaging Component. Currently my code is based off how I load resources but modified to work with the clipboard. everything up to initializing the stream works fine but once I try to use CreateDecoderFromeStream
it fails. I've tried copying images from numerous places to no avail. Is there something different about the copied image format that can't be read by WIC?
Here's my code below...
Creating a memory object to read from the clipboard
COMStreamSPtr WIC::createStreamFromClipboard() {
IStream* ipStream = NULL;
COMStreamSPtr stream = nullptr;
CoInitialize(nullptr);
if (!IsClipboardFormatAvailable(CF_BITMAP) && !IsClipboardFormatAvailable(CF_DIB) && !IsClipboardFormatAvailable(CF_DIBV5))
goto Return;
if (!OpenClipboard(NULL))
goto Return;
// Load the clipboard
HGLOBAL hMem = GetClipboardData(CF_BITMAP);
if (hMem == NULL || hMem == INVALID_HANDLE_VALUE)
hMem = GetClipboardData(CF_DIB);
if (hMem == NULL || hMem == INVALID_HANDLE_VALUE)
hMem = GetClipboardData(CF_DIBV5);
if (hMem == NULL || hMem == INVALID_HANDLE_VALUE)
goto CloseClipboard;
// Lock the clipboard, getting a pointer to its data
LPVOID pvSourceClipboardData = GlobalLock(hMem);
if (pvSourceClipboardData == NULL)
goto CloseClipboard;
// Read the clipboard data size
DWORD dwClipboardSize = GlobalSize(hMem);
if (dwClipboardSize == 0)
goto GlobalUnlock;
// Allocate memory to hold the clipboard data
HGLOBAL hgblClipboardData = GlobalAlloc(GMEM_MOVEABLE, dwClipboardSize);
if (hgblClipboardData == NULL)
goto GlobalUnlock;
// Get a pointer to the allocated memory
LPVOID pvClipboardData = GlobalLock(hgblClipboardData);
if (pvClipboardData == NULL)
goto FreeData;
// Copy the data from the clipboard to the new memory block
CopyMemory(pvClipboardData, pvSourceClipboardData, dwClipboardSize);
GlobalUnlock(hgblClipboardData);
// Create a stream on the HGLOBAL containing the data
if (SUCCEEDED(CreateStreamOnHGlobal(hgblClipboardData, TRUE, &ipStream))) {
stream = std::make_shared<COMStream>(ipStream);
goto CloseClipboard;
}
FreeData:
// Couldn't create stream; free the memory
GlobalFree(hgblClipboardData);
GlobalUnlock:
// Unlock the clipboard data
GlobalUnlock(hMem);
CloseClipboard:
// Close the clipboard
CloseClipboard();
Return:
// No need to unlock or free the resource
CoUninitialize(); // CoInialize is called by my COMObjects in the constructor so this is just decrementing the count.
return stream;
}
Elsewhere in the code using the returned stream.
WICBitmapDecoderSPtr WIC::createDecoderFromStream(COMStreamSPtr stream) {
if (isCOMObjectNull(stream))
return nullptr;
IWICImagingFactory* ipFactory = NULL;
IWICBitmapDecoder* ipDecoder = NULL;
WICBitmapDecoderSPtr decoder = nullptr;
// Create the factory
if (FAILED(CoCreateInstance(CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&ipFactory))))
goto Return;
// Create the decoder
if (FAILED(ipFactory->CreateDecoderFromStream(stream->ipObject, NULL, WICDecodeMetadataCacheOnDemand, &ipDecoder)))
goto ReleaseFactory; // FAILS HERE
decoder = std::make_shared<WICBitmapDecoder>(ipDecoder);
ReleaseFactory:
ipFactory->Release();
Return:
return decoder;
}
I've finally figured out how to do this. What I did is I used IWICImagingFactory
's CreateBitmapFromHBITMAP
function. Since reading an HBITMAP
from the clipboard work trivial, the solution becomes pretty straight forward.
IWICBitmapSource* WIC::readSourceFromClipboard() {
IWICBitmapSource* ipSource = NULL;
if (Clipboard::containsFormat(CF_BITMAP)) {
if (OpenClipboard(NULL)) {
HBITMAP hBitmap = (HBITMAP)GetClipboardData(CF_BITMAP);
ipSource = createSourceFromHBitmap(hBitmap);
CloseClipboard();
}
}
return ipSource;
}
IWICBitmapSource* WIC::createSourceFromHBitmap(HBITMAP hBitmap) {
if (hBitmap == NULL)
return NULL;
IWICImagingFactory* ipFactory = NULL;
IWICBitmap* ipBitmap = NULL;
CoInitialize(NULL);
// Create the factory
if (FAILED(CoCreateInstance(CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&ipFactory))))
goto Return;
// Create the bitmap
if (FAILED(ipFactory->CreateBitmapFromHBITMAP(hBitmap, NULL, WICBitmapIgnoreAlpha, &ipBitmap)))
goto ReleaseFactory;
ReleaseFactory:
ipFactory->Release();
Return:
CoUninitialize();
return ipBitmap;
}