private ScreenshotResource CaptureDirectX(IntPtr wnd)
        {
            if (!AttachHookToProcess())
            {
                throw new ScreenshotCaptureException("Error attaching to DirectX");
            }
            ScreenshotResource result = null;
            // Bitmap img = null;
            // captureProcess.BringProcessWindowToFront();
            // Initiate the screenshot of the CaptureInterface, the appropriate event handler within the target process will take care of the rest

            if (captureConfig.Direct3DVersion == Direct3DVersion.Direct3D9
                ||
                captureConfig.Direct3DVersion == Direct3DVersion.Direct3D9Simple)
            {
                var start = DateTime.Now.Ticks;
                var task = Task<Screenshot>.Factory.FromAsync(
                    (rect, timeout, callback, ctxt) => captureProcess.CaptureInterface.BeginGetScreenshot(rect, timeout, callback),
                    captureProcess.CaptureInterface.EndGetScreenshot,
                    emptyRect,
                    waitForScreenshotTimeout,
                    null);
                Screenshot screen = null;
                try
                {
                    task.Wait();
                    screen = task.Result;

                    var stop = DateTime.Now.Ticks;
                    var proc = TimeSpan.FromTicks(stop - start).Milliseconds;
                    TraceLog.Log("DX Capture speed: {0}", proc);

                    if (screen == null
                        && directxRetryCount == 0)
                    {
                        Log.Debug("No data received from DirectX hook, retrying once.");
                        directxRetryCount++;
                        return CaptureDirectX(wnd);
                    }
                    else if (screen == null)
                    {
                        Log.Debug("No data received from DirectX hook.");
                        return null;
                    }
                    directxRetryCount = 0;

                    task.Dispose();
                    try
                    {
                        var width = screen.Width;
                        var height = screen.Height;
                        var bitmapData = screen.CapturedBitmap;
                        var img = new Bitmap(width, height, PixelFormat.Format32bppRgb);
                        var bmpData = img.LockBits(new Rectangle(0, 0, img.Width, img.Height), ImageLockMode.WriteOnly, img.PixelFormat);

                        Marshal.Copy(bitmapData, 0, bmpData.Scan0, bitmapData.Length);
                        img.UnlockBits(bmpData);

                        result = new ScreenshotResource(img);
                    }
                    catch (Exception ex)
                    {
                        Log.Debug(ex, "Error decoding DirectX pixels: {0}");
                        return null;
                    }
                }
                finally
                {
                    if (screen != null)
                    {
                        screen.Dispose();
                    }
                }
            }
            else if (captureConfig.Direct3DVersion == Direct3DVersion.Direct3D9SharedMem)
            {
                try
                {
                    if (!hookReadyWaitHandle.WaitOne(2000))
                    {
                        Log.Debug("Waiting for DirectX hook initialization.");
                        return null;
                    }

                    captureDxWaitHandle.Set();
                    if (copyDataMem == null)
                    {
                        try
                        {
                            copyDataMem = MemoryMappedFile.OpenExisting("CaptureHookSharedMemData", MemoryMappedFileRights.Read);
                            copyDataMemAccess = copyDataMem.CreateViewAccessor(0, 0, MemoryMappedFileAccess.Read);
                            copyDataMemAccess.SafeMemoryMappedViewHandle.AcquirePointer(ref copyDataMemPtr);
                        }
                        catch (FileNotFoundException)
                        {
                            // not hooked
                            Log.Debug("Shared memory not found");
                            return null;
                        }
                    }
                    if (copyDataMemAccess == null)
                    {
                        // not hooked
                        Log.Debug("Shared memory not opened yet");
                        return null;
                    }

                    int lastRendered;
                    var copyData = (*((CopyData*)copyDataMemPtr));
                    if (copyData.height <= 0
                        || copyData.textureId == Guid.Empty)
                    {
                        return null;
                    }
                    lastRendered = copyData.lastRendered;

                    if (lastRendered != -1)
                    {
                        if (!sharedMemMutexes[lastRendered].WaitOne(1000))
                        {
                            Log.Warn("Failed acquiring shared texture lock in time (1000).");
                            return null;
                        }
                        if (lastKnownTextureId != copyData.textureId)
                        {
                            for (var i = 0; i < 2; i++)
                            {
                                if (sharedTexturesAccess[i] != null)
                                {
                                    sharedTexturesAccess[i].SafeMemoryMappedViewHandle.ReleasePointer();
                                    sharedTexturesAccess[i].Dispose();
                                    sharedTexturesAccess[i] = null;
                                }
                                if (sharedTextures[i] != null)
                                {
                                    sharedTextures[i].Dispose();
                                    sharedTextures[i] = null;
                                }
                            }
                        }

                        if (sharedTextures[lastRendered] == null)
                        {
                            sharedTextures[lastRendered] = MemoryMappedFile.OpenExisting(copyData.textureId.ToString() + lastRendered, MemoryMappedFileRights.ReadWrite);
                            sharedTexturesAccess[lastRendered] = sharedTextures[lastRendered].CreateViewAccessor(
                                0,
                                copyData.height * copyData.pitch,
                                MemoryMappedFileAccess.ReadWrite);
                            sharedTexturesAccess[lastRendered].SafeMemoryMappedViewHandle.AcquirePointer(ref sharedTexturesPtr[lastRendered]);
                        }

                        var img = new Bitmap(
                            copyData.width,
                            copyData.height,
                            copyData.pitch,
                            PixelFormat.Format32bppRgb,
                            new IntPtr(sharedTexturesPtr[lastRendered]));
                        lastKnownTextureId = copyData.textureId;
                        result = new DxScreenshotResource(img, sharedMemMutexes[lastRendered]);
                    }
                }
                catch (Exception ex)
                {
                    Log.Error(ex);
                }
            }

            return result;
        }
        private CaptureMethod? DetectCaptureMethod(IntPtr wnd, out ScreenshotResource img)
        {
            if (NativeMethods.IsIconic(wnd))
            {
                img = null;
                return null;
            }

            if (ScreenCapture.IsFullScreen(wnd))
            {
                if (dontUseDirectX)
                {
                    Log.Warn("Auto-detect: full-screen and DirectX errors. Capturing will probably not work.");
                }
                else
                {
                    Log.Info("Auto-detect: window is full-screen, use DirectX");
                    try
                    {
                        img = CaptureDirectX(wnd);
                        if (img != null
                            && img.Bitmap != null)
                        {
                            Log.Info("Auto-detect: Can use DirectX");
                            return CaptureMethod.DirectX;
                        }
                        Log.Warn("Auto-detect: DirectX returned empty image");
                    }
                    catch (Exception ex)
                    {
                        Log.Warn("Auto-detect: DirectX throws errors, investigate: " + ex);
                    }
                }

                img = null;
                return null;
            }

            if (!dontUseDirectX)
            {
                try
                {
                    img = CaptureDirectX(wnd);
                    if (img != null
                        && img.Bitmap != null)
                    {
                        Log.Info("Auto-detect: Can use DirectX");
                        return CaptureMethod.DirectX;
                    }
                }
                catch (Exception ex)
                {
                    Log.Warn("Auto-detect: DirectX throws errors, investigate: " + ex);
                }
            }

            try
            {
                img = CaptureWdm(wnd, true, false);
                if (img != null)
                {
                    if (!img.Bitmap.IsAllBlack())
                    {
                        Log.Info("Auto-detect: Can use Wdm");
                        return CaptureMethod.Wdm;
                    }
                }
            }
            catch (Exception)
            {
            }

            //if (dontUseDirectX)
            //{
            //    Log.Info("Auto-detect: DirectX gave too much errors, skipping DirectX.");
            //}
            //else
            //{
            //    try
            //    {
            //        img = CaptureDirectX(wnd);
            //        if (img != null)
            //        {
            //            if (!img.Bitmap.IsAllBlack())
            //            {
            //                Log.Info("Auto-detect: Can use DirectX");
            //                return CaptureMethod.DirectX;
            //            }
            //        }
            //    }
            //    catch (Exception)
            //    {
            //    }
            //}

            try
            {
                img = CaptureWdm(wnd, false, true);
                if (img != null
                    && img.Bitmap != null)
                {
                    if (!img.Bitmap.IsAllBlack())
                    {
                        Log.Info("Auto-detect: Can use BitBlt");
                        return CaptureMethod.BitBlt;
                    }
                }
            }
            catch (Exception)
            {
            }

            img = null;
            return null;
        }