Как я копирую буфер, который сохранил бы в ".BMP" файл к буферу обмена с помощью win32 API? Т.е. у меня есть необработанный буфер Windows V3 Bitmap (включая заголовок), что я могу буквально 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;
}
Кто-либо мог обеспечить некоторое понимание относительно того, как зафиксировать это?
На Aaron и предложения 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;
}
Но это все еще имеет тот же результат. Что я делаю неправильно?
Рабочий код:
#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!
Я думаю, что это должно быть возвращаемое из LocalAlloc значение, HMEMORY, а не указатель.
EDIT
К сожалению, да, GlobalAlloc с GMEM_MOVEABLE нужен, а не LocalAlloc.
EDIT
Я предлагаю использовать CF_DIB
тип формата данных буфера обмена.
DIB такая же, как и BMP, за исключением отсутствия BITMAPFILEHEADER
, поэтому копируйте исходные байты за исключением первых sizeof(BITMAPFILEHEADER)
байтов.
EDIT
Из документации OpenClipboard() (http://msdn.microsoft.com/en-us/library/ms649048(VS.85). ).aspx):
"Если приложение вызывает OpenClipboard с установленным hwnd значением NULL, EmptyClipboard устанавливает владельца буфера обмена в NULL; это приводит к ошибке SetClipboardData."
Нужно настроить окно; даже если вы не используете тип WM_RENDERFORMAT.
Я нашёл это часто в Windows API. Я не использовал буферные API как таковые, но с другими API я обычно находил, что создания скрытого окна и передачи этого дескриптора в соответствующий API было достаточно, чтобы сделать его незаметным. Обычно есть некоторые заметки о проблемах , если вы создаете окно из DLL, а не из EXE; прочтите все, что написано в Microsoft о DLL, циклах сообщений и создании окон.
Что касаетсяBITMAPINFO
, это не начало потока, который хочет видеть буфер обмена :- буфер, который вы даете SetClipboardData, должен начинаться сразу после того, как остановится BITMAPFILEHEADER.
Нужно передать в SetClipboard() HANDLE (то есть - память, выделенная с помощью GlobalAlloc()), а не передавать прямой указатель на растровую карту.
.Эко Аарон и Мартинер. Пример здесь, критический раздел:
// 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);