问题描述
我正在使用 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 消息这样的东西,并在它后面附加你的绘图程序。