0

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 );

私が完全に根拠のないものについてのポインタをいただければ幸いです。

4

3 に答える 3

3

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

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

関数が失敗した場合、戻り値はNULL、および*ppvBitsですNULL

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

戻り値が でないNULL場合、関数は成功しています。呼び出しGetLastErrorは、成功に関する確実に意味のある情報を返すとは限りません ( GetLastErrorから):

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

于 2010-03-10T17:21:48.640 に答える
1

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

コントラクトは、失敗すると GetLastError が意味のある値に設定されると述べています。CreateDIBSection が返されたときに、最後のエラー値が呼び出し元にとって意味を持つとは言いません。

メモリが不足している場合、例外がスローされたり、コードを単純化するために、最後のエラー値が割り当ての上部近くに先制的に設定される可能性が非常に高く、割り当てが必要な場合はそれ以上の努力なしで正しく設定されます。失敗するか、例外をスローします。

于 2010-03-10T19:28:47.483 に答える
0

GetLastError場合によっては、信頼できる値を取得するために、API 関数を呼び出すSetLastError(0)前に呼び出す必要があり、後で正しいエラーが発生することを覚えていますwith GetLastError()。成功した場合は更新されていなかったからです。

于 2010-03-10T17:24:47.810 に答える