Quantcast
Channel: Форум программистов и сисадминов Киберфорум
Viewing all articles
Browse latest Browse all 514886

Рисование поверх окон, включая полноэкранные приложения - C# .NET

$
0
0
Здравствуйте. Ищу способ отрисовки поверх полноэкранных приложений.
Пробовал GDI. Медленный. Пробовал DirectX:
:

    public class DXOverlayWindow
    {
        #region [STATIC]Fields
        private static Random random = new Random();
        #endregion
        #region Fields
        public Direct2DRenderer Graphics;
        private bool parentWindowExists = false;
        private MARGIN margin;
        private IntPtr handle, parent;
        private int x, y, width, height;
        private bool visible = true;
        private bool topMost = true;
        private bool isDisposing = false;
        private wndproc windowprochandle;
        private delegate int wndproc(IntPtr handle, uint message, uint wparam, uint lparam);
        #endregion
        #region Properties   
        public bool ParentWindowExists => parentWindowExists;
        public IntPtr Parent => parent;
        public IntPtr Handle => handle;
        public int X => x;
        public int Y => y;
        public int Width => width;
        public int Height => height;
        public bool Visible => visible;
        public bool TopMost => topMost;
        public bool IsDisposing => isDisposing;
        #endregion
        #region Constructors\Destructors
        public DXOverlayWindow(IntPtr parent = default(IntPtr), bool limitFps = false)
        {
            this.parent = parent;
            if (parent == default(IntPtr))
            {
                x = 0; y = 0;
                width = User32.GetSystemMetrics(0); height = User32.GetSystemMetrics(1);
            }
            else
            {
                RECT bounds;
                User32.GetWindowRect(parent, out bounds);
                x = bounds.Left;
                y = bounds.Top;
                width = bounds.Right - bounds.Left;
                height = bounds.Bottom - bounds.Top;
            }
            if (!CreateWindow()) throw new Exception("Couldn't create overlay-window.");
            Graphics = new Direct2DRenderer(handle, limitFps);
            User32.SetLayeredWindowAttributes(handle, 0, 255, 0x1 | 0x2);
            SetBounds(x, y, width, height);
            Task.Run(() => ParentServiceThread());
        }
        ~DXOverlayWindow() { Dispose(); }
        #endregion
        #region [PUBLIC]Methods
        public void SetPosition(int x, int y)
        {
            this.x = x;
            this.y = y;
            User32.MoveWindow(handle, x, y, width, height, 1);
            ExtendFrameIntoClient();
        }
        public void SetSize(int width, int height)
        {
            this.width = width;
            this.height = height;
            User32.MoveWindow(handle, x, y, width, height, 1);
            Graphics.AutoResize(Width, Height);
            ExtendFrameIntoClient();
        }
        public void SetBounds(int x, int y, int width, int height)
        {
            this.x = x;
            this.y = y;
            this.width = width;
            this.height = height;
            User32.MoveWindow(handle, x, y, width, height, 1);
            Graphics.AutoResize(width, height);
            ExtendFrameIntoClient();
        }
        public void Show()
        {
            if (visible) return;
            User32.ShowWindow(handle, 5);
            visible = true;
            ExtendFrameIntoClient();
        }
        public void Hide()
        {
            if (!visible) return;
            User32.ShowWindow(handle, 0);
            visible = false;
        }
        public void Dispose()
        {
            isDisposing = true;
            Graphics.Dispose();
            User32.DestroyWindow(Handle);
        }
        #endregion
        #region [PRIVATE]Methods
        private bool CreateWindow()
        {
            string className = GenerateRandomString(5, 11);
            string menuName = GenerateRandomString(5, 11);
            string windowName = GenerateRandomString(5, 11);
            WNDCLASSEX wndClassEx = new WNDCLASSEX()
            {
                cbSize = WNDCLASSEX.Size(),
                style = 0,
                lpfnWndProc = GetWindowProcPointer(),
                cbClsExtra = 0,
                cbWndExtra = 0,
                hInstance = IntPtr.Zero,
                hIcon = IntPtr.Zero,
                hCursor = IntPtr.Zero,
                hbrBackground = IntPtr.Zero,
                lpszMenuName = menuName,
                lpszClassName = className,
                hIconSm = IntPtr.Zero
            };
            if (User32.RegisterClassEx(ref wndClassEx) == 0) throw new Exception("RegisterClassExA failed with error code: " + Marshal.GetLastWin32Error());
            handle = User32.CreateWindowEx(0x8 | 0x20 | 0x80000 | 0x80 | 0x8000000,
                className, windowName,
                0x80000000 | 0x10000000 | 0x8000000,
                x, y,
                width, height,
                IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
            if (handle == IntPtr.Zero) return false;
            ExtendFrameIntoClient();
            return true;
        }
        private void ParentServiceThread()
        {
            RECT bounds;
            while (!isDisposing)
            {
                Thread.Sleep(100);
                User32.GetWindowRect(parent, out bounds);
                int w = bounds.Right - bounds.Left;
                int h = bounds.Bottom - bounds.Top;
                if (x != bounds.Left || y != bounds.Top || width != w || height != h) SetBounds(bounds.Left, bounds.Top, w, h);
            }
        }
        private void ExtendFrameIntoClient()
        {
            margin.cxLeftWidth = x;
            margin.cxRightWidth = width;
            margin.cyBottomHeight = height;
            margin.cyTopHeight = y;
            DwmApi.DwmExtendFrameIntoClientArea(handle, ref margin);
        }
        private static string GenerateRandomString(int minLen, int maxLen)
        {
            int len = random.Next(minLen, maxLen);
            char[] chars = new char[len];
            for (int i = 0; i < chars.Length; i++) chars[i] = (char)random.Next(97, 123);
            return new string(chars);
        }
        private IntPtr GetWindowProcPointer() { windowprochandle = WindowProcedure; return Marshal.GetFunctionPointerForDelegate(windowprochandle); }
        private int WindowProcedure(IntPtr handle, uint message, uint wparam, uint lparam)
        {
            switch (message)
            {
                case 0x12: return 0;
                case 0x14: User32.SendMessage(handle, 0x12, 0, 0); break;
                case 0x100: return 0;
                default: break;
            }
            return User32.DefWindowProc(handle, message, wparam, lparam);
        }
        #endregion
    }

Direct2DRenderer использует SharpDX.DXGI и SharpDX.Direct2D1. Не отрисовывает поверх полноэкранного приложение.
Возможно есть способ через DirectX как-то напрямую поставлять данные в видеопамять.
Возможно есть способ через инжект своего кода в сторонний процесс.
Есть идеи?

Viewing all articles
Browse latest Browse all 514886

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>