【问题标题】:CreateDIBSection leaving 'Not enough storage' error, but seems to still work anywayCreateDIBSection 留下“存储空间不足”错误,但似乎仍然有效
【发布时间】:2010-03-11 03:28:47
【问题描述】:

每当我的应用程序尝试通过调用 CreateDIBSection() 或使用 LR_CREATEDIBSECTION 标志调用 LoadImage() 来创建 DIB 部分时,它似乎都会成功返回。它返回的HBITMAP 是有效的,我可以很好地操作和显示它。

但是,对 GetLastError() 的调用将返回 8: Not enough storage is available to process this command. 从第一次调用到最后一次调用都会发生这种情况。请求的位图大小似乎无关紧要; 800x600 或 16x16,结果相同。在函数调用之前,GetLastError() 没有返回错误;另外,在函数调用之前调用 SetLastError(0) 的结果是一样的。

我发现其他人也问过类似的问题,但事实证明他们正在使用 CreateCompatibleBitmap() 并且当他们切换到 CreateDIBSection() 时问题就消失了,或者他们已经在使用 CreateDIBSection() 并且它返回的结果是无效,所以根本不工作。

由于一切似乎正常,我认为我可以忽略它(并在调用任一函数后调用 SetLastError(0)),但这样做可能会忽略一些微妙的问题。

当然,这是我正在使用的一些基本代码。首先是对 LoadImage() 的调用,它是基本位图类的一部分,我用于很多事情,我对其进行了相当多的简化以显示更相关的方面:

bool Bitmap::Load( const char* szBitmapName, /*...*/ )
{
   m_hBitmap = (HBITMAP)LoadImage( GetModuleHandle( NULL ), szBitmapName,
            IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_LOADFROMFILE );
   //...
}
// ...
Bitmap::~Bitmap()
{
   if( m_hBitmap ) DeleteObject( m_hBitmap );
}
bool Bitmap::Draw( HDC hDC, int iDstX, int iDstY, int iDstWidth,
                   int iDstHeight, int iSrcX, int iSrcY, int iSrcWidth,
                   int iSrcHeight, bool bUseMask ) const
{
   HDC hdcMem = CreateCompatibleDC( hDC );
   if( hdcMem == NULL ) return false;
   HBITMAP hOld = (HBITMAP)SelectObject( hdcMem, m_hBitmap );
   BLENDFUNCTION blendFunc;
   blendFunc.BlendOp = AC_SRC_OVER;
   blendFunc.BlendFlags = 0;
   blendFunc.AlphaFormat = AC_SRC_ALPHA;
   blendFunc.SourceConstantAlpha = 255;
   AlphaBlend( hDC, iDstX, iDstY, iDstWidth, iDstHeight, hdcMem, iSrcX,
               iSrcY, iSrcWidth, iSrcHeight, blendFunc );
   SelectObject( hdcMem, hOld );
   DeleteDC( hdcMem );
}

对 CreateDIBSection 的调用通常在更新分层窗口时完成:

HDC hDCScreen( GetDC(0) );
POINT tSourcePos = { 0, 0 };
HDC hDCSource( CreateCompatibleDC( hDCScreen ) );
// iWidth and iHeight are used both for the bitmap size and window size
// to keep this example simpler
BITMAPINFO bi32 = {0};
bi32.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bi32.bmiHeader.biWidth = iWidth;
bi32.bmiHeader.biHeight = iHeight;
bi32.bmiHeader.biPlanes = 1;
bi32.bmiHeader.biBitCount = 32;
bi32.bmiHeader.biCompression = BI_RGB;
void* pBits = NULL;
HBITMAP hBitmap = CreateDIBSection(NULL, &bi32, DIB_RGB_COLORS,
                  (void**)&pBits, NULL, NULL);

HBITMAP hOldBitmap = (HBITMAP)SelectObject( hDCSource, hBitmap );
POINT tWindowPos = { 0, 0 };
SIZE tWindowSize = { iWidth, iHeight };
BLENDFUNCTION blendFunction = {0};
blendFunction.BlendOp = AC_SRC_OVER;
blendFunction.SourceConstantAlpha = 255;
blendFunction.AlphaFormat = AC_SRC_ALPHA;
DWORD iFlags( ULW_ALPHA );

// m_tBitmap is an instance of Bitmap class previously mentioned
m_tBitmap.Draw( hDCSource, 0, 0, iWidth, iHeight, 0, 0, iWidth, iHeight );
UpdateLayeredWindow( GetHandle(), hDCScreen, &tWindowPos, &tWindowSize,
                     hDCSource, &tSourcePos, 0, &blendFunction, iFlags );
SelectObject( hDCSource, hOldBitmap );
DeleteObject( hBitmap );
DeleteDC( hDCSource );
ReleaseDC( 0, hDCScreen );

任何关于我完全不了解的事情的指针都将不胜感激。

【问题讨论】:

    标签: c++ windows bitmap dib createdibsection


    【解决方案1】:

    我认为您没有遵循文档所说的内容(来自CreateDIBSection):

    如果函数成功,则返回 value 是新创建的句柄 DIB,*ppvBits 指向位图 位值。

    如果函数失败,返回 值为NULL*ppvBitsNULL

    此函数可以返回以下值。 [...]

    如果返回值不是NULL,则函数成功。调用GetLastError 不一定会返回任何关于成功的可靠有意义的信息(来自GetLastError):

    如果函数没有记录到 设置最后一个错误代码,值 这个函数返回的很简单 最近的最后一个错误代码 已设置;一些功能设置 成功时最后一个错误代码为 0 并且 其他人没有。

    【讨论】:

    • 通过对 NULL 结果的代码检查,从 CreateDIBSection() 和 ppvBits 返回的 HBITMAP 始终为非 NULL(我已经删除了很多类似的额外代码)。在调用 CreateDIBSection(); 之前我已经清除了错误代码;无论错误代码处于什么状态,它总是来自代码 8 的调用。
    • @Doug,阅读GetLastError 的文档,特别是:“一些函数在成功时将最后错误代码设置为 0,而其他函数则没有。”
    • 好吧,我假设它可能是相关的,有点像“警告”类型的错误,但我发现它只在调用者定义的失败结果的上下文中相关。潜在地,在 CreateDIBSection 中调用的某些函数可能会翻转错误位,在这种情况下,这不是问题。这不像是一个未经处理的异常冒泡。
    【解决方案2】:

    那又怎样? CreateDIBSection 是一个复杂的函数,它利用许多其他 Windows API 来完成它的工作。一些那些 API 可以设置最后一个错误来反映它们的 内部状态。 CreateDIBSection 不会清除错误,只是为了在不失败时返回 0。

    合约说,当它失败时,GetLastError 被设置为一个有意义的值:它没有说当 CreateDIBSection 确实返回时,最后一个错误值对调用者有任何意义。

    如果内存不足,很可能会引发异常和/或为了简化代码,最后一个错误值会被抢先设置在分配的顶部附近,以便无需进一步努力即可正确设置如果分配失败或抛出异常。

    【讨论】:

      【解决方案3】:

      我记得在某些情况下,为了从GetLastError 获得可靠的值,您必须在调用任何 api 函数之前调用SetLastError(0),然后您会得到正确的错误with GetLastError()。因为万一它成功了,它就不会被更新。

      【讨论】:

      • 我试过了,调用后它仍然设置为错误 8。
      猜你喜欢
      • 2015-09-10
      • 2013-10-27
      • 2016-12-29
      • 1970-01-01
      • 1970-01-01
      • 2015-06-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多