Здравствуйте. Ищу способ отрисовки поверх полноэкранных приложений.
Пробовал GDI. Медленный. Пробовал DirectX:
Direct2DRenderer использует SharpDX.DXGI и SharpDX.Direct2D1. Не отрисовывает поверх полноэкранного приложение.
Возможно есть способ через DirectX как-то напрямую поставлять данные в видеопамять.
Возможно есть способ через инжект своего кода в сторонний процесс.
Есть идеи?
Пробовал 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
}
Возможно есть способ через DirectX как-то напрямую поставлять данные в видеопамять.
Возможно есть способ через инжект своего кода в сторонний процесс.
Есть идеи?