aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/Tango.ScreenCapture/DXScreenCapture.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Software/Visual_Studio/Tango.ScreenCapture/DXScreenCapture.cs')
-rw-r--r--Software/Visual_Studio/Tango.ScreenCapture/DXScreenCapture.cs436
1 files changed, 436 insertions, 0 deletions
diff --git a/Software/Visual_Studio/Tango.ScreenCapture/DXScreenCapture.cs b/Software/Visual_Studio/Tango.ScreenCapture/DXScreenCapture.cs
new file mode 100644
index 000000000..77428fd8d
--- /dev/null
+++ b/Software/Visual_Studio/Tango.ScreenCapture/DXScreenCapture.cs
@@ -0,0 +1,436 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using SharpDX;
+using SharpDX.Direct3D11;
+using SharpDX.DXGI;
+using Device = SharpDX.Direct3D11.Device;
+using MapFlags = SharpDX.Direct3D11.MapFlags;
+using System.IO;
+using System.Windows.Media.Imaging;
+using System.Runtime.InteropServices;
+using System.Windows.Media;
+using System.Runtime.ExceptionServices;
+using System.Diagnostics;
+
+namespace Tango.RemoteDesktop
+{
+ public class DXScreenCapture : IDisposable
+ {
+ #region INTERNALS
+
+ internal static class User32
+ {
+ public const Int32 CURSOR_SHOWING = 0x00000001;
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct ICONINFO
+ {
+ public bool fIcon;
+ public Int32 xHotspot;
+ public Int32 yHotspot;
+ public IntPtr hbmMask;
+ public IntPtr hbmColor;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct POINT
+ {
+ public Int32 x;
+ public Int32 y;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct CURSORINFO
+ {
+ public Int32 cbSize;
+ public Int32 flags;
+ public IntPtr hCursor;
+ public POINT ptScreenPos;
+ }
+
+ [DllImport("user32.dll")]
+ public static extern bool GetCursorInfo(out CURSORINFO pci);
+
+ [DllImport("user32.dll")]
+ public static extern IntPtr CopyIcon(IntPtr hIcon);
+
+ [DllImport("user32.dll", SetLastError = true)]
+ public static extern bool DestroyIcon(IntPtr hIcon);
+
+ [DllImport("user32.dll", SetLastError = true)]
+ public static extern bool DrawIconEx(IntPtr hdc, int xLeft, int yTop, IntPtr hIcon, int cxWidth, int cyHeight, int istepIfAniCur, IntPtr hbrFlickerFreeDraw, int diFlags);
+
+ [DllImport("user32.dll")]
+ public static extern bool DrawIcon(IntPtr hdc, int x, int y, IntPtr hIcon);
+
+ [DllImport("user32.dll")]
+ public static extern bool GetIconInfo(IntPtr hIcon, out ICONINFO piconinfo);
+ }
+
+ #endregion
+
+ #region Internal Classes
+
+ [StructLayout(LayoutKind.Sequential)]
+ struct CURSORINFO
+ {
+ public Int32 cbSize;
+ public Int32 flags;
+ public IntPtr hCursor;
+ public POINTAPI ptScreenPos;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ struct POINTAPI
+ {
+ public int x;
+ public int y;
+ }
+
+ [DllImport("user32.dll")]
+ static extern bool GetCursorInfo(out CURSORINFO pci);
+
+ [DllImport("user32.dll")]
+ static extern bool DrawIcon(IntPtr hDC, int X, int Y, IntPtr hIcon);
+
+ const Int32 CURSOR_SHOWING = 0x00000001;
+
+ internal struct SIZE
+ {
+ public int cx;
+ public int cy;
+ }
+
+ internal class GDIStuff
+ {
+ #region Class Variables
+ public const int SRCCOPY = 13369376;
+ #endregion
+
+
+ #region Class Functions
+ [DllImport("gdi32.dll", EntryPoint = "CreateDC")]
+ public static extern IntPtr CreateDC(IntPtr lpszDriver, string lpszDevice, IntPtr lpszOutput, IntPtr lpInitData);
+
+ [DllImport("gdi32.dll", EntryPoint = "DeleteDC")]
+ public static extern IntPtr DeleteDC(IntPtr hDc);
+
+ [DllImport("gdi32.dll", EntryPoint = "DeleteObject")]
+ public static extern IntPtr DeleteObject(IntPtr hDc);
+
+ [DllImport("gdi32.dll", EntryPoint = "BitBlt")]
+ public static extern bool BitBlt(IntPtr hdcDest, int xDest,
+ int yDest, int wDest,
+ int hDest, IntPtr hdcSource,
+ int xSrc, int ySrc, int RasterOp);
+
+ [DllImport("gdi32.dll", EntryPoint = "CreateCompatibleBitmap")]
+ public static extern IntPtr CreateCompatibleBitmap
+ (IntPtr hdc, int nWidth, int nHeight);
+
+ [DllImport("gdi32.dll", EntryPoint = "CreateCompatibleDC")]
+ public static extern IntPtr CreateCompatibleDC(IntPtr hdc);
+
+ [DllImport("gdi32.dll", EntryPoint = "SelectObject")]
+ public static extern IntPtr SelectObject(IntPtr hdc, IntPtr bmp);
+ #endregion
+ }
+
+ internal class Win32Stuff
+ {
+
+ #region Class Variables
+
+ public const int SM_CXSCREEN = 0;
+ public const int SM_CYSCREEN = 1;
+
+ public const Int32 CURSOR_SHOWING = 0x00000001;
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct ICONINFO
+ {
+ public bool fIcon; // Specifies whether this structure defines an icon or a cursor. A value of TRUE specifies
+ public Int32 xHotspot; // Specifies the x-coordinate of a cursor's hot spot. If this structure defines an icon, the hot
+ public Int32 yHotspot; // Specifies the y-coordinate of the cursor's hot spot. If this structure defines an icon, the hot
+ public IntPtr hbmMask; // (HBITMAP) Specifies the icon bitmask bitmap. If this structure defines a black and white icon,
+ public IntPtr hbmColor; // (HBITMAP) Handle to the icon color bitmap. This member can be optional if this
+ }
+ [StructLayout(LayoutKind.Sequential)]
+ public struct POINT
+ {
+ public Int32 x;
+ public Int32 y;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct CURSORINFO
+ {
+ public Int32 cbSize; // Specifies the size, in bytes, of the structure.
+ public Int32 flags; // Specifies the cursor state. This parameter can be one of the following values:
+ public IntPtr hCursor; // Handle to the cursor.
+ public POINT ptScreenPos; // A POINT structure that receives the screen coordinates of the cursor.
+ }
+
+ #endregion
+
+
+ #region Class Functions
+
+ [DllImport("user32.dll", EntryPoint = "GetDesktopWindow")]
+ public static extern IntPtr GetDesktopWindow();
+
+ [DllImport("user32.dll", EntryPoint = "GetDC")]
+ public static extern IntPtr GetDC(IntPtr ptr);
+
+ [DllImport("user32.dll", EntryPoint = "GetSystemMetrics")]
+ public static extern int GetSystemMetrics(int abc);
+
+ [DllImport("user32.dll", EntryPoint = "GetWindowDC")]
+ public static extern IntPtr GetWindowDC(Int32 ptr);
+
+ [DllImport("user32.dll", EntryPoint = "ReleaseDC")]
+ public static extern IntPtr ReleaseDC(IntPtr hWnd, IntPtr hDc);
+
+
+ [DllImport("user32.dll", EntryPoint = "GetCursorInfo")]
+ public static extern bool GetCursorInfo(out CURSORINFO pci);
+
+ [DllImport("user32.dll", EntryPoint = "CopyIcon")]
+ public static extern IntPtr CopyIcon(IntPtr hIcon);
+
+ [DllImport("user32.dll", SetLastError = true)]
+ static extern bool DestroyIcon(IntPtr hIcon);
+
+ [DllImport("user32.dll", EntryPoint = "GetIconInfo")]
+ public static extern bool GetIconInfo(IntPtr hIcon, out ICONINFO piconinfo);
+
+
+ #endregion
+ }
+
+ #endregion
+
+ // # of graphics card adapter
+ private int numAdapter = 0;
+
+ // # of output device (i.e. monitor)
+ private int numOutput = 0;
+
+ private Device device;
+
+ private Output1 output1;
+
+ private Texture2DDescription textureDesc;
+
+ private OutputDuplication duplicatedOutput;
+
+ private int widthDX;
+
+ private int heightDX;
+
+ public void Initialize()
+ {
+ // Create DXGI Factory1
+ var factory = new Factory1();
+ var adapter = factory.GetAdapter1(numAdapter);
+
+ // Create device from Adapter
+ device = new Device(adapter);
+
+ // Get DXGI.Output
+ var output = adapter.GetOutput(numOutput);
+ output1 = output.QueryInterface<Output1>();
+
+ // Width/Height of desktop to capture
+ widthDX = ((Rectangle)output.Description.DesktopBounds).Width;
+ heightDX = ((Rectangle)output.Description.DesktopBounds).Height;
+
+ // Create Staging texture CPU-accessible
+ textureDesc = new Texture2DDescription
+ {
+ CpuAccessFlags = CpuAccessFlags.Read,
+ BindFlags = BindFlags.None,
+ Format = Format.B8G8R8A8_UNorm,
+ Width = widthDX,
+ Height = heightDX,
+ OptionFlags = ResourceOptionFlags.None,
+ MipLevels = 1,
+ ArraySize = 1,
+ SampleDescription = { Count = 1, Quality = 0 },
+ Usage = ResourceUsage.Staging
+ };
+
+ // Duplicate the output
+ duplicatedOutput = output1.DuplicateOutput(device);
+ }
+
+ /// <summary>
+ /// Captures the bitmap source.
+ /// </summary>
+ /// <param name="left">The left.</param>
+ /// <param name="top">The top.</param>
+ /// <param name="width">The width.</param>
+ /// <param name="height">The height.</param>
+ /// <param name="captureCursor">Append cursor.</param>
+ /// <returns></returns>
+ [HandleProcessCorruptedStateExceptions]
+ [DebuggerStepThrough]
+ [DebuggerHidden]
+ public BitmapSource CaptureBitmapSource(int left, int top, int width, int height, bool captureCursor)
+ {
+ var screenTexture = new Texture2D(device, textureDesc);
+
+ try
+ {
+ SharpDX.DXGI.Resource screenResource;
+ OutputDuplicateFrameInformation duplicateFrameInformation;
+
+ // Try to get duplicated frame within given time
+ duplicatedOutput.AcquireNextFrame(5, out duplicateFrameInformation, out screenResource);
+
+ //if (i > 0)
+ //{
+ // copy resource into memory that can be accessed by the CPU
+ using (var screenTexture2D = screenResource.QueryInterface<Texture2D>())
+ device.ImmediateContext.CopyResource(screenTexture2D, screenTexture);
+
+ // Get the desktop capture texture
+ var mapSource = device.ImmediateContext.MapSubresource(screenTexture, 0, MapMode.Read, MapFlags.None);
+
+ // Create Drawing.Bitmap
+ var bitmap = new System.Drawing.Bitmap(widthDX, heightDX, System.Drawing.Imaging.PixelFormat.Format32bppRgb);
+ var boundsRect = new System.Drawing.Rectangle(0, 0, widthDX, heightDX);
+
+ // Copy pixels from screen capture Texture to GDI bitmap
+ var mapDest = bitmap.LockBits(boundsRect, System.Drawing.Imaging.ImageLockMode.WriteOnly, bitmap.PixelFormat);
+ var sourcePtr = mapSource.DataPointer;
+ var destPtr = mapDest.Scan0;
+ for (int y = 0; y < height; y++)
+ {
+ // Copy a single line
+ Utilities.CopyMemory(destPtr, sourcePtr, widthDX * 4);
+
+ // Advance pointers
+ sourcePtr = IntPtr.Add(sourcePtr, mapSource.RowPitch);
+ destPtr = IntPtr.Add(destPtr, mapDest.Stride);
+ }
+
+ // Release source and dest locks
+ bitmap.UnlockBits(mapDest);
+ device.ImmediateContext.UnmapSubresource(screenTexture, 0);
+
+ if (left > 0 || top > 0 || width < widthDX || height < heightDX)
+ {
+ CropImage(bitmap, new System.Drawing.Rectangle(left, top, width, height));
+ }
+
+ if (captureCursor)
+ {
+ using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(bitmap))
+ {
+ ApplyCursor(g, bitmap, left, top);
+ }
+ }
+
+ MemoryStream ms = new MemoryStream();
+ bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
+ ms.Position = 0;
+ var img = GetBitmapImage(ms);
+ img.Freeze();
+
+ bitmap.Dispose();
+ screenTexture.Dispose();
+ screenResource.Dispose();
+ duplicatedOutput.ReleaseFrame();
+
+
+
+ return img;
+ }
+ catch (SharpDXException e)
+ {
+ if (e.ResultCode.Code != SharpDX.DXGI.ResultCode.WaitTimeout.Result.Code)
+ {
+ Trace.TraceError(e.Message);
+ Trace.TraceError(e.StackTrace);
+ }
+
+ throw;
+ }
+ }
+
+ /// <summary>
+ /// Applies the cursor icon.
+ /// </summary>
+ /// <param name="g">The graphics context.</param>
+ /// <param name="bitmap">The bitmap.</param>
+ /// <param name="left">The left.</param>
+ /// <param name="top">The top.</param>
+ [DebuggerHidden]
+ [DebuggerStepThrough]
+ private void ApplyCursor(System.Drawing.Graphics g, System.Drawing.Bitmap bitmap, int left, int top)
+ {
+ try
+ {
+ CURSORINFO pci;
+ pci.cbSize = Marshal.SizeOf(typeof(CURSORINFO));
+
+ if (GetCursorInfo(out pci))
+ {
+ if (pci.flags == CURSOR_SHOWING)
+ {
+ //var iconPointer = User32.CopyIcon(pci.hCursor);
+ //User32.ICONINFO iconInfo;
+ //User32.GetIconInfo(iconPointer, out iconInfo);
+
+ var hdc = g.GetHdc();
+ User32.DrawIconEx(hdc, pci.ptScreenPos.x - left, pci.ptScreenPos.y - top, pci.hCursor, 0, 0, 0, IntPtr.Zero, 0x0003);
+
+ //User32.DestroyIcon(iconPointer);
+ GDIStuff.DeleteObject(pci.hCursor);
+ }
+ }
+ g.ReleaseHdc();
+ }
+ catch { }
+ }
+
+ /// <summary>
+ /// Gets the bitmap image.
+ /// </summary>
+ /// <param name="ms">The ms.</param>
+ /// <returns></returns>
+ private BitmapImage GetBitmapImage(MemoryStream ms)
+ {
+ var bitmapImage = new BitmapImage();
+ bitmapImage.BeginInit();
+ bitmapImage.StreamSource = ms;
+ bitmapImage.EndInit();
+ return bitmapImage;
+ }
+
+ /// <summary>
+ /// Crops the image.
+ /// </summary>
+ /// <param name="img">The img.</param>
+ /// <param name="cropArea">The crop area.</param>
+ /// <returns></returns>
+ private System.Drawing.Bitmap CropImage(System.Drawing.Bitmap img, System.Drawing.Rectangle cropArea)
+ {
+ System.Drawing.Bitmap bmpImage = new System.Drawing.Bitmap(img);
+ return bmpImage.Clone(cropArea, bmpImage.PixelFormat);
+ }
+
+ /// <summary>
+ /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
+ /// </summary>
+ public void Dispose()
+ {
+ duplicatedOutput.Dispose();
+ device.Dispose();
+ }
+ }
+}