3

我正在开发一个剪贴板管理器(可以在这里看到:http: //flamefusion.net/software/shapeshifter)。

但是,我目前遇到的问题是位图 ( bmp) 无法真正正确地插入剪贴板。我的第一种方法如下,使用SetClipboardData.

var hBitmap = bmp.GetHBitmap();
SetClipboardData(CF_BITMAP, hBitmap);

我知道这可能存在内存泄漏,并且仅作为测试。测试失败。粘贴到剪贴板中的图像在粘贴时无法被 Paint 读取。

所以经过大量的研究和失败的尝试,我得到了一个新的理论。我正在使用的位图是从 a 创建的MemoryStream,它是通过先前调用该Bitmap.Save(Stream, ImageFormat)方法创建的。这使我相信 aSystem.Drawing.Bitmap不是GetHBitmap函数所期望HBITMAP的那种。SetClipboardData

所以我尝试了以下方法,并取得了某种成功。

var memDC = CreateCompatibleDC(IntPtr.Zero);
var memBitmap = CreateCompatibleBitmap(memDC, bmp.Width, bmp.Height);
SetClipboardData(CF_BITMAP, memBitmap);

现在图像以正确的尺寸插入,但作为黑色图像。这是非常明显的,因为除了bmp宽度和高度之外,实际上没有任何东西用于创建“兼容”位图。

我假设我必须以某种方式使用 BitBlt 将我的原始位图复制到这个现在“兼容”的位图,但我不知道从哪里开始。

你们中的任何一个 GDI 向导都知道吗?这里显然需要魔法。

编辑 1 正如 dthorpe 很好地指出的那样,我的问题似乎是我试图保存的图像实际上是一个 DIB。现在问题变了。我需要弄清楚如何从 DIB 转换为 DDB。我知道在执行此操作时会造成 alpha 损失,但仍然需要它。

编辑 2 不能接受使用Clipboard.SetImage. 这在我的场景中不起作用。我需要使用 API。

4

2 回答 2

2

CF_BITMAP 可能是与您的位图一起使用的错误格式。CF_BITMAP 剪贴板格式指定设备位图,但如今几乎所有位图都是 DIB - 与设备无关的位图。设备位图与系统/硬件设备调色板相关(想想 EGA 图形),并且必须匹配当前显示模式的像素格式。DIB 带有自己的颜色信息,其像素格式与显示模式无关。

文档说,如果应用程序在从剪贴板读取时请求 CF_DIB,剪贴板管理器会将 CF_BITMAP 转换为 CF_DIB,但这假定原始图像实际上是当前显示模式像素格式的设备位图。如果不是,则转换将产生垃圾,因为输入是垃圾。

再次尝试使用 CF_DIB 而不是 CF_BITMAP。

于 2012-08-28T16:40:45.483 回答
2

我认为你过于复杂了。根本不需要 p/invoke —— 框架已经为你处理好了。您可以以单行方式执行此操作:

Clipboard.SetImage(bmp);
于 2012-08-28T19:21:01.173 回答