CreateDIBSection留下“没有足够的存储空间”错误,但似乎仍然有用

时间:2010-03-10 16:53:15

标签: c++ windows bitmap dib createdibsection

每当我的应用尝试创建DIB部分时,无论是通过调用CreateDIBSection(),还是通过使用LR_CREATEDIBSECTION标志调用LoadImage(),它似乎都会成功返回。它返回的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 );

任何关于我完全偏离基础的事情都会受到赞赏。

3 个答案:

答案 0 :(得分:3)

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

  

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

     

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

     

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

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

  

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

答案 1 :(得分:1)

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

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

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

答案 2 :(得分:0)

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