Creating a HBITMAP from a DirectX BackBuffer (One more quick question!)

Started by
45 comments, last by Endurion 18 years, 4 months ago
Ugh, that's "out of memory". With valid values such an error is highly unlikely for Windows.

Check the width and height of the DIBSection.

Did you provide the width and height from your surface rect or use GetSystemMetrics as you did before?

The sample code i posted last worked for me as it created the DIB section without an error. Check for differences again as i modified quite some bits.

If that doesn't work out paste your current code again and i'll see to get it working once and for all :)

Fruny: Ftagn! Ia! Ia! std::time_put_byname! Mglui naflftagn std::codecvt eY'ha-nthlei!,char,mbstate_t>

Advertisement
Endurion,

This is what I have at the moment. Thanks again for your help, It really is appreciated!

HBITMAP MyClass::ScreenGrab(){   //RenderTargetSurface.   IDirect3DSurface9* pRenderTargetSurface = NULL;   //DestinationTargetSurface   IDirect3DSurface9* pDestinationTargetSurface = NULL;   //DisplayMode   D3DDISPLAYMODE d3dDipMode;   if (m_pd3dDevice == NULL)      return NULL;   //Get the client rectangle   RECT rc;   GetClientRect(myhWnd, &rc);   ClientToScreen(myhWnd, LPPOINT(&rc.left));   ClientToScreen(myhWnd, LPPOINT(&rc.right));   //GetRenderTargetSurface.   if(FAILED(m_pd3dDevice->GetRenderTarget(0, &pRenderTargetSurface)))	   return NULL;   //Display Mode (d3dDipMode)   if(FAILED(m_pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT,&d3dDipMode)))       return NULL;      //GetDestinationTargetSurface   if(FAILED(m_pd3dDevice->CreateOffscreenPlainSurface((rc.right - rc.left),	                                               (rc.bottom - rc.top),                                                   d3dDipMode.Format,												   D3DPOOL_SYSTEMMEM,                                                   &pDestinationTargetSurface,												   NULL)))												   return NULL;   //copy RenderTargetSurface -> DestTarget   if(FAILED(m_pd3dDevice->GetRenderTargetData(pRenderTargetSurface, pDestinationTargetSurface)))	   return NULL;   //Create a lock on the DestinationTargetSurface   D3DLOCKED_RECT lockedRC;   if(FAILED(pDestinationTargetSurface->LockRect(&lockedRC,	                                   NULL,									   D3DLOCK_NO_DIRTY_UPDATE|D3DLOCK_NOSYSLOCK|D3DLOCK_READONLY)))   return NULL;   int windowSize = (rc.bottom - rc.top) * (rc.right - rc.left) * 4;   LPBYTE lpSource = reinterpret_cast<LPBYTE>(lockedRC.pBits);   LPBYTE lpDestination = new BYTE[windowSize];   LPBYTE lpDestinationTemp = lpDestination;    //memcpy data across    int termination = rc.bottom - rc.top;    for ( int iY = 0; iY < termination; ++iY )    {      memcpy( lpDestinationTemp, lpSource, 4 * ( rc.right - rc.left ) );      lpSource += lockedRC.Pitch;      lpDestinationTemp += 4 * ( rc.right - rc.left );    }   //Unlock the rectangle   if(FAILED(pDestinationTargetSurface->UnlockRect()))		return NULL;    //Create a handle to a bitmap (return from CreateDIBitmap())   HBITMAP hbm;   //Create a Device Context (parameter 1 for CreateDIBitmap())   HDC hCaptureDC = CreateCompatibleDC(NULL);   //Create a BITMAPINFO/BITMAPINFOHEADER structure and fill it(parameter 2 & 5 for CreateDIBitmap())   BITMAPINFO	bmpInfo;   ZeroMemory(&bmpInfo,sizeof(BITMAPINFO));   bmpInfo.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);   bmpInfo.bmiHeader.biBitCount=32;   bmpInfo.bmiHeader.biCompression = BI_RGB;   bmpInfo.bmiHeader.biWidth= rc.right - rc.left;   bmpInfo.bmiHeader.biHeight= -( rc.bottom - rc.top );;   bmpInfo.bmiHeader.biSizeImage = 0;   bmpInfo.bmiHeader.biPlanes = 1;   bmpInfo.bmiHeader.biClrUsed = 0;   bmpInfo.bmiHeader.biClrImportant = 0;   void* pData = NULL;   //Create DIB Section   hbm = CreateDIBSection(hCaptureDC,	                    &bmpInfo,			            DIB_PAL_COLORS,		                (void**)&pData,			            NULL,			            NULL);   //Set the DIB Bits   SetDIBits(hCaptureDC,	         hbm,			 0,			 bmpInfo.bmiHeader.biHeight,			 &lpDestinationTemp,			 &bmpInfo,			 DIB_PAL_COLORS);      //Release Resources   pRenderTargetSurface->Release();   pDestinationTargetSurface->Release();   lastError = GetLastError(); //lastError = 6,230   return hbm;}
Thinking mistake, with CreateDIBSection you can't use SetDIBits, as you get a pointer to the data you can fill from the CreateDIBSection call.

The usual code sample, i used the HBITMAP and showed it after that, so it works (if the source buffer depth is 32bits):


HBITMAP ScreenGrab(){   //RenderTargetSurface.   IDirect3DSurface9* pRenderTargetSurface = NULL;   //DestinationTargetSurface   IDirect3DSurface9* pDestinationTargetSurface = NULL;   //DisplayMode   D3DDISPLAYMODE d3dDipMode;   IDirect3DDevice9* m_pd3dDevice = ( (CDX9RenderClass*)theApp.Renderer() )->Device();   if (m_pd3dDevice == NULL)      return NULL;   //Get the client rectangle   RECT rc;   GetClientRect( theApp.GetSafeHwnd(), &rc);   ClientToScreen(theApp.GetSafeHwnd(), LPPOINT(&rc.left));   ClientToScreen(theApp.GetSafeHwnd(), LPPOINT(&rc.right));   //GetRenderTargetSurface.   if(FAILED(m_pd3dDevice->GetRenderTarget(0, &pRenderTargetSurface)))	   return NULL;   IDirect3D9*    m_pD3D;      m_pd3dDevice->GetDirect3D( &m_pD3D );   //Display Mode (d3dDipMode)   if(FAILED(m_pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT,&d3dDipMode)))       return NULL;      //GetDestinationTargetSurface   if(FAILED(m_pd3dDevice->CreateOffscreenPlainSurface((rc.right - rc.left),	                                               (rc.bottom - rc.top),                                                   d3dDipMode.Format,												   D3DPOOL_SYSTEMMEM,                                                   &pDestinationTargetSurface,												   NULL)))												   return NULL;   //copy RenderTargetSurface -> DestTarget   if(FAILED(m_pd3dDevice->GetRenderTargetData(pRenderTargetSurface, pDestinationTargetSurface)))	   return NULL;   //Create a lock on the DestinationTargetSurface   D3DLOCKED_RECT lockedRC;   if(FAILED(pDestinationTargetSurface->LockRect(&lockedRC,	                                   NULL,									   D3DLOCK_NO_DIRTY_UPDATE|D3DLOCK_NOSYSLOCK|D3DLOCK_READONLY)))   return NULL;   int windowSize = (rc.bottom - rc.top) * (rc.right - rc.left) * 4;   LPBYTE lpSource = reinterpret_cast<LPBYTE>(lockedRC.pBits);   //Create a handle to a bitmap (return from CreateDIBitmap())   HBITMAP hbm;   //Create a Device Context (parameter 1 for CreateDIBitmap())   HDC hCaptureDC = CreateCompatibleDC(NULL);   //Create a BITMAPINFO/BITMAPINFOHEADER structure and fill it(parameter 2 & 5 for CreateDIBitmap())   BITMAPINFO	bmpInfo;   ZeroMemory(&bmpInfo,sizeof(BITMAPINFO));   bmpInfo.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);   bmpInfo.bmiHeader.biBitCount=32;   bmpInfo.bmiHeader.biCompression = BI_RGB;   bmpInfo.bmiHeader.biWidth= rc.right - rc.left;   bmpInfo.bmiHeader.biHeight= -( rc.bottom - rc.top );;   bmpInfo.bmiHeader.biSizeImage = 0;   bmpInfo.bmiHeader.biPlanes = 1;   bmpInfo.bmiHeader.biClrUsed = 0;   bmpInfo.bmiHeader.biClrImportant = 0;   void* pData = NULL;   //Create DIB Section -> this returns a valid pointer to use in pData   hbm = CreateDIBSection(hCaptureDC,	                    &bmpInfo,			            DIB_PAL_COLORS,		                (void**)&pData,			            NULL,			            NULL);      LPBYTE lpDestination = (LPBYTE)pData;   LPBYTE lpDestinationTemp = lpDestination;    //memcpy data across    int termination = rc.bottom - rc.top;    for ( int iY = 0; iY < termination; ++iY )    {      memcpy( lpDestinationTemp, lpSource, 4 * ( rc.right - rc.left ) );      lpSource += lockedRC.Pitch;      lpDestinationTemp += 4 * ( rc.right - rc.left );    }    DWORD lastError = GetLastError(); //lastError = 6,230   //Unlock the rectangle   if(FAILED(pDestinationTargetSurface->UnlockRect()))		return NULL;    //Release Resources   pRenderTargetSurface->Release();   pDestinationTargetSurface->Release();      return hbm;}

Fruny: Ftagn! Ia! Ia! std::time_put_byname! Mglui naflftagn std::codecvt eY'ha-nthlei!,char,mbstate_t>

Endurion,

Many thanks again, but CreateDIBSection is still throwing that error with code 8.

Alex.
Endurion,

Maybe if you posted the entire program that you have used to test this method I might find a flaw elsewhere in my application.

Thanks again,

Alex.
I've seen the lasterror getting filled with 8 as well, and it seems to have that value well before calling CreateDIBSection. Probably some internal thing with Direct3D?

Does the call to CreateDIBSection actually return a valid HBITMAP value? It did in my case and i was able to set the HBITMAP to a Static control and saw the previous contents of the backbuffer.

Note that there're some bits missing:

To adjust the pixel data copying to line widths divisible by 4 (this does not really apply to 32bit depth though, so if you never change to another format this is ok).

edit: I used the exact code that is in my last post, i had that error 8 as well, but it didn't seem to make any problems.

Fruny: Ftagn! Ia! Ia! std::time_put_byname! Mglui naflftagn std::codecvt eY'ha-nthlei!,char,mbstate_t>

Endurion,

Quote:I've seen the lasterror getting filled with 8 as well, and it seems to have that value well before calling CreateDIBSection. Probably some internal thing with Direct3D?


I wrapped the CreateDIBSection in GetLastError() calls and it IS the CreateDIBSection call that is resulting in the 8 error code.

Quote:Does the call to CreateDIBSection actually return a valid HBITMAP value? It did in my case and i was able to set the HBITMAP to a Static control and saw the previous contents of the backbuffer.


It does not appear to no. This is probably linked the 8 error code?

Thanks again,

Alex
I tried several methods, i always got last error 8 after CreateDIBSection, but i also got a valid HBITMAP (non-null).

It seriously looks like a GDI bug, the HBITMAP is valid on every try. The error must be wrong, since there obviously is enough memory and the bitmap is in fact created.

Note: If your hbm is not NULL it is valid.

Fruny: Ftagn! Ia! Ia! std::time_put_byname! Mglui naflftagn std::codecvt eY'ha-nthlei!,char,mbstate_t>

Endurion,

AAH! LOL! suddenly it is working! but it is upside down! You mentioned something negating the height in the BITMAPINFOHEADER which i did do. I will have a play with it and see if I can get it working.

Thanks again mate. I'm amazed how much help you have given me!

Alex.
It was a good opportunity to test my code which worked flawlessly for years (the CreateDIBSection stuff). Since i always got the HBITMAP it never struck me to test the last error value.

Weird!

Fruny: Ftagn! Ia! Ia! std::time_put_byname! Mglui naflftagn std::codecvt eY'ha-nthlei!,char,mbstate_t>

This topic is closed to new replies.

Advertisement