CreateDIBSection lasciando 'Memoria insufficiente' errore, ma sembra funzionare ancora in ogni caso

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

Domanda

Ogni volta che la mia app cerca di creare una sezione DIB, chiamando CreateDIBSection (), o chiamando LoadImage () con il flag LR_CREATEDIBSECTION, sembra di tornare con successo. Il HBITMAP ritorna è valido, e posso manipolare e visualizzarlo più che bene.

Tuttavia, le chiamate a GetLastError () restituirà 8: Not enough storage is available to process this command. Questo accade fin dal primo richiamare l'ultimo. La dimensione del bitmap richiesto sembra irrilevante; 800x600 o 16x16, stesso risultato. Immediatamente prima della chiamata di funzione, GetLastError () restituisce nessun errore; Inoltre, chiamando SetLastError (0) prima della chiamata di funzione ha lo stesso risultato.

ho trovato altre persone a fare domande simili, ma neanche scopre che stanno utilizzando CreateCompatibleBitmap () e il problema va via quando si passa a CreateDIBSection (), o che stanno già utilizzando CreateDIBSection () e il risultato viene restituito è non valido e quindi non funziona affatto.

Poiché le cose sembrano funzionare, ho pensato che avrei potuto semplicemente ignorarlo (e chiamo SetLastError (0), dopo le chiamate a entrambe le funzioni), ma ci potrebbe essere qualche problema sottile che sto sottovalutando in questo modo.

E, naturalmente, ecco alcuni dei codice di base che sto utilizzando. In primo luogo, la chiamata a LoadImage (), che fa parte di una classe bitmap di base che uso per un sacco di cose, e che ho semplificato un po 'per mostrare gli aspetti più rilevanti:

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

Le chiamate a CreateDIBSection sono in genere fatto durante l'aggiornamento di una finestra a più livelli:

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

Tutti gli indicatori su qualsiasi cosa io sono completamente off-base circa sarebbe apprezzato.

È stato utile?

Soluzione

Credo che non si stanno seguendo quello che dice la documentazione (da CreateDIBSection ):

  

Se la funzione riesce, il ritorno   valore è un handle per la nuova costituzione   DIB, e *ppvBits punti al bitmap   valori dei bit.

     

Se la funzione fallisce, il ritorno   valore è NULL, e *ppvBits è NULL.

     

Questa funzione può restituire il seguente valore. [...]

Se il valore di ritorno non è NULL, la funzione è riuscita. Chiamando GetLastError non necessariamente restituire tutte le informazioni in modo affidabile significativo sul successo (da GetLastError ):

  

Se la funzione non è documentata a   impostare il codice dell'ultimo errore, il valore   restituito da questa funzione è semplicemente   il più recente codice di ultimo errore   sono stati fissati; alcune funzioni impostano la   ultimo codice errore a 0 in caso di successo e   altri non lo fanno.

Altri suggerimenti

E allora? CreateDIBSection è una funzione complessa che si avvale di molte API altre finestre fare il suo lavoro. Alcuni di quelli API potrebbe impostare l'ultimo errore per riflettere loro stato interno. CreateDIBSection non sta per cancellare l'errore, solo in modo che uno 0 possono essere restituiti quando non sicuro.

Il contratto dice, quando non riesce, GetLastError è impostato su un valore significativo:. Non dice che l'ultimo valore di errore ha un senso per il chiamante quando CreateDIBSection fa ritorno

La sua molto probabile che, se v'è una mancanza di memoria, un'eccezione si butta e / o per semplificare il codice l'ultimo valore di errore semplicemente viene preventivamente impostato vicino alla parte superiore delle assegnazioni tale che la sua correttamente impostato, senza ulteriore sforzo qualora le allocazioni fallire o un'eccezione.

Mi ricordo che in alcuni casi, al fine di ottenere un valore attendibile da GetLastError devi chiamare SetLastError(0) prima di chiamare qualsiasi funzione API e poi si ottiene il corretto with GetLastError() errore. Perché nel caso in cui è riuscito non è stato aggiornato.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top