代码之家  ›  专栏  ›  技术社区  ›  Doug Kavendek

CreateDibSection离开“存储不足”错误,但似乎仍然有效

  •  0
  • Doug Kavendek  · 技术社区  · 15 年前

    每当我的应用程序尝试创建DIB部分时,可以通过调用CreatedIBSection()或通过使用 LR_CREATEDIBSECTION 旗子,似乎返回成功。这个 HBITMAP 它返回的是有效的,我可以很好地操作和显示它。

    但是,对getLastError()的调用将返回 8: Not enough storage is available to process this command. 这是从第一个呼叫到最后一个呼叫。请求的位图的大小似乎无关紧要;800x600或16x16,结果相同。在函数调用之前,getLastError()不会返回任何错误;此外,在函数调用之前调用setLastError(0)也会产生相同的结果。

    我发现其他人也在问类似的问题,但结果要么是他们正在使用createCompatibleBitmap(),当他们切换到createdBibSection()时问题就消失了,要么是他们已经在使用createdBibSection(),并且返回的结果无效,因此根本不起作用。

    因为事情看起来是可行的,我认为我可以忽略它(在调用任何函数之后调用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 回复  |  直到 15 年前
        1
  •  3
  •   MSN    15 年前

    我认为你没有遵守文件上的规定 CreateDIBSection ):

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

    如果函数失败,返回 值是 NULL *PPV比特 无效的 .

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

    如果返回值不是 无效的 ,函数成功。打电话 GetLastError 不一定会返回任何有意义的成功信息(从 GetLastError ):

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

        2
  •  1
  •   Chris Becke    15 年前

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

    契约说,当失败时,getLastError被设置为一个有意义的值:当createdBisection返回时,它不说最后一个错误值对调用方有任何意义。

    很有可能,如果内存不足,就会引发异常和/或简化代码,最后一个错误值只会被预先设置在分配的顶部附近,这样在分配失败或引发异常时,就可以无需进一步努力就正确设置。

        3
  •  0
  •   Ismael Philip Pryde    15 年前

    我记得在某些情况下,为了从 GetLastError 你得打电话 SetLastError(0) 在调用任何API函数之前,稍后会得到正确的错误 with GetLastError() . 因为在成功的情况下,它没有被更新。