原因1:
去年开始处理图像时到现在一直有这样一个问题:如果打开一幅位24真彩色图像,进行各种处理,都没有问题,但如果不是真彩色图像,如黑白图、灰度图或伪彩色图,那么只能处理一次,再进行任何一种处理时都会弹出对话框提示:Debug Assertion Failed! File:wingdi.cpp Line:1120 For information on how your program can cause an assertion failure,see the Visual C++ documentation on asserts.
然后,我打开wingdi.cpp,定位到1120行,内容如下:
BOOL CGdiObject::Attach(HGDIOBJ hObject)
{
ASSERT(m_hObject == NULL); // only attach once, detach on destroy 1120行
if (hObject == NULL) return FALSE;
CHandleMap* pMap = afxMapHGDIOBJ(TRUE); // create map if not exist
ASSERT(pMap != NULL);
pMap->SetPermanent(m_hObject = hObject, this);
return TRUE;
}
HGDIOBJ CGdiObject::Detach()
{
HGDIOBJ hObject = m_hObject;
if (hObject != NULL)
{
CHandleMap* pMap = afxMapHGDIOBJ(); // don't create if not exist
if (pMap != NULL) pMap->RemoveHandle(m_hObject);
}
m_hObject = NULL;
return hObject;
}
我调试运G行时,打开调用堆栈,显示部分代码如下:
CGdiObject::Attach(void * 0x6f081467) line 1120 + 28 bytes
CPalette::CreatePalette(tagLOPALETTE * 0x0013f62c) line 431 + 26 bytes
CImageView2::CreateBitmapPalette(CDibImage * 0x00034d10 {CDibImage}) line 151
CImageView2::OnDraw(CDC * 0x0013fac8 {CPaintDC hWnd=0x00010b2e}) line 95 + 15 bytes
选中某一条,定位到各个函数,函数内容及定位的行如下:
void CImageView2::OnDraw(CDC* pDC)
{
CImageDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if( pDoc->statedoc==1 && state2==1 )
{
BYTE* pBitmapData = CDibNew1->GetData();
LPBITMAPINFO pBitmapInfo = CDibNew1->GetInfo();
int m_scale=1;
int bitmapHeight = CDibNew1->GetHeight();
int bitmapWidth = CDibNew1->GetWidth();
int scaledWidth = (int)(bitmapWidth * m_scale);
int scaledHeight = (int)(bitmapHeight * m_scale);
if (CDibNew1->GetRGB()) // Has a color table
{
CPalette * hPalette2=CreateBitmapPalette(CDibNew1);
CPalette * hOldPalette = pDC->SelectPalette(hPalette2, true);
pDC->RealizePalette();
::StretchDIBits(pDC->GetSafeHdc(),0, 0, scaledWidth, scaledHeight,
0, 0, bitmapWidth, bitmapHeight,
pBitmapData, pBitmapInfo,
DIB_RGB_COLORS, SRCCOPY);
pDC->SelectPalette(hOldPalette, true);
::DeleteObject(hPalette2);
}
else
{
StretchDIBits(pDC->GetSafeHdc(), 0, 0, scaledWidth, scaledHeight,
0, 0, bitmapWidth, bitmapHeight, pBitmapData, pBitmapInfo,
DIB_RGB_COLORS, SRCCOPY);
}
}
}
CPalette *CImageView2::CreateBitmapPalette(CDibImage *pBitmap)
{
CPalette hPalette;
struct
{
WORD Version;
WORD NumberOfEntries;
PALETTEENTRY aEntries[256];
} palette = { 0x300, 256 };
LPRGBQUAD pRGBTable = pBitmap->GetRGB();
UINT numberOfColors = pBitmap->GetNumberOfColors();
for(UINT x=0; x<numberOfColors; ++x)
{
palette.aEntries[x].peRed = pRGBTable[x].rgbRed;
palette.aEntries[x].peGreen = pRGBTable[x].rgbGreen;
palette.aEntries[x].peBlue = pRGBTable[x].rgbBlue;
palette.aEntries[x].peFlags = 0;
}
hPalette.CreatePalette((LPLOGPALETTE)&palette);
return &hPalette;
::DeleteObject(hPalette);
}
_AFXWIN_INLINE BOOL CPalette::CreatePalette(LPLOGPALETTE lpLogPalette)
{ return Attach(::CreatePalette(lpLogPalette)); }
通过红字部分的提示和我自己的分析,发现hPalette是全局变量,因为 // only attach once, detach on destroy ,所以在程序运行期间第一次处理时attach了,没有出错,第二次处理时,又要attach,但第一次处理完后还没有detach
,因为它是全局变量,程序结束时才销毁,也就是程序结束时才detach。所以,这样分析,问题就解决了,将hPalette设为局部变量,进入函数后,attach,走出函数时,变量销毁,便dettach。绿色代码是新加的。
原因2:
是由于字体设置的方式有问题,下边没有被注释掉的是正确的设置方式。
// NONCLIENTMETRICS ncm;
// memset(&ncm, 0, sizeof(NONCLIENTMETRICS));
// ncm.cbSize = sizeof(NONCLIENTMETRICS);
//
// VERIFY(::SystemParametersInfo(SPI_GETNONCLIENTMETRICS,
// sizeof(NONCLIENTMETRICS), &ncm, 0));
// ncm.lfMessageFont.lfWeight = 500;
// m_headerCtrl.m_HeaderFont.CreateFontIndirect(&ncm.lfMessageFont);
// SetFont(&(m_headerCtrl.m_HeaderFont));
//////////////////////////////////////////////////////////////////////////
CFont m_font;
LOGFONT lf; // Used to create the CFont.
memset(&lf, 0, sizeof(LOGFONT)); // Clear out structure.
lf.lfWeight = 500; // Request a 20-pixel-high font
lf.lfHeight = 15;
strcpy(lf.lfFaceName, "宋体"); // with face name "Arial".
m_font.CreateFontIndirect(&lf); // Create the font.
// Use the font to paint a control. This code assumes
// a control named IDC_TEXT1 in the dialog box.
SetFont(&m_font);