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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1977363/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 13:39:58  来源:igfitidea点击:

How to copy bitmap to clipboard using the win32 API?

cwindowswinapibitmapclipboard

提问by Sam

How do I copy a buffer that would save to a ".BMP" file to the clipboard using the win32 API? I.e., I have a raw buffer of a Windows V3 Bitmap (including the header) that I can literally write()to a file and will result in a valid .BMP file, but I want to copy it to the clipboard instead.

如何使用 win32 API 将保存到“.BMP”文件的缓冲区复制到剪贴板?即,我有一个 Windows V3 位图(包括标题)的原始缓冲区,我可以从字面上write()将其写入文件并生成有效的 .BMP 文件,但我想将其复制到剪贴板。

On OS X, in plain C, the code would look something like this (which works as intended):

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

I am unsure how to accomplish this with the win32 API. This is as far as I've gotten, but it seems to silently fail (that is, the function returns with a successful error code, but when attempting to paste, the menu item is disabled).

我不确定如何使用 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;
}

Could anyone provide some insight as to how to fix this?

谁能提供一些有关如何解决此问题的见解?

Edit

编辑

Per Aaron and martinr's suggestions, I've now modified the code to the following:

根据 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;
}

But it still has the same result. What am I doing wrong?

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

Final Edit

最终编辑

The working code:

工作代码:

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

Thanks, martinr!

谢谢,马丁!

采纳答案by martinr

I think the hMem needs to be a return value from LocalAlloc, an HMEMORY rather than a pointer.

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

EDIT

编辑

Sorry yes, GlobalAlloc with GMEM_MOVEABLE is required, not LocalAlloc.

抱歉,是的,需要带有 GMEM_MOVEABLE 的 GlobalAlloc,而不是 LocalAlloc。

EDIT

编辑

I suggest you use CF_DIBclipboard data format type.

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

DIB is the same as BMP except it is without the BITMAPFILEHEADER, so copy the source bytes except for the first sizeof(BITMAPFILEHEADER)bytes.

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

EDIT

编辑

From OpenClipboard() documentation (http://msdn.microsoft.com/en-us/library/ms649048(VS.85).aspx):

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

"If an application calls OpenClipboard with hwnd set to NULL, EmptyClipboard sets the clipboard owner to NULL; this causes SetClipboardData to fail."

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

You need to set up a window; even if you're not doing WM_RENDERFORMAT type stuff.

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

I found this a lot with Windows APIs. I haven't used the Clipboard APIs per se but with other APIs I usually found that creating a hidden window and passing that handle to the relevant API was enough to keep it quiet. There's usually some notes on issuesto do with this if you're creating a window from a DLL rather than an EXE; read whatever is the latest Microsoft word about DLLs, message loops and window creation.

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

As regardsBITMAPINFO, that's not the start of the stream the clipboard wants to see :- the buffer you give to SetClipboardData should start right after where the BITMAPFILEHEADER stops.

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

回答by Aaron

You need to pass a HANDLE to SetClipboard() (that is - memory allocated with GlobalAlloc()) rather than passing a straight pointer to your bitmap.

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

回答by J.J.

Echo Aaron and martinr. Example here, crucial section:

Echo Aaron 和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);