Screenshot from directX in C#. Need help!

Reidar Lange

Member
Joined
Oct 29, 2004
Messages
16
Screenshot from directX in C#. SOLVED!

In c++ there is a nice way of geting and saving a screenshot. Does anyone know how to do this in C#. The problem is that ther is no equivalent to the C++ D3DXSaveSurfaceToFile() in C#.

I have found som C++ code that gos like this:

HRESULT CMyD3DApplication::Screenshot( char* filename )
{
HRESULT hr;
D3DDISPLAYMODE dmCurrent;
LPDIRECT3DSURFACE9 pSurface = NULL;


if ( !m_pd3dDevice ) return E_FAIL;



/////////////////////////////////
// QUERY CURRENT WINDOW MODE //
/////////////////////////////////
hr = m_pd3dDevice->GetDisplayMode( 0, &dmCurrent );

if ( FAILED( hr ) )
{
return( hr );
}


////////////////////////////////////////
// CREATE SUFACE SAME SIZE AS WINDOW //
////////////////////////////////////////
hr = m_pd3dDevice->CreateOffscreenPlainSurface( dmCurrent.Width, dmCurrent.Height,
D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH,
&pSurface, NULL );

if ( FAILED( hr ) )
{
return( hr );
}



//////////////////////////////////////////////////////////////////
// COPY FRONTBUFFER INTO SURFACE (WE CANT TOUCH IT DIRECTLY) //
//////////////////////////////////////////////////////////////////
hr = m_pd3dDevice->GetFrontBufferData( 0, pSurface );

if ( FAILED( hr ) )
{
pSurface->Release();
return( hr );
}



//////////////////////////////
// OUTPUT SURFACE TO BMP //
//////////////////////////////
hr = D3DXSaveSurfaceToFile( filename, D3DXIFF_BMP, pSurface, NULL, NULL );

pSurface->Release();



return hr;
}

The C# version will look like this:
Surface renderTarget = null;
Surface destTarget = null;

renderTarget = device.GetRenderTarget(0);
destTarget = device.CreateOffscreenPlainSurface(ClientRectangle.Width,ClientRectangle.Height,graphicsSettings.WindowedDisplayMode.Format,Pool.SystemMemory);
device.GetRenderTargetData(renderTarget,destTarget);

// Now we are ready to save, but how ?????????
 
Last edited by a moderator:
You can save a surface to a file by using the TextureLoaders Save method. Add a reference to Microsoft.DirectX.Direct3DX and it should be available in the Direct3D namespace.
 
You are hereby declared as HERO

mutant said:
You can save a surface to a file by using the TextureLoaders Save method. Add a reference to Microsoft.DirectX.Direct3DX and it should be available in the Direct3D namespace.

I was not able to make TextureLoader work but you put me on the track that lead me right to the solution!

Here is the code that takes a snapshot from the current suface and saves it to the disk (can be executed before Device.Present()):
-------------------------------------------------------------------------------------------
Surface renderTarget = device.GetRenderTarget(0);
Surface destTarget = device.CreateOffscreenPlainSurface(ClientRectangle.Width,ClientRectangle.Height,graphicsSettings.WindowedDisplayMode.Format,Pool.SystemMemory);
device.GetRenderTargetData(renderTarget,destTarget);
SurfaceLoader.Save(@"c:\temp\test.bmp",ImageFileFormat.Bmp,destTarget);
-------------------------------------------------------------------------------------------
You have saved my day!!!!!!!!!!!!!!!
 
Last edited by a moderator:
OK, but thanks anyway. By the way; I have found out that the code example can be simplified:

Code:
Surface renderTarget = device.GetRenderTarget(0);
SurfaceLoader.Save(@"c:\temp\test.bmp",ImageFileFormat.Bmp,renderTarget);
I said earlier that the code could be executed before device.Present(). Infact it should be....

You do not know how many hours I have spent in search for this solution.
Just look at the beauty.

It realy is quite different than the c++ sniplet I started out with.
 
Render to memory

Thanks for this tip, that was very useful for writing to file. Is there a similar trick to writing directly to memory, say to a Bitmap? Thanks
 
i am trying to do something similar to this, however i want to capture from a game thats already running from my c# application, how can I do this?
 
This method uses alot of unmanaged code, but will probably be very fast:
http://www.developerfusion.com/code/4630/capture-a-screen-shot/

This code will get the image into a BitmatpSource (for use with WPF .Net 3.0/5)
Code:
                Bitmap bmpScreenshot;
                Graphics gfxScreenshot;
                // Hide the form so that it does not appear in the screenshot
                this.Hide();
                System.Threading.Thread.Sleep(1);
                // Set the bitmap object to the size of the screen
                bmpScreenshot = new Bitmap((int)System.Windows.SystemParameters.PrimaryScreenWidth, (int)System.Windows.SystemParameters.PrimaryScreenHeight, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
                // Create a graphics object from the bitmap
                gfxScreenshot = Graphics.FromImage(bmpScreenshot);
                // Take the screenshot from the upper left corner to the right bottom corner
                gfxScreenshot.CopyFromScreen(0, 0, 0, 0, new System.Drawing.Size((int)System.Windows.SystemParameters.PrimaryScreenWidth,(int)System.Windows.SystemParameters.PrimaryScreenHeight), CopyPixelOperation.SourceCopy);
                // Save the screenshot to the specified path that the user has chosen
                BitmapSource bitmapSource = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(bmpScreenshot.GetHbitmap(),
IntPtr.Zero,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());

                imx.Source = bitmapSource;
                //bmpScreenshot.Save(saveScreenshot.FileName, ImageFormat.Png);
                // Show the form again
                this.Show();

Otherwise, this code will probably work if you just want a Bitmap object:

Code:
Bitmap bmpScreenshot;
                Graphics gfxScreenshot;
                // Hide the form so that it does not appear in the screenshot
                this.Hide();
                System.Threading.Thread.Sleep(1);
                // Set the bitmap object to the size of the screen
                bmpScreenshot = new Bitmap((int)System.Windows.SystemParameters.PrimaryScreenWidth, (int)System.Windows.SystemParameters.PrimaryScreenHeight, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
                // Create a graphics object from the bitmap
                gfxScreenshot = Graphics.FromImage(bmpScreenshot);
                // Take the screenshot from the upper left corner to the right bottom corner
                gfxScreenshot.CopyFromScreen(0, 0, 0, 0, new System.Drawing.Size((int)System.Windows.SystemParameters.PrimaryScreenWidth,(int)System.Windows.SystemParameters.PrimaryScreenHeight), CopyPixelOperation.SourceCopy);
this.Show();
 
This method uses alot of unmanaged code, but will probably be very fast:
http://www.developerfusion.com/code/4630/capture-a-screen-shot/

This code will get the image into a BitmatpSource (for use with WPF .Net 3.0/5)
Code:
                Bitmap bmpScreenshot;
                Graphics gfxScreenshot;
                // Hide the form so that it does not appear in the screenshot
                this.Hide();
                System.Threading.Thread.Sleep(1);
                // Set the bitmap object to the size of the screen
                bmpScreenshot = new Bitmap((int)System.Windows.SystemParameters.PrimaryScreenWidth, (int)System.Windows.SystemParameters.PrimaryScreenHeight, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
                // Create a graphics object from the bitmap
                gfxScreenshot = Graphics.FromImage(bmpScreenshot);
                // Take the screenshot from the upper left corner to the right bottom corner
                gfxScreenshot.CopyFromScreen(0, 0, 0, 0, new System.Drawing.Size((int)System.Windows.SystemParameters.PrimaryScreenWidth,(int)System.Windows.SystemParameters.PrimaryScreenHeight), CopyPixelOperation.SourceCopy);
                // Save the screenshot to the specified path that the user has chosen
                BitmapSource bitmapSource = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(bmpScreenshot.GetHbitmap(),
IntPtr.Zero,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());

                imx.Source = bitmapSource;
                //bmpScreenshot.Save(saveScreenshot.FileName, ImageFormat.Png);
                // Show the form again
                this.Show();

Otherwise, this code will probably work if you just want a Bitmap object:

Code:
Bitmap bmpScreenshot;
                Graphics gfxScreenshot;
                // Hide the form so that it does not appear in the screenshot
                this.Hide();
                System.Threading.Thread.Sleep(1);
                // Set the bitmap object to the size of the screen
                bmpScreenshot = new Bitmap((int)System.Windows.SystemParameters.PrimaryScreenWidth, (int)System.Windows.SystemParameters.PrimaryScreenHeight, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
                // Create a graphics object from the bitmap
                gfxScreenshot = Graphics.FromImage(bmpScreenshot);
                // Take the screenshot from the upper left corner to the right bottom corner
                gfxScreenshot.CopyFromScreen(0, 0, 0, 0, new System.Drawing.Size((int)System.Windows.SystemParameters.PrimaryScreenWidth,(int)System.Windows.SystemParameters.PrimaryScreenHeight), CopyPixelOperation.SourceCopy);
this.Show();

this works on everything except vista32, with a dx10 card. What gives with that??? I just get a black screen!
 
Back
Top