用CreateDIBSection创建的HBITMAP进行OleDuplicateData复制出来的HBITMAP有问题?

w_anthony 2010-01-08 04:29:35

#include <stdio.h>
#include <stdlib.h>
#include <tchar.h>
#include <windows.h>

#define WHSIZE 32

int _tmain(int, char**)
{
BITMAPINFOHEADER bih = {0}; //生成位图信息头
bih.biSize = sizeof(bih);
bih.biBitCount = 24;
bih.biWidth = bih.biHeight = WHSIZE;
bih.biPlanes = 1;
bih.biSizeImage = bih.biWidth * 3 * bih.biHeight;
void* lpBits = NULL;
HBITMAP hBitmap = CreateDIBSection(NULL, (BITMAPINFO*)&bih, DIB_RGB_COLORS, &lpBits, NULL, 0);
if (hBitmap != NULL)
{ //用CreateDIBSection创建HBITMAP
for (int i = 0; i < bih.biHeight; i++) //生成一个渐变位图
memset(((char*)lpBits) + i * bih.biWidth * 3, 0xFF * i / (bih.biHeight - 1), bih.biWidth * 3);
BITMAPFILEHEADER bfh = {0}; //生成文件头
bfh.bfType = 'MB';
bfh.bfOffBits = sizeof(bfh) + sizeof(bih);
bfh.bfSize = bfh.bfOffBits + bih.biSizeImage;
{ //写文件
HANDLE hFile = CreateFile(_T("E:\\a.bmp"), GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL);
if (hFile)
{
DWORD dwUseless = 0;
WriteFile(hFile, &bfh, sizeof(bfh), &dwUseless, NULL);
WriteFile(hFile, &bih, sizeof(bih), &dwUseless, NULL);
WriteFile(hFile, lpBits, bih.biSizeImage, &dwUseless, NULL);
CloseHandle(hFile);
printf("%s", "Write a.bmp succeeded!\r\n");
}
}
HBITMAP hBitmap2 = (HBITMAP)OleDuplicateData(hBitmap, CF_BITMAP, 0); //用下面的CopyImage就没问题,或者源是LoadImage出来的也没问题
//HBITMAP hBitmap2 = (HBITMAP)CopyImage(hBitmap, IMAGE_BITMAP, 0, 0, 0);
if (hBitmap2)
{
HDC hdc = GetDC(NULL);
if (hdc != NULL)
{
char chBits[WHSIZE * 3 * WHSIZE];
if (GetDIBits(hdc, hBitmap2, 0, bih.biHeight, chBits, (BITMAPINFO*)&bih, DIB_RGB_COLORS) != 0)
{
HANDLE hFile = CreateFile(_T("E:\\b.bmp"), GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL);
if (hFile)
{
DWORD dwUseless = 0;
WriteFile(hFile, &bfh, sizeof(bfh), &dwUseless, NULL);
WriteFile(hFile, &bih, sizeof(bih), &dwUseless, NULL);
WriteFile(hFile, chBits, bih.biSizeImage, &dwUseless, NULL);
CloseHandle(hFile);
printf("%s", "Write b.bmp succeeded!\r\n");
}
}
ReleaseDC(NULL, hdc);
}
DeleteObject(hBitmap2);
}
DeleteObject(hBitmap);
}
system("PAUSE");
return 0;
}


用CreateDIBSection创建的HBITMAP进行OleDuplicateData复制出来的HBITMAP有问题,在一些地方会显示黑屏,一些地方直接返回失败。于是写了上面这段代码作测试,结果就是GetDIBits返回0,取不到像素数据。
如果把OleDuplicateData换成CopyImage则执行成功,两个BMP都可以保存,或者如果源HBITMAP是LoadImage创建的,OleDuplicateData出来的HBITMAP也可以正常访问。
这是BUG,还是本来就不能这么搞?
...全文
373 9 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
w_anthony 2010-01-11
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 lambochan 的回复:]
引用 7 楼 w_anthony 的回复:
DIB不是不支持,比如LoadImage带LR_CREATEDIBSECTION或者CopyImage带LR_CREATEDIBSECTION,也都是可以的。
貌似只有 CreateDIBSection不行。。。


不知道你用什么方法test的,不过偶用LoadImage()带LR_CREATEDIBSECTION就不行,不带就可以..

C/C++ code
BOOL test()
{// 用LoadImage()函数test. HBITMAP hBmp1= ( HBITMAP )::LoadImage( NULL,"car.bmp"/* 24Bit BMP*/, IMAGE_BITMAP,0,0, LR_LOADFROMFILE| LR_CREATEDIBSECTION );


CMyDoc* pDoc= GetDocument();
ASSERT_VALID(pDoc);// 取Doc打开的原图 HBITMAP hBitmap= pDoc->GetBMP()->GetHBitmap();// 用LoadImage() load出来的复制一个新句柄 HBITMAP hBmp= ( HBITMAP )OleDuplicateData( hBmp1, CF_BITMAP,0 );if(!hBmp )
MessageBox("fail.." );

HDC hDC= ::GetDC( NULL );// 取来BitBlt() 复制的句柄 HDC hDrawDC= pDoc->GetBMP()->BeginDraw( hDC );// 用来选入dupe的句柄然后BitBlt() HDC hMemDC= CreateCompatibleDC( hDC );
HBITMAP hOld= ( HBITMAP )SelectObject( hMemDC, hBmp );
RECT rc;
rc.left= rc.top=0; rc.right= pDoc->GetBMP()->GetWidth();
rc.bottom= pDoc->GetBMP()->GetHeight();// 先刷白它 FillRect( hDrawDC,&rc, ( HBRUSH )GetStockObject( WHITE_BRUSH ) );// BitBlt() dupe来的句柄 BitBlt( hDrawDC,0,0, rc.right, rc.bottom, hMemDC,0,0, SRCCOPY );// 释放.... pDoc->GetBMP()->EndDraw();
SelectObject( hMemDC, hOld );
DeleteObject( hBmp );
::ReleaseDC( NULL, hDC );

Invalidate();
DeleteObject( hBmp1 );return1;// 注: 用来test的两幅图象画面是一样的(32bit/24bit),系统色深32bit.// 所以偶先Fill白再bitblt()}

如上,用laodimage() load出来后BitBlt()到doc打开的位图上..不带LR_CREATEDIBSECTION时没问题,带这个标志的话,就象代码那样..只有被fill白的底色, dupe来的句柄非空但....
那应该说明它只支持DDB.

BTW:如果当前系统色深是32Bit,而被dupe的位图(也就是LoadImage()load出来的)是32bit的话,用LR_CREATEDIBSECTION也没有问题,但这已经是兼容当前显示模式的位图了,可以说和DDB没分别.而偶用24bit的位图来做dupe的话,DIBSECTION就失败了,啥都没有只剩白色.  ( 那就更说明它只支持DDB了)
[/Quote]

你是对的!之前我LoadImage确实是读取了一个32位色深的图片测试,而CopyImage又是从LoadImage不带LR_CREATEDIBSECTION的源Copy出来的,这样色深也是32位。
OleDuplicateData可能只支持与系统色深相同的HBITMAP。辛苦这位老兄编码测试了……
lambochan 2010-01-10
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 w_anthony 的回复:]
DIB不是不支持,比如LoadImage带LR_CREATEDIBSECTION或者CopyImage带LR_CREATEDIBSECTION,也都是可以的。
貌似只有 CreateDIBSection不行。。。
[/Quote]

不知道你用什么方法test的,不过偶用LoadImage()带LR_CREATEDIBSECTION就不行,不带就可以..


BOOL test()
{
// 用LoadImage()函数test.
HBITMAP hBmp1 = ( HBITMAP )::LoadImage( NULL, "car.bmp"/* 24Bit BMP*/, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION );


CMyDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);

// 取Doc打开的原图
HBITMAP hBitmap = pDoc->GetBMP()->GetHBitmap();

// 用LoadImage() load出来的复制一个新句柄
HBITMAP hBmp = ( HBITMAP )OleDuplicateData( hBmp1, CF_BITMAP, 0 );
if( !hBmp )
MessageBox( "fail.." );

HDC hDC = ::GetDC( NULL );
// 取来BitBlt() 复制的句柄
HDC hDrawDC = pDoc->GetBMP()->BeginDraw( hDC );
// 用来选入dupe的句柄然后BitBlt()
HDC hMemDC = CreateCompatibleDC( hDC );
HBITMAP hOld = ( HBITMAP )SelectObject( hMemDC, hBmp );
RECT rc;
rc.left = rc.top = 0; rc.right = pDoc->GetBMP()->GetWidth();
rc.bottom = pDoc->GetBMP()->GetHeight();
// 先刷白它
FillRect( hDrawDC, &rc, ( HBRUSH )GetStockObject( WHITE_BRUSH ) );
// BitBlt() dupe来的句柄
BitBlt( hDrawDC, 0, 0, rc.right, rc.bottom, hMemDC, 0, 0, SRCCOPY );
// 释放....
pDoc->GetBMP()->EndDraw();
SelectObject( hMemDC, hOld );
DeleteObject( hBmp );
::ReleaseDC( NULL, hDC );

Invalidate();
DeleteObject( hBmp1 );
return 1;

// 注: 用来test的两幅图象画面是一样的(32bit/24bit),系统色深32bit.
// 所以偶先Fill白再bitblt()
}


如上,用laodimage() load出来后BitBlt()到doc打开的位图上..不带LR_CREATEDIBSECTION时没问题,带这个标志的话,就象代码那样..只有被fill白的底色, dupe来的句柄非空但....
那应该说明它只支持DDB.

BTW:如果当前系统色深是32Bit,而被dupe的位图(也就是LoadImage()load出来的)是32bit的话,用LR_CREATEDIBSECTION也没有问题,但这已经是兼容当前显示模式的位图了,可以说和DDB没分别.而偶用24bit的位图来做dupe的话,DIBSECTION就失败了,啥都没有只剩白色. ( 那就更说明它只支持DDB了)
w_anthony 2010-01-10
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 lambochan 的回复:]
引用 3 楼 w_anthony 的回复:
引用 2 楼 lambochan 的回复:
use CreateDIBitmap() or CreateCompatibleBitmap()....


确实用CreateDIBitmap创建的HBITMAP进行OleDuplicateData没有问题。不过为什么用CreateDIBSection就不行呢?这应该与是否指明了要使用DIB没有关系,因为LoadImage带LR_CREATEDIBSECTION参数创建的HBITMAP进行OleDuplicateData也没有问题。
而且最重要的是当HBITMAP作为一个你设计的函数的参数的时候,你根本不知道其他人是怎么创建它的,也不知道OleDuplicateData一下结果是否正确(因为即便是返回的HBITMAP有问题,它也不返回NULL),或许唯一个方法就是对OleDuplicateData出来的HBITMAP进行一次GetDIBits做认证,可惜这效率是不可接受的,还不如直接CopyImage。
难道CreateDIBSection出来的HBITMAP进行OleDuplicateData的结果真是一个BUG?



貌似只支持DDB的.
[/Quote]
DIB不是不支持,比如LoadImage带LR_CREATEDIBSECTION或者CopyImage带LR_CREATEDIBSECTION,也都是可以的。
貌似只有 CreateDIBSection不行。。。
w_anthony 2010-01-09
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 qimiao77 的回复:]
CreateDIBSection创建的PDIB为空,需要你把数据写到ppvBits,那样才有用.
[/Quote]

不知所云,没看到我已经写了吗?
贪玩的老鼠 2010-01-09
  • 打赏
  • 举报
回复
CreateDIBSection创建的PDIB为空,需要你把数据写到ppvBits,那样才有用.
lambochan 2010-01-09
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 w_anthony 的回复:]
引用 2 楼 lambochan 的回复:
use CreateDIBitmap() or CreateCompatibleBitmap()....


确实用CreateDIBitmap创建的HBITMAP进行OleDuplicateData没有问题。不过为什么用CreateDIBSection就不行呢?这应该与是否指明了要使用DIB没有关系,因为LoadImage带LR_CREATEDIBSECTION参数创建的HBITMAP进行OleDuplicateData也没有问题。
而且最重要的是当HBITMAP作为一个你设计的函数的参数的时候,你根本不知道其他人是怎么创建它的,也不知道OleDuplicateData一下结果是否正确(因为即便是返回的HBITMAP有问题,它也不返回NULL),或许唯一个方法就是对OleDuplicateData出来的HBITMAP进行一次GetDIBits做认证,可惜这效率是不可接受的,还不如直接CopyImage。
难道CreateDIBSection出来的HBITMAP进行OleDuplicateData的结果真是一个BUG?
[/Quote]


貌似只支持DDB的.
w_anthony 2010-01-08
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 lambochan 的回复:]
use CreateDIBitmap() or CreateCompatibleBitmap()....
[/Quote]

确实用CreateDIBitmap创建的HBITMAP进行OleDuplicateData没有问题。不过为什么用CreateDIBSection就不行呢?这应该与是否指明了要使用DIB没有关系,因为LoadImage带LR_CREATEDIBSECTION参数创建的HBITMAP进行OleDuplicateData也没有问题。
而且最重要的是当HBITMAP作为一个你设计的函数的参数的时候,你根本不知道其他人是怎么创建它的,也不知道OleDuplicateData一下结果是否正确(因为即便是返回的HBITMAP有问题,它也不返回NULL),或许唯一个方法就是对OleDuplicateData出来的HBITMAP进行一次GetDIBits做认证,可惜这效率是不可接受的,还不如直接CopyImage。
难道CreateDIBSection出来的HBITMAP进行OleDuplicateData的结果真是一个BUG?
lambochan 2010-01-08
  • 打赏
  • 举报
回复
use CreateDIBitmap() or CreateCompatibleBitmap()....
xwsn007 2010-01-08
  • 打赏
  • 举报
回复
应该不是bug吧,没这么弱的
具体没弄过,顶一个

16,548

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • AIGC Browser
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧