迷死你不赔命---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中说清楚,害得我瞎折腾了几天~ ~

你可能感兴趣的:(迷死你不赔命---GetDIBits()的陷阱)