我们看到一个间歇性问题,在 Windows XP 下使用位图作为背景的所有者绘制的按钮显示位图不正确。将显示包含多个按钮的窗口,这些按钮对用于按钮背景的位图图像使用相同的位图文件,并且大多数按钮将是正确的,尽管在某些情况下可能有一个或两个按钮显示位图背景减少到较小的尺寸。
如果您退出应用程序然后重新启动它,您可能会看到按钮上图标显示不正确的相同行为,但它可能与以前的按钮相同,也可能不同。这种在按钮上不正确显示图标的行为也并非总是可见的。有时它显示,有时它不显示。因为一旦我们为按钮加载了一个图标,我们就保留它,一旦按钮显示不正确,它总是会显示不正确。
使用调试器,我们终于发现似乎正在发生的事情是,当GetObject()
调用函数时,返回的位图大小数据有时不正确。例如,在一种情况下,位图是 75x75 像素,而返回的大小GetObject()
是 13x13。由于这个尺寸被用作位图绘制的一部分,所以显示的背景成为按钮窗口上的一个小装饰。
实际源区如下。
if (!hBitmapFocus) {
CString iconPath;
iconPath.Format(ICON_FILES_DIR_FORMAT, m_Icon);
hBitmapFocus = (HBITMAP)LoadImage(NULL, iconPath, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
}
if (hBitmapFocus) {
BITMAP bitmap;
int iNoBytes = GetObject(hBitmapFocus, sizeof(BITMAP), &bitmap);
if (iNoBytes < 1) {
char xBuff[128];
sprintf (xBuff, "GetObject() failed. GetLastError = %d", GetLastError ());
NHPOS_ASSERT_TEXT((iNoBytes > 0), xBuff);
}
cxSource = bitmap.bmWidth;
cySource = bitmap.bmHeight;
//Bitmaps cannot be drawn directly to the screen so a
//compatible memory DC is created to draw to, then the image is
//transfered to the screen
CDC hdcMem;
hdcMem.CreateCompatibleDC(pDC);
HGDIOBJ hpOldObject = hdcMem.SelectObject(hBitmapFocus);
int xPos;
int yPos;
//The Horizontal and Vertical Alignment
//For Images
//Are set in the Layout Manager
//the proper attribute will have to be checked against
//for now the Image is centered on the button
//Horizontal Alignment
if(btnAttributes.horIconAlignment == IconAlignmentHLeft){//Image to left
xPos = 2;
}else if(btnAttributes.horIconAlignment == IconAlignmentHRight){//Image to right
xPos = myRect.right - cxSource - 5;
}else {//Horizontal center
xPos = ((myRect.right - cxSource) / 2) - 1;
}
//Vertical Alignment
if(btnAttributes.vertIconAlignment == IconAlignmentVTop){//Image to top
yPos = 2;
}else if(btnAttributes.vertIconAlignment == IconAlignmentVBottom){//Image to bottom
yPos = myRect.bottom - cySource - 5;
}else{//Vertical Center
yPos = ((myRect.bottom - cySource) / 2) - 1;
}
pDC->BitBlt(xPos, yPos, cxSource, cySource, &hdcMem, 0, 0, SRCCOPY);
hdcMem.SelectObject(hpOldObject);
}
使用调试器,我们可以看到iconPath
字符串是正确的,并且加载的位图hBitmapFocus
不是 NULL。接下来我们可以看到调用GetObject()
了 并且返回的值iNoBytes
等于 24。对于那些正确显示值bitmap.bmWidth
并且正确的按钮,bitmap.bmHeight
但是对于那些不正确的按钮,值太小导致绘制时的大小不正确位图。
该变量在类头中定义为
HBITMAP hBitmapFocus;
作为对此进行研究的一部分,我发现了这个堆栈溢出问题,GetObject 返回奇怪的大小,我想知道这里是否存在某种对齐问题。
bitmap
调用中使用的变量是否GetObject()
需要位于某种对齐边界上?当我们对一些数据使用打包时,我们使用pragma
指令仅指定包含文件中需要打包在一个字节边界上的特定结构的代码的特定部分。