Как скопировать растровое изображение в буфер обмена с помощью win32 API?
как скопировать буфер, который будет сохранен в".Bmp " файл в буфер обмена с помощью win32 API? То есть, У меня есть необработанный буфер растрового изображения Windows V3 (включая заголовок), который я могу буквально write()
в файл и приведет к действительным .BMP-файл, но я хочу скопировать его в буфер обмена.
в OS X, в обычном C, код будет выглядеть примерно так (который работает по назначению):
#include <ApplicationServices/ApplicationServices.h>
int copyBitmapToClipboard(char *bitmapBuffer, size_t buflen)
{
PasteboardRef clipboard;
CFDataRef data;
if (PasteboardCreate(kPasteboardClipboard, &clipboard) != noErr) {
return PASTE_OPEN_ERROR;
}
if (PasteboardClear(clipboard) != noErr) return PASTE_CLEAR_ERROR;
data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, bitmapBuffer, buflen,
kCFAllocatorNull);
if (data == NULL) {
CFRelease(clipboard);
return PASTE_DATA_ERROR;
}
if (PasteboardPutItemFlavor(clipboard, 42, kUTTypeBMP, data, 0) != noErr) {
CFRelease(data);
CFRelease(clipboard);
return PASTE_PASTE_ERROR;
}
CFRelease(data);
CFRelease(clipboard);
return PASTE_WE_DID_IT_YAY;
}
Я не уверен, как это сделать с помощью win32 API. Это насколько я понял, но он, похоже, молча терпит неудачу (то есть функция возвращается с успешным кодом ошибки, но при попытке вставить элемент меню отключен).
#include <windows/windows.h>
int copyBitmapToClipboard(char *bitmapBuffer, size_t buflen)
{
if (!OpenClipboard(NULL)) return PASTE_OPEN_ERROR;
if (!EmptyClipboard()) return PASTE_CLEAR_ERROR;
if (SetClipboardData(CF_DSPBITMAP, bitmapBuffer) == NULL) {
CloseClipboard();
return PASTE_PASTE_ERROR;
}
CloseClipboard();
return PASTE_WE_DID_IT_YAY;
}
может кто-нибудь дать некоторое представление о том, как исправить это?
редактировать
за Аарона и предложения martinr, я сейчас изменил код следующим образом:
#include <windows/windows.h>
int copyBitmapToClipboard(char *bitmapBuffer, size_t buflen)
{
HGLOBAL hResult;
if (!OpenClipboard(NULL)) return PASTE_OPEN_ERROR;
if (!EmptyClipboard()) return PASTE_CLEAR_ERROR;
hResult = GlobalAlloc(GMEM_MOVEABLE, buflen);
if (hResult == NULL) return PASTE_DATA_ERROR;
memcpy(GlobalLock(hResult), bitmapBuffer, buflen);
GlobalUnlock(hResult);
if (SetClipboardData(CF_DSPBITMAP, hResult) == NULL) {
CloseClipboard();
return PASTE_PASTE_ERROR;
}
CloseClipboard();
return PASTE_WE_DID_IT_YAY;
}
но он по-прежнему имеет тот же результат. Что я делаю не так?
финал Edit
работающий код:
#include <windows/windows.h>
int copyBitmapToClipboard(char *bitmapBuffer, size_t buflen)
{
HGLOBAL hResult;
if (!OpenClipboard(NULL)) return PASTE_OPEN_ERROR;
if (!EmptyClipboard()) return PASTE_CLEAR_ERROR;
buflen -= sizeof(BITMAPFILEHEADER);
hResult = GlobalAlloc(GMEM_MOVEABLE, buflen);
if (hResult == NULL) return PASTE_DATA_ERROR;
memcpy(GlobalLock(hResult), bitmapBuffer + sizeof(BITMAPFILEHEADER), buflen);
GlobalUnlock(hResult);
if (SetClipboardData(CF_DIB, hResult) == NULL) {
CloseClipboard();
return PASTE_PASTE_ERROR;
}
CloseClipboard();
GlobalFree(hResult);
return PASTE_WE_DID_IT_YAY;
}
спасибо, martinr!
3 ответов
Я думаю, что hMem должен быть возвращаемым значением из LocalAlloc, HMEMORY, а не указателем.
редактировать
Извините да, GlobalAlloc с GMEM_MOVEABLE требуется, а не LocalAlloc.
редактировать
Я предлагаю вам использовать CF_DIB
тип формата данных буфера обмена.
Диб это же как БМП только без BITMAPFILEHEADER
, поэтому скопируйте исходные байты, за исключением первого sizeof(BITMAPFILEHEADER)
байты.
редактировать
из документации OpenClipboard () (http://msdn.microsoft.com/en-us/library/ms649048 (VS.85).aspx):
" если приложение вызывает OpenClipboard с hwnd равным NULL, EmptyClipboard задает владельцу буфера обмена значение NULL; это приводит к сбою SetClipboardData."
вам нужно настроить окно; даже если вы не делаете WM_RENDERFORMAT типа вещи.
Я нашел это много с Windows Апис. Я не использовал API буфера обмена как таковые, но с другими API я обычно находил, что создание скрытого окна и передача этого дескриптора соответствующему API было достаточно, чтобы держать его в секрете. Обычно есть некоторые заметки о вопросы для этого, если вы создаете окно из DLL, а не EXE; прочитайте все, что является последним Microsoft word о DLL, циклах сообщений и создании окна.
в отношенииBITMAPINFO
, это не начало потока буфера обмена хочет видеть: - буфер, который вы даете SetClipboardData, должен начинаться сразу после остановки BITMAPFILEHEADER.
вам нужно передать дескриптор SetClipboard() (то есть - память, выделенная GlobalAlloc ()), а не передавать прямой указатель на ваше растровое изображение.
Эхо Аарон и martinr. Пример здесь, решающее значение раздел:
// Allocate a global memory object for the text.
hglbCopy = GlobalAlloc(GMEM_MOVEABLE,
(cch + 1) * sizeof(TCHAR));
if (hglbCopy == NULL)
{
CloseClipboard();
return FALSE;
}
// Lock the handle and copy the text to the buffer.
lptstrCopy = GlobalLock(hglbCopy);
memcpy(lptstrCopy, &pbox->atchLabel[ich1],
cch * sizeof(TCHAR));
lptstrCopy[cch] = (TCHAR) 0; // null character
GlobalUnlock(hglbCopy);
// Place the handle on the clipboard.
SetClipboardData(CF_TEXT, hglbCopy);