Как скопировать битовый массив в буфер обмена с помощью win32 API?

Как я копирую буфер, который сохранил бы в ".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!

6
задан Sam 30 December 2009 в 01:09
поделиться

3 ответа

Я думаю, что это должно быть возвращаемое из 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.

.
3
ответ дан 17 December 2019 в 02:29
поделиться

Нужно передать в SetClipboard() HANDLE (то есть - память, выделенная с помощью GlobalAlloc()), а не передавать прямой указатель на растровую карту.

.
3
ответ дан 17 December 2019 в 02:29
поделиться

Эко Аарон и Мартинер. Пример здесь, критический раздел:

    // 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); 
0
ответ дан 17 December 2019 в 02:29
поделиться
Другие вопросы по тегам:

Похожие вопросы: