如何使用win32 API将位图复制到剪贴板?

时间:2009-12-29 22:34:25

标签: c windows winapi bitmap clipboard

如何使用win32 API将保存为“.BMP”文件的缓冲区复制到剪贴板?即,我有一个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;
}

有人能提供一些有关如何解决这个问题的见解吗?

修改

Per 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;
}

谢谢,马丁!“

3 个答案:

答案 0 :(得分:3)

我认为hMem需要是LocalAlloc的返回值,一个HMEMORY而不是一个指针。

修改

很抱歉,需要使用GMEM_MOVEABLE的GlobalAlloc,而不是LocalAlloc。

修改

我建议您使用CF_DIB剪贴板数据格式类型。

DIB与BMP相同,只是没有BITMAPFILEHEADER,因此复制除第一个sizeof(BITMAPFILEHEADER)字节之外的源字节。

修改

来自OpenClipboard()文档(http://msdn.microsoft.com/en-us/library/ms649048(VS.85).aspx):

“如果应用程序在hwnd设置为NULL的情况下调用OpenClipboard,则EmptyClipboard会将剪贴板所有者设置为NULL;这会导致SetClipboardData失败。”

你需要设置一个窗口;即使你没有做WM_RENDERFORMAT类型的东西。

我在Windows API中发现了很多。我没有使用剪贴板API本身,但我使用其他API,我通常发现创建一个隐藏的窗口并将该句柄传递给相关的API足以让它保持安静。如果您是从DLL而不是EXE创建窗口,那么通常会对问题做一些注释。阅读有关DLL,消息循环和窗口创建的最新Microsoft字样。

关于BITMAPINFO,这不是剪贴板想要看到的流的开始: - 您给SetClipboardData的缓冲区应该在BITMAPFILEHEADER停止之后立即开始。

答案 1 :(得分:3)

您需要将HANDLE传递给SetClipboard()(即 - 使用GlobalAlloc()分配的内存),而不是将直指针传递给您的位图。

答案 2 :(得分:0)

回声亚伦和马丁。示例here,关键部分:

    // 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);