我有一个 Windows 窗体,上面有一些数字(此时只有一个数字)并定期刷新它们(数字是随机生成的)。更新过程与应用程序在一个单独的线程中进行,因此表单可以接收用户单击按钮、调整窗口大小等事件。 主要方法:
class Program {
static void Main(string[] args) {
Form o = new Overlay();
Application.Run(o);
}
}
表单类:
public partial class Overlay : Form {
Graphics g;
Drawer drawer;
public Overlay() {
InitializeComponent();
TopMost = true;
TransparencyKey = Color.Black;
BackColor = TransparencyKey;
CheckForIllegalCrossThreadCalls = false;
g = CreateGraphics();
drawer = new Drawer();
}
protected override void OnLoad(EventArgs e) {
base.OnLoad(e);
Thread upd = new Thread(mainLoop);
upd.Start();
}
void mainLoop() {
while (true) {
NetCoreEx.Geometry.Rectangle r;
GetWindowRect(Handle, out r);
Refresh();
drawer.Update(g, new Rectangle(r.Left, r.Top, r.Width, r.Height));
}
}
抽屉:
class Drawer {
Font font;
public Drawer() {
string workingDir = Environment.CurrentDirectory;
string projDir = Directory.GetParent(workingDir).Parent.FullName;
PrivateFontCollection collection = new PrivateFontCollection();
collection.AddFontFile(projDir + "\\Resources\\Athelas-Regular.ttf");
FontFamily fontFamily = new FontFamily("Athelas", collection);
font = new Font(fontFamily, 16);
}
public void Update(Graphics g, Rectangle rect) {
string stats = new Random().NextDouble().ToString();
g.DrawString(stats, font, Brushes.Aqua, rect.Width / 2, (int)(rect.Height * 0.75));
}
}
代码对我来说看起来很简单,但由于某种原因,在正常运行 5-10 秒后,应用程序突然因 DrawString 方法上的 System.AccessViolateException 而崩溃... 堆栈跟踪
at System.Drawing.SafeNativeMethods.Gdip.GdipDrawString(HandleRef graphics, String textString, Int32 length, HandleRef font, GPRECTF& layoutRect, HandleRef stringFormat, HandleRef brush)
at System.Drawing.Graphics.DrawString(String s, Font font, Brush brush, RectangleF layoutRectangle, StringFormat format)
at System.Drawing.Graphics.DrawString(String s, Font font, Brush brush, Single x, Single y)
at OverlayStatistics.Scripts.Drawer.Update(Graphics g, Rectangle rect) in C:\Users\Гриша\source\repos\OverlayStatistics\Scripts\Drawer.cs:line 30
at OverlayStatistics.Overlay.mainLoop() in C:\Users\Гриша\source\repos\OverlayStatistics\Scripts\Overlay.cs:line 50
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
我花了很多时间调试,但仍然不知道我做错了什么,有什么帮助吗?
最佳答案
发生的事情是 FontFamily
实例被处置并导致内部 GDI 调用崩溃。您可以像这样加速行为:
public void Update(Graphics g, Rectangle rect)
{
string stats = new Random().NextDouble().ToString();
g.DrawString(stats, font, Brushes.Aqua, rect.Width / 2, (int)(rect.Height * 0.75));
GC.Collect(); // a good way to check for dispose issues
}
有多种方法可以修复它,例如只需确保 FontFamily
实例也是 Drawer
的成员,即:
class Drawer {
Font font;
FontFamily fontFamily;
public Drawer() {
...
fontFamily = new FontFamily("Athelas", collection);
font = new Font(fontFamily, 16);
}
public void Update(Graphics g, Rectangle rect) {
string stats = new Random().NextDouble().ToString();
g.DrawString(stats, font, Brushes.Aqua, rect.Width / 2, (int)(rect.Height * 0.75));
}
}
关于c# - Graphics.DrawString() 上的 AccessViolation,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65552667/