Sign in to follow this  

Just want to take fullscreen capture.. somthing missing - please help

This topic is 2650 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

hi all

im trying to take a screenshot from a running DirectX 9 game via C# code and SlimDX
i have this code:


Direct3D direct3d = new SlimDX.Direct3D9.Direct3D();
AdapterInformation adapter = direct3d.Adapters.DefaultAdapter;

PresentParameters parameters = new SlimDX.Direct3D9.PresentParameters();
parameters.BackBufferFormat = adapter.CurrentDisplayMode.Format;
parameters.BackBufferHeight = adapter.CurrentDisplayMode.Height;
parameters.BackBufferWidth = adapter.CurrentDisplayMode.Width;
parameters.Multisample = SlimDX.Direct3D9.MultisampleType.None;
parameters.SwapEffect = SlimDX.Direct3D9.SwapEffect.Discard;
parameters.PresentationInterval = SlimDX.Direct3D9.PresentInterval.Default;
parameters.FullScreenRefreshRateInHertz = 0;


Device device = new Device(direct3d, adapter.Adapter, DeviceType.Hardware, parameters.DeviceWindowHandle, CreateFlags.SoftwareVertexProcessing, parameters);

Surface surface = Surface.CreateOffscreenPlain(device, adapter.CurrentDisplayMode.Width, adapter.CurrentDisplayMode.Height, Format.A8R8G8B8, Pool.SystemMemory);

device.GetFrontBufferData(0, surface);

Rectangle region = new Rectangle(0, 0, adapter.CurrentDisplayMode.Width, adapter.CurrentDisplayMode.Height);

bmp = new Bitmap(Surface.ToStream(surface, ImageFileFormat.Bmp, new Rectangle(region.Left, region.Top, region.Width, region.Height)));


which of course works great only on windowed games..
im really stuck here.. how do i take screens from a full screen games using that code?

thanks in advance

Share this post


Link to post
Share on other sites
it works perfect on windowed games but when im maximize them to full screen i get a deviceLostException(or something like that)
i never payed attention to DPI..... i dont thinks it matter anyway?

Share this post


Link to post
Share on other sites
From the information you provided, I guess the problem is more likely in your transition code. Here are my suggestions.

1. Don't call GetFronBuffer(say by setting a flag) during the transition from windowed mode to full screen mode. what will happen? Different from D3D10 or above, during transition from windowed mode to full screen mode, D3D9 device must be reset/recreated. I wonder if your code is correct?

2. go to this site to download Direct SDK 2010

http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=2c7da5fb-ffbb-4af6-8c66-651cbd28ca15

there are many D3D9 samples which support the trasisition from windowed mode to full screen mode. Add your code for GetFrontBuffer to there, and see what will happen?

[Edited by - standby01 on September 2, 2010 8:22:49 PM]

Share this post


Link to post
Share on other sites
Here is a piece of code from DirectX SDK Feb 2010.

HRESULT WINAPI DXUTToggleFullScreen()
{
HRESULT hr;

// Get the current device settings and flip the windowed state then
// find the closest valid device settings with this change
DXUTDeviceSettings deviceSettings = DXUTGetDeviceSettings();
DXUTDeviceSettings orginalDeviceSettings = DXUTGetDeviceSettings();

// Togggle windowed/fullscreen bit
if( DXUTIsD3D9( &deviceSettings ) )
deviceSettings.d3d9.pp.Windowed = !deviceSettings.d3d9.pp.Windowed;
else
deviceSettings.d3d10.sd.Windowed = !deviceSettings.d3d10.sd.Windowed;

DXUTMatchOptions matchOptions;
matchOptions.eAPIVersion = DXUTMT_PRESERVE_INPUT;
matchOptions.eAdapterOrdinal = DXUTMT_PRESERVE_INPUT;
matchOptions.eDeviceType = DXUTMT_CLOSEST_TO_INPUT;
matchOptions.eWindowed = DXUTMT_PRESERVE_INPUT;
matchOptions.eAdapterFormat = DXUTMT_IGNORE_INPUT;
matchOptions.eVertexProcessing = DXUTMT_CLOSEST_TO_INPUT;
matchOptions.eBackBufferFormat = DXUTMT_IGNORE_INPUT;
matchOptions.eBackBufferCount = DXUTMT_CLOSEST_TO_INPUT;
matchOptions.eMultiSample = DXUTMT_CLOSEST_TO_INPUT;
matchOptions.eSwapEffect = DXUTMT_CLOSEST_TO_INPUT;
matchOptions.eDepthFormat = DXUTMT_CLOSEST_TO_INPUT;
matchOptions.eStencilFormat = DXUTMT_CLOSEST_TO_INPUT;
matchOptions.ePresentFlags = DXUTMT_CLOSEST_TO_INPUT;
matchOptions.eRefreshRate = DXUTMT_IGNORE_INPUT;
matchOptions.ePresentInterval = DXUTMT_CLOSEST_TO_INPUT;

// Go back to previous state

BOOL bIsWindowed = DXUTGetIsWindowedFromDS( &deviceSettings );
UINT nWidth = ( bIsWindowed ) ? GetDXUTState().GetWindowBackBufferWidthAtModeChange() :
GetDXUTState().GetFullScreenBackBufferWidthAtModeChange();
UINT nHeight = ( bIsWindowed ) ? GetDXUTState().GetWindowBackBufferHeightAtModeChange() :
GetDXUTState().GetFullScreenBackBufferHeightAtModeChange();

if( nWidth > 0 && nHeight > 0 )
{
matchOptions.eResolution = DXUTMT_CLOSEST_TO_INPUT;
if( DXUTIsD3D9( &deviceSettings ) )
{
deviceSettings.d3d9.pp.BackBufferWidth = nWidth;
deviceSettings.d3d9.pp.BackBufferHeight = nHeight;
}
else
{
deviceSettings.d3d10.sd.BufferDesc.Width = nWidth;
deviceSettings.d3d10.sd.BufferDesc.Height = nHeight;
}
}
else
{
// No previous data, so just switch to defaults
matchOptions.eResolution = DXUTMT_IGNORE_INPUT;
}

hr = DXUTFindValidDeviceSettings( &deviceSettings, &deviceSettings, &matchOptions );
if( SUCCEEDED( hr ) )
{
// Create a Direct3D device using the new device settings.
// If there is an existing device, then it will either reset or recreate the scene.
hr = DXUTChangeDevice( &deviceSettings, NULL, NULL, false, false );

// If hr == E_ABORT, this means the app rejected the device settings in the ModifySettingsCallback so nothing changed
if( FAILED( hr ) && ( hr != E_ABORT ) )
{
// Failed creating device, try to switch back.
HRESULT hr2 = DXUTChangeDevice( &orginalDeviceSettings, NULL, NULL, false, false );
if( FAILED( hr2 ) )
{
// If this failed, then shutdown
DXUTShutdown();
}
}
}

return hr;
}

Calling GetFrontBuffer during transition could cause an exception.

Share this post


Link to post
Share on other sites
oh thanks a lot!
are there any C# solutions for that..?
i just finished learning C# and i have no background at all...
and i don't really know what to do with this..... :\

Share this post


Link to post
Share on other sites
download DirectX SDK 06/2006. There are many C# samples in this packet.

http://www.microsoft.com/downloads/details.aspx?FamilyId=C72D9F1E-53F3-4747-8490-6801D8E8B4EF&displaylang=en

Share this post


Link to post
Share on other sites
I forgot to mention, directly using C# for Game programing is not recommended. Instead you could consider to use XNA Game Studio, which is a programming environment that allows you to use Visual Studio to create games for Windows Phone, the Xbox 360 console, and Windows-based computers. XNA Game Studio includes the XNA Framework, which is a set of managed libraries designed for game development based on Microsoft .NET Framework 2.0. This documentation collection contains technology overviews, tutorials, and reference material related to XNA Game Studio.

download XNA Game Studio
http://creators.xna.com/en-US/downloads

Search XNA GameStudio on the web you can find some good books.

[Edited by - standby01 on September 7, 2010 5:27:10 PM]

Share this post


Link to post
Share on other sites
Barina already uses SlimDX which is probably the "best" way to access DirectX from a .NET language (Edit: on Windows platform).

To be of more help, I checked my screen-shot function and it seems to work in both full-screen and windowed mode. I do use the backbuffer though:

void SaveScreenShot()
{
Surface backbuffer = device.GetBackBuffer(0, 0);
Surface.ToFile(backbuffer, "screenshot.bmp", ImageFileFormat.Bmp);
backbuffer.Dispose();
}


Just make sure you do this after device.EndScene() and before device.Present(). Haven't checked for the other overload of Surface and a custom rectangle, but maybe this helps.

Share this post


Link to post
Share on other sites
when should i call device.EndScene() and device.Present() ?
i tried somthing but i get invalidCall on device.EndScene()...
and when i removed it i get DeviceLostException

Share this post


Link to post
Share on other sites
What did you try ? Your render loop should look like this:
device.BeginScene();
// ... clear and draw your scene ...
device.EndScene();
if(takeScreenShot)
SaveScreenShot();
device.Present();
Hmmm, never had a problem so far, I can even take a screenshot every frame and my debug runtimes are fine. What do the debug runtimes say exactly about that InvalidCall in your case ?

Oh, I just realized my presentation parameters use SwapEffect.Flip in fullscreen (and Discard in windowed). Can't even switch to fullscreen (dynamically) when using Discard. Maybe that's it.

Nope, it wasn't, sorry for the confusion: Just had "break on exception" enabled in the Visual Studio debugger which disturbed the switching. So the rendering and screenshooting should work either way.

[Edited by - unbird on September 8, 2010 12:59:42 PM]

Share this post


Link to post
Share on other sites
exception when i tried:
device.GetFrontBufferData(0, surface);


D3DERR_DEVICELOST: Device lost (-2005530520)

at SlimDX.Result.Throw[T](Object dataKey, Object dataValue)
at SlimDX.Result.Record[T](Int32 hr, Boolean failed, Object dataKey, Object dataValue)
at SlimDX.Direct3D9.Device..ctor(Direct3D direct3D, Int32 adapter, DeviceType deviceType, IntPtr controlHandle, CreateFlags createFlags, PresentParameters[] presentParameters)
at ScreenGrabber.Program.grabDX() in D:\Documents\Visual Studio 2008\Projects\ScreenGrabber\ScreenGrabber\Program.cs:line 286

and when i tried:
surface = device.GetBackBuffer(0, 0);



D3DERR_DEVICELOST: Device lost (-2005530520)

at SlimDX.Result.Throw[T](Object dataKey, Object dataValue)
at SlimDX.Result.Record[T](Int32 hr, Boolean failed, Object dataKey, Object dataValue)
at SlimDX.Direct3D9.Device..ctor(Direct3D direct3D, Int32 adapter, DeviceType deviceType, IntPtr controlHandle, CreateFlags createFlags, PresentParameters[] presentParameters)
at ScreenGrabber.Program.grabDX() in D:\Documents\Visual Studio 2008\Projects\ScreenGrabber\ScreenGrabber\Program.cs:line 286



the code is:



D3D9.Direct3D direct3d = new SlimDX.Direct3D9.Direct3D();
D3D9.AdapterInformation adapter = direct3d.Adapters.DefaultAdapter;

D3D9.PresentParameters parameters = new SlimDX.Direct3D9.PresentParameters();
parameters.BackBufferFormat = adapter.CurrentDisplayMode.Format;
parameters.BackBufferHeight = adapter.CurrentDisplayMode.Height;
parameters.BackBufferWidth = adapter.CurrentDisplayMode.Width;
parameters.Multisample = SlimDX.Direct3D9.MultisampleType.None;
parameters.SwapEffect = SlimDX.Direct3D9.SwapEffect.Discard;
parameters.PresentationInterval = SlimDX.Direct3D9.PresentInterval.Default;
parameters.FullScreenRefreshRateInHertz = 0;

D3D9.Device device = new D3D9.Device(direct3d, adapter.Adapter, D3D9.DeviceType.Hardware,
parameters.DeviceWindowHandle, D3D9.CreateFlags.SoftwareVertexProcessing, parameters); // this is line 286.

D3D9.Surface surface = D3D9.Surface.CreateOffscreenPlain(device, adapter.CurrentDisplayMode.Width,
adapter.CurrentDisplayMode.Height, D3D9.Format.A8R8G8B8, D3D9.Pool.SystemMemory);

device.BeginScene(); // do i really need this?
device.EndScene();
//device.GetFrontBufferData(0, surface);

surface = device.GetBackBuffer(0, 0);
D3D9.Surface.ToFile(surface, Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\screenshot.bmp", D3D9.ImageFileFormat.Bmp);

Rectangle region = new Rectangle(0, 0, adapter.CurrentDisplayMode.Width, adapter.CurrentDisplayMode.Height);
bmp = new Bitmap(D3D9.Surface.ToStream(surface, D3D9.ImageFileFormat.Bmp, new Rectangle(region.Left, region.Top, region.Width, region.Height)));
surface.Dispose();

device.Present();



line 286:
D3D9.Device device = new D3D9.Device(direct3d, adapter.Adapter, D3D9.DeviceType.Hardware, parameters.DeviceWindowHandle, D3D9.CreateFlags.SoftwareVertexProcessing, parameters);

i just want to take a screenshot from a fullscreen game
from the desktop it works great.. i can see the desktop and a windowed game running inside :)


BTW i have the source code on github at
https://Barina@github.com/Barina/ScreenGrabber.git

Share this post


Link to post
Share on other sites
Sorry, I fatally misread. You want to grab from another game, not your's. Ok, not much help from me then, never tried.

Anyway: What I meant with debug runtimes is enabling the DirectX Debug runtimes, not just the call stack of the exception. This will give you more detailed information than just InvalidCall. See here.

Edit: I think you will have to resort to hooking DirectX calls. Be warned: hooking from a managed language has its quirks. Also, there have been threads about overlay rendering (like steam does) which might point you in the right direction.

[Edited by - unbird on September 9, 2010 2:52:21 PM]

Share this post


Link to post
Share on other sites
Thank you both unbird and standby01!
its too complicated for my project.. ill ask my teacher to give up.. :(
i bet opengl has a single function to do this(apart from GDI+)......
so thanks again guys you helped me a lot here and i really appreciate it!
Thank you very much
Roy

Share this post


Link to post
Share on other sites

This topic is 2650 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this