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