Copying a DIB to the Clipboard

本文介绍了一种将24位设备独立位图(DIB)复制到剪贴板的方法。作者经过多次尝试和求助,最终通过微软提供的示例程序解决了问题,并分享了实现过程及代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Copying a DIB to the Clipboard

By John Simmons / outlaw programmer

Helps with copying a device independant bitmap to the clipboard.

Introduction

Recently, I had cause to save a DIB to the clipboard. I tried numerous methods over a four-week period, but none of them worked (many thanks to Chris Losinger and Christian Graus for their willingness to try and provide me with guidance, an answer, or both). This article describes how I finally attained my goal, but also falls neatly into the category It Ain't Pretty But It Works.

Trials and Tribulations

Since the reason I need to do this is fairly well out of the scope of this article, suffice it to say that my starting point was a BITMAPINFOHEADER struct and a pointer to an array of bits which represented the actual bitmap data. The bitmap was of the 24-bit variety.

At first, I wandered around trying to create a bitmap handle with the info I had. I was sure I was doing it right, but with failure after failure where moving that bitmap to the clipboard was concerned, I (naturally) assumed I must have really mucked it up, so I went looking for help, and ended up using Chris Maunder's CDIBSectionLite class.

Chris's class contains all the code necessary to turn my captured bitmap into a DIBSection, but it lacked the code to move the DIB to the clipboard. This turned out to be a great place to start. However, no matter what I tried, I couldn't get the bitmap to the clipboard.

How It all Came Together

After doinking around for a week trying to coerce the desired functionality out of my code (and CDIBSectionLite), I called the Microsoft Software Developer Hotline (using one of two available free incidents on my MSDN subscription). The guy at MS steered me to a sample that evidently comes with the compiler called wincap32. This sample program will capture the contents of the selected window and convert it to a DIB, and store it on the clipboard. Perfect.

After changing a one or two #include statements, and changing the name of a file, I compiled my code, ran the resulting program, and bingo - DIB on the clipboard!

What I did

The first thing I did was to add this function to the CDIBSectionLite class (remember, it ain't pretty, but it works:

Collapse
HANDLE CDIBSectionLite::PutOnClipboard()
{
HANDLE hResult = NULL;

if (::OpenClipboard(NULL))
{
::EmptyClipboard();
::GdiFlush();

// borrowed these variables from the sample app
HDIB hDib = NULL;
HBITMAP hBitmap = NULL;
HPALETTE ghPal = NULL;

if (m_hBitmap)
{
// call the function that converts the bitmap to a DIB
hDib = BitmapToDIB(m_hBitmap, ghPal);
if (hDib)
{
// ahhh, the sweet smell of success
hResult = ::SetClipboardData(CF_DIB, hDib);
if (hResult == NULL)
{
_ShowLastError();
}
}
else
{
MessageBeep(0);
}
}
::CloseClipboard();
}
return hResult;
}

From the Microsoft sample application, I copied the following files into my project directory:

Collapse
    DIBUTIL.C
DIBUTIL.H
DIBAPI.H

I then renamed the DIBUTIL.C file to DIBUTIL.CPP. After that, I had to make the following changes in that file so that it would compile. The sample app compiled as is, but because I included stdafx.h, the compiler puked on some type mismatches, hence the following changes:

Collapse
Line  30:    #include <windows.h>
to: #include "stdafx.h"

Line 381: lpbi = GlobalLock(hDIB);
to: lpbi = (LPSTR)GlobalLock(hDIB);

Line 524: lpDIBHdr = GlobalLock(hDIB);
to: lpDIBHdr = (LPSTR)GlobalLock(hDIB);

Line 608: hPal = GetStockObject(DEFAULT_PALETTE);
to: hPal = (HPALETTE)GetStockObject(DEFAULT_PALETTE);

Finally, I was using the whole shebang as follows:

Collapse
   // I needed to construct the BITMAPINFO structure to be passed to the 
// CDIBSectionLite object would be happy
HBITMAP hBitmap;
BITMAPINFO bmi;
memset(&bmi, 0, sizeof(BITMAPINFO));
// use the BITMAPINFOHEADER structure that we captured
bmi.bmiHeader = cb.bih;

CDIBSectionLite dib;
// use the BITMAPINFO struct that we created above and the bits we captured
dib.SetBitmap(&bmi, cb.pBuffer);
dib.PutOnClipboard();

In The End

It works. I'm not really interested in culling out just the stuff I need from the files I harvested from the Microsoft sample app, so I intend on just leaving it all in there. This is an exercise I am leaving to the reader.

The zip file accompanying this article contains both the modified CDIBSectionLite class with the modified sample app files, as well as the entire sample app source in it's native form. One thing to note is that if compiled as is, the sample app project creates (or is supplied with) a DLL called DIBAPI.DLL. This DLL contains the code that I linked directly into my program (I didn't want it in DLL form).

Due to the size of the bitmaps I'm capturing, I didn't equip CDIBSectionLite with the ability to save the bitmap on the clipboard as anything other than a DIB. However, keep in mind that it is possible to save multiple items on the clipboard at one time, so you could simultaneously (using the sample app code) place a bitmap on the clipboard in DIB format, device dependent format, and metafile format if that's what trips your trigger. Any app that pastes from the clipboard will/should pull out the format that best fits it's requirements.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

John Simmons / outlaw programmer


Mvp
I've been paid as a programmer since 1982 with experience in Pascal, and C++ (both self-taught). I've been writing Windows programs since 1991 almost exclusively with Visual C++ and MFC. In the 2nd half of 2007, I started writing C# desktop and web applications.

My weakest point is that my moments of clarity are too brief to hold a meaningful conversation that requires more than 30 seconds to complete. Thankfully, grunts of agreement are all that is required to conduct most discussions without committing to any particular belief system.

I really don't care if you vote 1's on my forum posts, but at least act like a professional when it comes to my articles. When you play stupid little voting games because you don't agree with someone's politics or sense of humor, you're cheating all the other members of the site.
Occupation: Software Developer (Senior)
Location: United States United States

From: http://www.codeproject.com/KB/clipboard/dib2clipboard.aspx
### 使用或实现 `toClipboard` 函数的方法 在现代浏览器中,可以通过使用 Clipboard API 来实现复制文本到剪贴板的功能。以下是关于如何实现和使用 `toClipboard` 的方法。 #### 方法一:通过 `navigator.clipboard.writeText` 可以利用 `navigator.clipboard.writeText()` 方法来将指定的字符串写入用户的剪贴板[^5]。此功能需要页面具有安全上下文(HTTPS 或 localhost),并且通常会请求权限以访问剪贴板数据。 ```javascript async function toClipboard(text) { try { await navigator.clipboard.writeText(text); console.log('Content copied to clipboard'); } catch (err) { console.error('Failed to copy: ', err); } } ``` 上述代码定义了一个异步函数 `toClipboard`,它接受一个参数 `text` 并将其复制到剪贴板上。如果操作成功,则会在控制台打印一条消息;如果有错误发生,则捕获并记录该错误。 #### 方法二:兼容旧版浏览器的传统方式 对于不支持 Clipboard API 的较老版本浏览器,可以采用创建临时输入框的方式手动触发复制行为: ```javascript function toClipboardFallback(text) { const textArea = document.createElement("textarea"); textArea.value = text; // 将 textarea 添加至 body 中以便选中文本 document.body.appendChild(textArea); textArea.select(); // 选择文本区域中的内容 try { const successful = document.execCommand('copy'); // 执行复制命令 if(successful){ console.log('Copying was successful.'); }else{ console.warn('Copy command failed.'); } } catch(err) { console.error('Unable to copy.', err); } document.body.removeChild(textArea); // 移除临时创建的 DOM 节点 } ``` 这种方法适用于那些尚未完全支持最新标准的老式环境,尽管其效率可能不如直接调用原生接口那么高效[^6]。 #### 注意事项 - **安全性考量**:由于涉及敏感的操作——即修改用户设备上的剪切板状态,因此许多现代浏览器都会对这些API施加严格的限制条件,比如仅允许 HTTPS 下运行或者强制要求显式的用户交互作为前置动作。 - **跨域问题**:当尝试从不同源加载资源时可能会遇到 CORS 相关的问题,在这种情况下需确保服务器端配置正确从而允许客户端发起此类请求[^7]。 ### 结论 综上所述,无论是借助于最新的 Web 标准所提供的强大工具集还是退而求其次选用更为普遍但也相对繁琐的技术手段都可以有效地达成我们的目标即将特定的数据项传递给系统的全局共享存储空间供后续粘贴之用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值