CreateDIBSection dejando 'Espacio de almacenamiento insuficiente' error, pero parece que todavía funcionan de todos modos

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

Pregunta

Siempre que mi aplicación intenta crear una sección DIB, ya sea llamando CreateDIBSection (), o llamando LoadImage () con el indicador LR_CREATEDIBSECTION, parece volver con éxito. El HBITMAP devuelve es válida, y puede manipular y mostrarlo bien.

Sin embargo, las llamadas a GetLastError () devolverá 8: Not enough storage is available to process this command. Esto sucede desde la primera llamada al último. El tamaño del mapa de bits requerida parece intrascendente; 800x600 o 16x16, mismo resultado. Inmediatamente antes de la llamada de función, GetLastError () devuelve ningún error; Adicionalmente, llamando SetLastError (0) antes de la llamada a la función tiene el mismo resultado.

He encontrado otras personas haciendo preguntas similares, pero tampoco resulta que están utilizando CreateCompatibleBitmap () y el problema desaparece cuando cambian a CreateDIBSection (), o que ya están utilizando CreateDIBSection () y el resultado se devuelve es inválida y por lo que no funciona en absoluto.

Ya que las cosas parecen estar trabajando, he pensado que podría simplemente lo ignoran (y llamo SetLastError (0) después de las llamadas a cualquiera de las funciones), pero podría haber algún problema sutil que se me escapa por hacerlo.

Y, por supuesto, esto es una parte del código básico que estoy usando. En primer lugar, la llamada a LoadImage (), que es parte de una clase de mapa de bits básico que utilizo para un montón de cosas, y lo que he simplificado un poco para mostrar los aspectos más relevantes:

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

Las llamadas a CreateDIBSection normalmente se realizan al actualizar una ventana por capas:

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

Cualquier punteros sobre cualquier cosa que estoy completamente fuera de la base sobre serían apreciadas.

¿Fue útil?

Solución

Creo que no está siguiendo lo que dice la documentación (de CreateDIBSection):

  

Si la función tiene éxito, el regreso   valor es un identificador para el recién creado   DIB, y *ppvBits puntos al mapa de bits   valores de bit.

     

Si la función falla, el regreso   valor es NULL y *ppvBits es NULL.

     

Esta función puede devolver el siguiente valor. [...]

Si el valor de retorno no está NULL, la función tuvo éxito. Llamando GetLastError no necesariamente va a devolver ninguna información fiable significativa en el éxito (de GetLastError ):

  

Si la función no está documentada a   establecer el último código de error, el valor   devuelto por esta función es simplemente   el más reciente último código de error para   han sido establecidas; algunas funciones establecen el   último código de error a 0 en caso de éxito y   otros no lo hacen.

Otros consejos

Entonces, ¿qué? CreateDIBSection es una función complicada que hace uso de muchas API de otras ventanas haga su trabajo. Algunos de los API podría establecer el último error para reflejar su estado interno. CreateDIBSection no va a borrar el error, sólo para que un 0 se puede devolver cuando no falla.

El contrato dice que, cuando falla, GetLastError se establece en un valor significativo:. No dice que el valor de error última tiene ningún significado para la persona que llama cuando CreateDIBSection no volver

Es bastante posible que, si hay una falta de memoria, una excepción es lanzada y / o para simplificar el código del valor de error pasado, simplemente se establece de forma preventiva en la parte superior de las asignaciones de tal manera que su ajustado correctamente sin mayor esfuerzo las asignaciones deben fallar o lanzar una excepción.

Recuerdo que, en algunos casos, con el fin de obtener un valor fiable de GetLastError usted tiene que llamar SetLastError(0) antes de llamar a cualquier función de API y, posteriormente, se da la with GetLastError() error correcto. Ya que en caso de que tuvo éxito no se actualizaba.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top