コード例 #1
0
        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;
        }
コード例 #2
0
        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;
        }
コード例 #3
0
        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);
                        }
                        else
                        {
                            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 = this.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);
        }
コード例 #4
0
        private ScreenshotResource CaptureDirectX(IntPtr wnd)
        {
            if (!this.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 (this.captureConfig.Direct3DVersion == Direct3DVersion.Direct3D9 ||
                this.captureConfig.Direct3DVersion == Direct3DVersion.Direct3D9Simple)
            {
                var start = DateTime.Now.Ticks;
                var task  = Task <Screenshot> .Factory.FromAsync(
                    (rect, timeout, callback, ctxt) => this.captureProcess.CaptureInterface.BeginGetScreenshot(rect, timeout, callback),
                    this.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("Error decoding DirectX pixels: {0}", ex);
                        return(null);
                    }
                }
                finally
                {
                    if (screen != null)
                    {
                        screen.Dispose();
                    }
                }
            }
            else if (this.captureConfig.Direct3DVersion == Direct3DVersion.Direct3D9SharedMem)
            {
                try
                {
                    if (!hookReadyWaitHandle.WaitOne(2000))
                    {
                        Log.Debug("Waiting for DirectX hook initialization.");
                        return(null);
                    }

                    captureDxWaitHandle.Set();
                    if (this.copyDataMem == null)
                    {
                        try
                        {
                            this.copyDataMem       = MemoryMappedFile.OpenExisting("CaptureHookSharedMemData", MemoryMappedFileRights.Read);
                            this.copyDataMemAccess = this.copyDataMem.CreateViewAccessor(0, 0, MemoryMappedFileAccess.Read);
                            this.copyDataMemAccess.SafeMemoryMappedViewHandle.AcquirePointer(ref this.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;
                    CopyData copyData = (*((CopyData *)this.copyDataMemPtr));
                    if (copyData.height <= 0 || copyData.textureId == Guid.Empty)
                    {
                        return(null);
                    }
                    lastRendered = copyData.lastRendered;

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

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

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

            return(result);
        }
コード例 #5
0
        private void CaptureLoop()
        {
            IntPtr wnd;

            try
            {
                wnd = HearthstoneHelper.GetHearthstoneWindow();
            }
            catch (Exception ex)
            {
                Log.Error(ex);
                OnWindowLost();
                return;
            }

            // Verify window exists
            if (wnd == IntPtr.Zero)
            {
                OnWindowLost();
                return;
            }

            ScreenshotResource img = null;

            try
            {
                if (currentCaptureMethod == null)
                {
                    currentCaptureMethod = CaptureMethod;
                }

                if (preferredCaptureMethod != CaptureMethod)
                {
                    // user changed capture method in settings
                    currentCaptureMethod   = CaptureMethod;
                    preferredCaptureMethod = CaptureMethod;
                }

                if (dontUseDirectX && currentCaptureMethod.Value == CaptureMethod.DirectX)
                {
                    Log.Info("DirectX gave too much errors, switching to Wdm.");
                    currentCaptureMethod = CaptureMethod.Wdm;
                }

                switch (currentCaptureMethod)
                {
                case CaptureMethod.AutoDetect:
                    var detectedMethod = DetectCaptureMethod(wnd, out img);
                    if (detectedMethod == null)
                    {
                        OnWindowMinimized();
                        extraDelay = 200;     // small delay, just enough to not be noticable, but less cpu
                        Thread.Sleep(extraDelay);
                        return;
                    }
                    currentCaptureMethod = detectedMethod.Value;
                    break;

                case CaptureMethod.DirectX:
                    img = CaptureDirectX(wnd);
                    break;

                case CaptureMethod.Wdm:
                    img = CaptureWdm(wnd);
                    break;

                case CaptureMethod.BitBlt:
                    img = CaptureWdm(wnd, false, true);
                    break;
                }

                if (lastCaptureMethod != currentCaptureMethod.Value)
                {
                    Log.Debug("Capture method changed from {0} to {1}", lastCaptureMethod, currentCaptureMethod.Value);
                    // Do not detach hook, so we can quickly switch again
                    //if (lastCaptureMethod == CaptureMethod.DirectX)
                    //{
                    //    DettachHookFromProcess();
                    //}
                    lastCaptureMethod = currentCaptureMethod.Value;
                }

                if (img == null || img.Bitmap == null)
                {
                    TraceLog.Log("No image data found.");
                    OnWindowMinimized();
                    extraDelay = 200; // small delay, just enough to not be noticable, but less cpu
                    Thread.Sleep(extraDelay);
                    return;
                }

                if (CaptureMethod == CaptureMethod.AutoDetect)
                {
                    if (lastImageHeight > 0 && lastImageHeight != img.Bitmap.Height)
                    {
                        // reset capture method so we detect again on next run
                        Log.Debug("Auto-detect: Image resolution changed from {0} to {1}, reset auto-detect.", lastImageHeight, img.Bitmap.Height);
                        currentCaptureMethod = null;
                    }

                    lastImageHeight = img.Bitmap.Height;
                }

                extraDelay = 0;
                OnWindowFound();

                if (this.PublishCapturedWindow)
                {
                    // Log.Diag("Window captured");
                    var bmpcpy = new Bitmap(img.Bitmap);
                    this.Publish(new WindowCaptured(bmpcpy), log: false);
                }

                var start = DateTime.Now.Ticks;

                try
                {
                    // scan areas, publish events;
                    foreach (var scanner in this.imageScanners)
                    {
                        scanner.Run(img.Bitmap, null);
                    }
                }
                finally
                {
                    try
                    {
                        if (img != null)
                        {
                            img.Dispose();
                        }
                    }
                    catch { }

                    var stop = DateTime.Now.Ticks;
                    var proc = TimeSpan.FromTicks(stop - start).Milliseconds;
                    TraceLog.Log("Scanner speed: {0}", proc);
                }
                // wait with passing next capture to scanner and signal scanner thread to process
                //this.captureWaitHandle.Wait();
                //this.captureWaitHandle.Reset();
                //if (this.currentImage != null)
                //{
                //    this.currentImage.Dispose();
                //    this.currentImage = null;
                //}
                //this.currentImage = img;
                //this.scannerWaitHandle.Set();
            }
            catch (ScreenshotCaptureException ex)
            {
                Log.Debug(ex.ToString());
                OnWindowLost();
                extraDelay = 2000;
                Thread.Sleep(extraDelay);
            }
            catch (Exception ex)
            {
                Log.Error(ex);
            }
        }