Как скопировать растровое изображение в буфер обмена с помощью 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);