迷死你不赔命---GetDIBits()的陷阱

GetDIBits()存在一个小陷阱,我中招了!希望本文可以帮助踩进去的朋友:)

 

近日写程序时因要处理位图,所以使用了GetDIBits()这个函数。但在使用过程中,总是抛出异常,提示内存读写错误。

 

代码如下:

BITMAPINFO Bmi;

HDC hBmpDC = ::GetDC(NULL);

Bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);

BOOL FgRetVal = FALSE;

if (::GetDIBits(hBmpDC,hBmp,0,0,NULL,&Bmi,DIB_RGB_COLORS))   // 第一次调用,获取位图信息

{

     BYTE *pTempBits =new BYTE [Bmi.bmiHeader.biSizeImage];   // DIB数据的大小分配内存

     if(pTempBits)

     {

         // 第二次调用,获取位图数据

         if (::GetDIBits(hBmpDC, hBmp, 0, (WORD)Bmi.bmiHeader.biHeight, pTempBits, &Bmi, DIB_RGB_COLORS))

         {

              FgRetVal = TRUE;

         }

     }

}

 

反复检查都未能找到出错原因。在检查时还发现,如果打开的是24bits位图或单色图,程序就不会出错,但如果是16色、256色的位图就会异常。

 

在网上查找相关信息时发现有人也曾经出现过同样问题,但最后也不了了之,没有明确的提示说明问题究竟出在哪。

后来将我的代码与网上找到的调试正常的代码再仔细对比,这时终于发现有个可疑之处:

在我的代码中,第二次调用GetDIBits()前所申请的内存,只考虑了DIB数据的大小,未考虑BITMAPINFOCOLOR TABLE的空间(因为前面已有专门的变量存放这些信息);

而正常的代码,第二次调用GetDIBits()前所申请的内存空间,包括了BITMAPINFOCOLOR TABLE以及实际DIB数据的内容(将前面获得的BITMAPINFOCOLOR TABLE都拷贝到此空间)。

 

我郁闷啦,难道是这里出的问题?可是这样的话,函数为什么要把这些信息的地址分开两个参数来传送呢?

然后在微软的支持中心找到一篇文章,基本证实了这点http://support.microsoft.com/kb/80080/en-us

(这篇文章里讲了使用时的步骤,早点看见就好了。。。)

 

以下是更改后的代码。

BITMAPINFO Bmi;

HDC hBmpDC = ::GetDC(NULL);

Bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);

BOOL FgRetVal = FALSE;

if (::GetDIBits(hBmpDC,hBmp,0,0,NULL,&Bmi,DIB_RGB_COLORS))   // 第一次调用,获取位图信息

{

DWORD InfoSize = 0;

     InfoSize = Bmi.bmiHeader.biSize + Bmi.bmiHeader.biClrUsed * sizeof(RGBQUAD);   // 位图信息及调色板大小

// 分配空间大小须包括位图信息、调色板、位图数据

     BYTE *pTempBits = new BYTE [Bmi.bmiHeader.biSizeImage + InfoSize];  

     if(pTempBits)

     {

         memcpy(pTempBits,&Bmi,InfoSize); // 将位图信息及调色板大小拷贝至新的内存空间

         if (::GetDIBits(hBmpDC, hBmp, 0, Bmi.bmiHeader.biHeight, pTempBits+InfoSize, (LPBITMAPINFO)pTempBits,

DIB_RGB_COLORS))

         {

              FgRetVal = TRUE;

         }

     }

}

 

不过对于确切的原因我还是不太清楚,估计是因为第二次调用GetDIBits()时,对参数LPVOID lpvBits前的内容进行了操作(因打开24色位图时正常,所以可能是对COLOR TABLE的操作),希望看见这篇文章且又清楚原因的高手能指点一下!

 

微软也太不厚道了,对于调用这个函数,参数传递要注意的基本问题,居然不在MSDN中说清楚,害得我瞎折腾了几天~ ~

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值