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

Sam*_*Sam 6 c windows clipboard winapi bitmap

如何使用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;
}
Run Code Online (Sandbox Code Playgroud)

我不确定如何使用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;
}
Run Code Online (Sandbox Code Playgroud)

任何人都可以提供一些有关如何解决此问题的见解?

编辑

根据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;
}
Run Code Online (Sandbox Code Playgroud)

但它仍然有相同的结果.我究竟做错了什么?

最终编辑

工作代码:

#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;
}
Run Code Online (Sandbox Code Playgroud)

谢谢,马丁!

mar*_*inr 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 ):

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

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

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

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