用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,还是本来就不能这么搞?
...全文
348 9 打赏 收藏 转发到动态 举报
写回复
用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吧,没这么弱的
具体没弄过,顶一个
VB 做的相册(缩略图预览程序) VB做的小型相册,实际上是一个图片浏览程序,打开时显示缩略图,鼠标点击显示大图片,并可接着浏览下去,程序相关说明:   函数功能: 该函数将指定位图的位拷贝到缓冲区里?   函数原型:LONG GetBitmapBits(HBITMAP hbmp, LONG cbBuffer, LPVOID lpvBits);   参数:   hbmp:指向感兴趣的位图的句柄?   cbBuffer:指定要从位图拷贝到缓冲区的字节数?   lpvBits:指向接收位图位数据的缓冲区指针?这些位是按字节类型存储在数组中的?   返回值:如果该函数执行成功,那么返回值就是拷贝到缓冲区的字节数;如果该函数执行失败,那么返回值为0。   Declare Function GetBitmapBits Lib "gdi32" (ByVal hBitmap As Long, ByVal nwCount As Long, lpBits As Any) As Long      函数功能:该函数将位图的颜色数据位设置成指定值?   函数原型:LONG SetBitmapBits(HBITMAP hmbp, DWORD cBytes, CONST VOID (lpBits);   参数:   hbmp:指向要设置的位图的句柄?   cBytes:指定参数lpBits指向的数组的字节数?   lpBits:指向字节类型数组的指针?该数组中包含了指定位图的颜色数据?   返回值:如果该函数执行成功,则返回值就是在设置位图位时使用的字节数;如果失败,则返回值为0。      函数功能:该函数得到指定图形对象的信息,根据图形对象,函数把填满的或结构,或表项(用于逻辑调色板)数目放入一个指定的缓冲区。   函数原型:int GetObject(HGDIOBJ hgdiobj, int cbBuffer, LPVOID lpvObject);   参数:   hgdiobj:指向感兴趣的图形对象的句柄,它可以是这样的一个句柄:一个逻辑位图、一个刷子、一种字体、一个调色板、笔或通过调用CreateDIBsection函数创建的与设备无关位图。   cbBuffer:指定将要写到缓冲区的信息的字节数目?‘lpvObject:指向一个缓冲区的指针,该缓冲区将要检索指定图形对象的信息。      函数功能描述:将一块内存的数据从一个位置复制到另一个位置   函数原型:VOID CopyMemory(PVOID Destination,CONST VOID *Source,DWORD Length);   参数:   Destination:要复制内存块的目的地址?   Source:要复制内存块的源地址?   Length:指定要复制内存块的大小,单位为字节   返回值:该函数为VOID型,没有返回值。
Snapshot526控件 授权后抓拍到的图片以时间为基准自动命令,未授权再无法抓拍图片。 保存的图片格式为bmp格式。 包含包“Snapshot526.h” 并在stdafx.h中或调用的模块中加入 #pragma comment(lib, "Camera526.lib") 然后在操作开始摄像头抓拍操作事件中 CSnapshot526 snapshot; CString strFileName=L"",strFilePath; snapshot.SetGrantUserName(L"用户名"); //设置授权用户 snapshot.SetGrantUserKey(L"授权号"); //设置授权号 snapshot.SetCameraWindowSize(520,460); //设置视频窗口大小 snapshot.SetSaveImagePath(L"debug"); //设置抓拍图片保存路径 if(snapshot.ShowCameraDlg()) { strFileName = snapshot.GetPhotoFileName(); //获取抓拍图片文件名 SetDlgItemText(IDC_STNAME,strFileName); strFilePath = snapshot.GetPhotoFilePath(); //获取图片路径 if(!strFilePath.IsEmpty()) { //显示抓拍到的图片 HDC hSrcDC; HDC hDesDC; HBITMAP hBitmap; BITMAP bm; CRect rect; Sleep(100); hDesDC = m_stPicture.GetDC()->m_hDC; hSrcDC = CreateCompatibleDC(hDesDC); hBitmap=(HBITMAP)LoadImage(AfxGetInstanceHandle(), strFilePath, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE|LR_CREATEDIBSECTION); //m_stPicture.SetBitmap(hBitmap); GetObject(hBitmap, sizeof(BITMAP), &bm); SelectObject(hSrcDC, hBitmap); m_stPicture.GetClientRect(&rect); ::SetStretchBltMode(hDesDC, COLORONCOLOR); ::StretchBlt(hDesDC, rect.left, rect.top, rect.right, rect.bottom, hSrcDC, 0, 0, bm.bmWidth, bm.bmHeight,+SRCCOPY); m_stPicture.InvalidateRect(rect); } } 注意,需要把文件Snapshot526.h拷到工程中并加入,另需要Camera526.dll和Camera526.lib文件。 具体查看示例
////绘制底面路径imagePath 和 相框路径framePicPath void PaintFramePicture(HDC hDC,RECT rc,CString imagePath,CString framePicPath) { CDC *pDC=new CDC; pDC->Attach(hDC); CString bmpFile; HBITMAP hFgBmp; //画顶层透明位图 CDC DCImage, DCMask; CBitmap Bmp2; //Bmp2.LoadBitmap(IDB_BITMAP2); bmpFile=framePicPath; ///表层框架,相框 hFgBmp = (HBITMAP) LoadImage(NULL,bmpFile,IMAGE_BITMAP,0,0,LR_LOADFROMFILE|LR_DEFAULTSIZE|LR_CREATEDIBSECTION); Bmp2.Attach(hFgBmp); BITMAP bm; Bmp2.GetBitmap(&bm); int nWidth=bm.bmWidth,nHeight=bm.bmHeight; bmpFile=imagePath;//画底层位图//底层内容 CBitmap Bmp1; hFgBmp = (HBITMAP) LoadImage(NULL,bmpFile,IMAGE_BITMAP,0,0,LR_LOADFROMFILE|LR_DEFAULTSIZE|LR_CREATEDIBSECTION); Bmp1.Attach(hFgBmp); CDC memDC; memDC.CreateCompatibleDC(pDC); memDC.SelectObject(&Bmp1); pDC->BitBlt(0,0,nWidth,nHeight,&memDC,0,0,SRCCOPY); DCImage.CreateCompatibleDC(pDC); DCMask.CreateCompatibleDC(pDC); //把图像装入image DC DCImage.SelectObject(&Bmp2); //为“掩码”位图创建一个单色bitmap CBitmap BmpMask; //把mask位图装入mask DC BmpMask.CreateBitmap(nWidth, nHeight, 1, 1, NULL); //用透明色创建“掩码”位图 DCMask.SelectObject(&BmpMask); //设置透明色 DCImage.SetBkColor(RGB(0,0,0)); DCMask.BitBlt(0, 0, nWidth, nHeight, &DCImage, 0, 0, SRCCOPY); pDC->BitBlt(0,0, nWidth, nHeight, &DCImage, 0, 0, SRCINVERT); pDC->BitBlt(0,0, nWidth, nHeight, &DCMask, 0, 0, SRCAND); pDC->BitBlt(0,0, nWidth, nHeight, &DCImage, 0, 0, SRCINVERT); delete pDC; }

16,472

社区成员

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

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

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