System.Drawing.Graphics.FromHwnd 绘图闪烁

问题描述

我正在使用 system.drawing.graphics.FromHwnd(IntPtr) 在另一个应用程序中绘制一个圆作为第二个光标。该形状在我的光标下方正确绘制,但它闪烁。我熟悉双缓冲,但这段代码在我制作的“输入”类中,而不是在表单中。这是在游戏中,所以我很确定这正在发生,因为游戏中的画布每帧都会重新绘制并绘制在我的圆形上。

有没有办法:

  • 在这种情况下正确地引起双缓冲
  • 通过其他方式消除闪烁

谢谢

如果这很重要,请使用 C# 和 .NET 5(另外,因为我知道我的类结构上会有不可避免的注释,所以这快速而肮脏地演示了这个问题 - 我知道我在这里做的一些事情不是最佳实践).

public class Input
{
    private ThreadTimer timer;
    private IntPtr hwnd;
    private Graphics? winGraphics = default;

    public input() 
    {
        timer = new ThreadTimer();
        timer.Interval = 15;
        timer.AutoReset = true;
        timer.Elapsed += Timer_Elapsed;
    }

    private void Timer_Elapsed(object sender,System.Timers.ElapsedEventArgs e)
    {
        User32.POINT clientPt = new User32.POINT(Cursor.Position.X,Cursor.Position.Y);
        User32.ScreenToClient(hwnd,ref clientPt);

        var cursor = new Rectangle(clientPt,new Size(5,5));
        winGraphics = Graphics.FromHwnd(hwnd);
        winGraphics.FillEllipse(new SolidBrush(Color.FromArgb(50,Color.Red)),new Rectangle(clientPt.X-15,clientPt.Y-15,30,30));
    }

    public void StartDrawMouse(IntPtr hwnd)
    {
        this.hwnd = hwnd;
        timer.Start();
    }

    public void StopDrawMouse()
    {
        this.hwnd = IntPtr.Zero;
        timer.Stop();
    }
}

ScreenToClient 及其用于 POINT 的 pinvoke 数据结构:

[DllImport("user32.dll")]
public static extern bool ScreenToClient(IntPtr hWnd,ref POINT lpPoint);

[StructLayout(LayoutKind.Sequential)]
public struct POINT
{
    public int X;
    public int Y;

    public POINT(int x,int y)
    {
        this.X = x;
        this.Y = y;
    }

    public static implicit operator System.Drawing.Point(POINT p)
    {
        return new System.Drawing.Point(p.X,p.Y);
    }

    public static implicit operator POINT(System.Drawing.Point p)
    {
        return new POINT(p.X,p.Y);
    }
}

解决方法

我认为问题是因为在另一个应用程序设备上下文中绘制时,您正在交叉线程他们的 UI 线程。

所以你可能想尝试在他们的线程上执行你的代码。 Windows 使用消息循环来处理某些事件,如键盘/鼠标。您可以使用 SetWindowsHook 来附加绘制圆圈的(本机代码)dll 库。然后你应该检查像 WM_PAINT 消息这样的东西,并在它后面附加你的绘图程序。