[font=arial,helvetica,sans-serif]I'm new to DirectX and l am trying to modify an existing project (http://spazzarama.co...sing-api-hooks/) so that it will properly take screenshots from fullscreen directx9 applications from a third party application written in c#, hence the SlimDX. This app also hooks with easy hook.[/font]
[font=arial,helvetica,sans-serif]The comments on the author's post above indicate that to get fullscreen working for dx9, one must set [color=#111111] DeviceType.NullReference when initializing the device:[/font]
[font=arial,helvetica,sans-serif][color=#111111]
using (device = new Device(d3d, 0, DeviceType.NullReference, IntPtr.Zero, CreateFlags.HardwareVertexProcessing, new PresentParameters() { BackBufferWidth = 1, BackBufferHeight = 1 }))
{
id3dDeviceFunctionAddresses.AddRange(GetVTblAddresses(device.ComPointer, D3D9_DEVICE_METHOD_COUNT));
}
[/font][font=arial,helvetica,sans-serif]This, however, is not working for me in various DX9 games running fullscreen. It does seem to work fine for games running Windowed mode.[/font]
[font=arial, helvetica, sans-serif]Here is the exception:[/font]
SlimDX.Direct3D9.Direct3D9Exception: D3DERR_INVALIDCALL: Invalid call (-2005530516)
Similar to this thread:
http://www.gamedev.n...devices-solved/
I've tried the solution offered in that thread, but I am having the same result. Here is the screenshot producing function, can anybody point me in the right direction to overcome this exception?
Thank you,
Dan
int EndSceneHook(IntPtr devicePtr)
{
Configuration.AddResultWatch(ResultCode.DeviceLost, ResultWatchFlags.AlwaysIgnore);
using (Device device = Device.FromPointer(devicePtr))
{
// If you need to capture at a particular frame rate, add logic here decide whether or not to skip the frame
try
{
#region Screenshot Request
// Is there a screenshot request? If so lets grab the backbuffer
//this.DebugMessage("Locking");
lock (_lockRenderTarget)
{
if (Request != null)
{
this.DebugMessage("Locked");
_lastRequestTime = DateTime.Now;
DateTime start = DateTime.Now;
try
{
// First ensure we have a Surface to the render target data into
if (_renderTarget == null)
{
this.DebugMessage("Render Target is Null");
// Create offscreen surface to use as copy of render target data
using (SwapChain sc = device.GetSwapChain(0))
{
this.DebugMessage("Create a New Target to Render on");
_renderTarget = Surface.CreateOffscreenPlain(device, sc.PresentParameters.BackBufferWidth, sc.PresentParameters.BackBufferHeight, sc.PresentParameters.BackBufferFormat, Pool.SystemMemory);
}
}
#region Prepare lines for overlay
if (this.Request.RegionToCapture.Width == 0)
{
_lineVectors = new SlimDX.Vector2[] {
new SlimDX.Vector2(0, 0),
new SlimDX.Vector2(_renderTarget.Description.Width - 1, _renderTarget.Description.Height - 1),
new SlimDX.Vector2(0, _renderTarget.Description.Height - 1),
new SlimDX.Vector2(_renderTarget.Description.Width - 1, 0),
new SlimDX.Vector2(0, 0),
new SlimDX.Vector2(0, _renderTarget.Description.Height - 1),
new SlimDX.Vector2(_renderTarget.Description.Width - 1, _renderTarget.Description.Height - 1),
new SlimDX.Vector2(_renderTarget.Description.Width - 1, 0),
};
}
else
{
_lineVectors = new SlimDX.Vector2[] {
new SlimDX.Vector2(this.Request.RegionToCapture.X, this.Request.RegionToCapture.Y),
new SlimDX.Vector2(this.Request.RegionToCapture.Right, this.Request.RegionToCapture.Bottom),
new SlimDX.Vector2(this.Request.RegionToCapture.X, this.Request.RegionToCapture.Bottom),
new SlimDX.Vector2(this.Request.RegionToCapture.Right, this.Request.RegionToCapture.Y),
new SlimDX.Vector2(this.Request.RegionToCapture.X, this.Request.RegionToCapture.Y),
new SlimDX.Vector2(this.Request.RegionToCapture.X, this.Request.RegionToCapture.Bottom),
new SlimDX.Vector2(this.Request.RegionToCapture.Right, this.Request.RegionToCapture.Bottom),
new SlimDX.Vector2(this.Request.RegionToCapture.Right, this.Request.RegionToCapture.Y),
};
}
#endregion
using (Surface backBuffer = device.GetBackBuffer(0, 0))
{
// Create a super fast copy of the back buffer on our Surface
device.GetRenderTargetData(backBuffer, _renderTarget);
this.DebugMessage("We have the frame in memory");
// We have the back buffer data and can now work on copying it to a bitmap
ProcessRequest();
}
}
finally
{
// We have completed the request - mark it as null so we do not continue to try to capture the same request
// Note: If you are after high frame rates, consider implementing buffers here to capture more frequently
// and send back to the host application as needed. The IPC overhead significantly slows down
// the whole process if sending frame by frame.
Request = null;
}
DateTime end = DateTime.Now;
this.DebugMessage("EndSceneHook: Capture time: " + (end - start).ToString());
_lastScreenshotTime = (end - start);
}
}
#endregion
#region Example: Draw Overlay (after screenshot so we don't capture overlay as well)
#region Draw fading lines based on last screencapture request
if (_lastRequestTime != null && _lineVectors != null)
{
TimeSpan timeSinceRequest = DateTime.Now - _lastRequestTime.Value;
if (timeSinceRequest.TotalMilliseconds < 1000.0)
{
using (Line line = new Line(device))
{
_lineAlpha = (float)((1000.0 - timeSinceRequest.TotalMilliseconds) / 1000.0); // This is our fade out
line.Antialias = true;
line.Width = 1.0f;
line.Begin();
line.Draw(_lineVectors, new SlimDX.Color4(_lineAlpha, 0.5f, 0.5f, 1.0f));
line.End();
}
}
else
{
_lineVectors = null;
}
}
#endregion
#region Draw frame rate
using (SlimDX.Direct3D9.Font font = new SlimDX.Direct3D9.Font(device, new System.Drawing.Font("Times New Roman", 16.0f)))
{
if (_lastFrame != null)
{
font.DrawString(null, String.Format("{0:N1} fps", (1000.0 / (DateTime.Now - _lastFrame.Value).TotalMilliseconds)), 100, 100, System.Drawing.Color.Red);
}
_lastFrame = DateTime.Now;
}
#endregion
#endregion
}
catch(Exception e)
{
// If there is an error we do not want to crash the hooked application, so swallow the exception
this.DebugMessage("EndSceneHook: Exeception: " + e.GetType().FullName + ": " + e.Message);
}
// EasyHook has already repatched the original EndScene - so calling EndScene against the SlimDX device will call the original
// EndScene and bypass this hook. EasyHook will automatically reinstall the hook after this hook function exits.
return device.EndScene().Code;
}
}