来自LoadImage()的位图句柄上的GetObject()有时会返回不正确的位图大小

时间:2012-12-17 21:01:48

标签: windows winapi visual-c++ mfc

我们看到一个间歇性的问题,在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.bmWidthbitmap.bmHeight中的值是正确的但是对于那些没有这些值的人来说,这些值太小会导致在绘制位图时尺寸不正确。

变量在类标题中定义为

HBITMAP hBitmapFocus;

作为对此进行研究的一部分,我发现了stack overflow question, GetObject returns strange size,我想知道这里是否存在某种对齐问题。

bitmap调用中使用的GetObject()变量是否需要在某种对齐边界上?虽然我们正在使用packed来处理我们的一些数据,但我们使用pragma指令仅指定包含需要在一个字节边界上打包的包含文件中的特定结构的特定代码部分。

1 个答案:

答案 0 :(得分:0)

请阅读this Microsoft KB如何使用调色板信息加载位图。它也有一个很好的例子。

旁注:我没有在你的代码中看到调用:: DeleteObject(hBitmapFocus)的任何地方。调用它非常重要,因为你可以很快耗尽GDI对象。

使用Windows任务管理器查看您的程序不会耗尽GDI资源总是一个好主意。只需将“GDI对象”列添加到任务管理器,并查看应用程序中对象的数量不会不断增加,但保持在预期范围内,类似于其他程序

相关问题