CreateDIBSection で「ストレージが不足しています」エラーが発生しますが、それでも動作するようです

StackOverflow https://stackoverflow.com/questions/2418776

質問

アプリが DIB セクションを作成しようとするたびに、CreateDIBSection() を呼び出すか、LoadImage() を呼び出して、 LR_CREATEDIBSECTION フラグを立てたところ、正常に返されたようです。の HBITMAP 返される値は有効であり、問​​題なく操作して表示できます。

ただし、GetLastError() を呼び出すと返されます。 8: Not enough storage is available to process this command. これは最初の呼び出しから最後の呼び出しまで発生します。要求されたビットマップのサイズは重要ではないようです。800x600 または 16x16、同じ結果。関数呼び出しの直前に、GetLastError() はエラーを返しません。さらに、関数呼び出しの前に SetLastError(0) を呼び出しても同じ結果になります。

他の人も同様の質問をしているのを見つけましたが、その人が CreateSupportBitmap() を使用していることが判明し、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 );

私が完全に的外れな点についてのご指摘をいただければ幸いです。

役に立ちましたか?

解決

ドキュメントの内容に従っていないと思います(から) DIBSection の作成):

関数が成功した場合、返品値は新しく作成されたDIBのハンドルであり、 *ppvBits ビットマップビット値を指します。

関数が失敗した場合、返品値は次のとおりです NULL, 、 そして *ppvBitsNULL.

この関数は次の値を返すことができます。[...]

戻り値がそうでない場合 NULL, 、関数は成功しました。電話をかける GetLastError 成功に関して確実に意味のある情報が返されるとは限りません ( GetLastError):

関数が最後のエラーコードを設定するように文書化されていない場合、この関数によって返される値は、単に設定された最新の最後のエラーコードです。いくつかの関数は、成功して最後のエラーコードを0に設定し、他の関数はそうではありません。

他のヒント

だから何? CreateDIBSectionは、他の多くのWindowsのAPIの使用がその仕事を作る複雑な関数です。 のいくつかのものをのAPIは、の自分のの内部状態を反映するために、最後のエラーを設定することができます。 CreateDIBSectionがちょうど0を返すことができるように、それが失敗していない場合、エラーをクリアするつもりはないされます。

契約は、それが失敗した場合、GetLastError関数が意味のある値に設定されている、と言う:それは最後のエラー値がCreateDIBSectionが返さない呼び出し側に何らかの意味を持っていることを言っていません。

メモリーの不足がある場合、例外がスローされますおよび/または最後のエラー値を単純に先制配分の上部付近に設定されますコードを簡素化するために、そのかなり可能、ということなのは正しくありませんさらに努力で設定していること割り当てが失敗したり、例外をスローする必要があります。

私はいくつかのケースでは、GetLastErrorから信頼性の高い値を得るためにあなたが任意のAPI関数を呼び出す前にSetLastError(0)を呼び出してから、後であなたが正しいエラーwith GetLastError()を取得する必要があることを覚えておいてください。そのため場合には、それはそれが更新されていなかった成功したこと。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top