justinstenning / Direct3DHook

DirectX Capture and Overlays by using Direct3D API hooks
http://spazzarama.com/2011/03/14/c-screen-capture-and-overlays-for-direct3d-9-10-and-11-using-api-hooks
MIT License
580 stars 178 forks source link

Capturing screenshot causes DirectX application to crash #20

Closed JasonBurton2 closed 9 years ago

JasonBurton2 commented 9 years ago

My application captures a screenshot of a 32-bit DirectX application (BlueStacks) whenever it needs it. It works fine, but after about 150 calls, it crashes BlueStacks (not the program that is performing the capture). So I tested it with the "Load Test" button on the TestScreenshot application. It does not crash BlueStacks. However, if I execute the code below from a button click in the TestScreenshot application, it does crash BlueStacks. Is there something I am doing wrong with this? Here is the code:

private void button1_Click(object sender, EventArgs e)
{ 
    new Thread(testCapture).Start();
}
public void testCapture()
{
    for (int i = 0; i < 200; i++)
    {
        Bitmap b = _captureProcess.CaptureInterface.GetScreenshot().CapturedBitmap.ToBitmap();
        b.Dispose();
     }
}
JasonBurton2 commented 9 years ago

If I Dispose() the Screenshot object, my problem is corrected, like:

private void button1_Click(object sender, EventArgs e)
{
    new Thread(testCapture).Start();
}
public void testCapture()
{
    for (int i = 0; i < 200; i++)
    {
        Screenshot s = _captureProcess.CaptureInterface.GetScreenshot();
        Bitmap b = s.CapturedBitmap.ToBitmap();
        s.Dispose();
        // didn't have to, or want to, Dispose() the Bitmap since that is what I need
    }
}
justinstenning commented 9 years ago

Yes, these screenshot objects are instantiated within the target application, so it is quite important that they are disposed of correctly. There was a critical fix a while ago to ensure that the MarshalByRef objects' lifetime service would release the object when disposed.

justinstenning commented 9 years ago

I would suggest always wrapping in a using block like so:

using (Screenshot s = _captureProcess.CaptureInterface.GetScreenshot())
{
... do stuff with s
}