CreateDIBSection laissant erreur « Pas assez de stockage », mais semble encore travailler de toute façon

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

Question

Chaque fois que mon application essaie de créer une section de DIB, soit en appelant CreateDIBSection (), ou en appelant LoadImage () avec le drapeau de LR_CREATEDIBSECTION, il semble revenir avec succès. Le HBITMAP retourne est valide, et je peux manipuler et afficher très bien.

Toutefois, les appels à GetLastError () retournera 8: Not enough storage is available to process this command. Cela se produit dès le premier appel à la dernière. La taille du bitmap demandé semble sans conséquence; 800x600 ou 16x16, même résultat. Immédiatement avant l'appel de fonction, GetLastError () retourne pas d'erreur; en outre, l'appel SetLastError (0) avant que l'appel de fonction a le même résultat.

Je l'ai trouvé d'autres personnes à poser des questions similaires, mais non plus se révèle qu'ils utilisent CreateCompatibleBitmap () et le problème disparaît quand ils passent à CreateDIBSection (), ou ils utilisent déjà CreateDIBSection () et le résultat renvoyé est invalide et donc ne fonctionne pas du tout.

Depuis les choses semblent fonctionner, je pensais que je pouvais l'ignorer (et appelle SetLastError (0) après les appels à une ou l'autre fonction), mais il pourrait y avoir un problème subtil je donne sur en le faisant.

Et bien sûr, voici une partie du code de base que je utilise. Tout d'abord, l'appel à LoadImage (), qui fait partie d'une classe bitmap de base que j'utilise pour beaucoup de choses, et que je simplifié un peu pour montrer les aspects les plus pertinents:

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

Les appels à CreateDIBSection sont généralement fait lors de la mise à jour d'une fenêtre en couches:

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

Les pointeurs sur tout ce que je suis complètement hors de la base au sujet seraient appréciés.

Était-ce utile?

La solution

Je pense que vous ne suivez pas ce que dit la documentation ( CreateDIBSection ):

  

Si la fonction réussit, le retour   valeur est une poignée à la nouvelle   DIB, et les points *ppvBits au bitmap   valeurs de bits.

     

Si la fonction échoue, le retour   valeur est NULL et *ppvBits est NULL.

     

Cette fonction peut renvoyer la valeur suivante. [...]

Si la valeur de retour est NULL pas, la fonction a réussi. L'appel GetLastError retournera pas nécessairement toute information fiable significative sur le succès (

Autres conseils

Alors quoi? CreateDIBSection est une fonction complexe qui utilise beaucoup d'autres fenêtres API faire son travail. Certains d'entre les API pourrait définir la dernière erreur pour refléter leur état interne. CreateDIBSection ne va pas effacer l'erreur, juste pour que 0 peut être renvoyé quand il ne manque pas.

Le contrat dit, quand il échoue, GetLastError est réglé sur une valeur significative. Il ne dit pas que la dernière valeur d'erreur a un sens à l'appelant lorsque CreateDIBSection ne retourne

Son tout à fait possible que, s'il y a un manque de mémoire, une exception est jeté et / ou de simplifier le code de la dernière valeur d'erreur se suffit préventivement situé près du sommet des allocations telles que son jeu correctement sans effort supplémentaire si les allocations échouent ou lancer une exception.

Je me souviens que, dans certains cas, afin d'obtenir une valeur fiable de GetLastError vous devez appeler SetLastError(0) avant d'appeler une fonction api, puis plus tard, vous obtenez le with GetLastError() d'erreur correct. Parce que dans le cas où elle a réussi il n'a pas été mis à jour.

scroll top