我们有一个动态控件创建,允许用户自己配置面向任务的GUI。一些WinForms控件似乎与其他控件不同地处理非托管句柄。问题的最好例子是TextBox:
只要设置了文本框实例Font属性,即使字体与另一个文本框实例中的字体相同,也会创建新的GDI句柄。同样代表设置创建HBRUSH句柄的BackColor。
如果您拥有包含大量控件的丰富用户界面,则可以轻松达到每个进程的10000个句柄限制。
一种解决方法是使用WM_SETFONT设置字体并控制句柄创建,但这会导致其他问题,例如文本框不会调整为字体。
要查看GDI句柄,我们使用Nir-Soft的GDIView。带有三个文本框和两个按钮的示例代码如下所示:
public partial class Form1 : Form
{
// Used for the work-around
[DllImport("gdi32.dll", EntryPoint = "DeleteObject")]
public static extern bool DeleteObject([In]IntPtr hObject);
// Used for the work-around
[DllImport("user32.dll")]
internal static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
internal const int WM_SETFONT = 0x0030;
private class FontFactory
{
private static Dictionary<Font, IntPtr> _fonts = new Dictionary<Font, IntPtr>();
public static void SetFont(Font font, IntPtr controlHandle)
{
IntPtr fontHandle;
if (!_fonts.TryGetValue(font, out fontHandle))
{
fontHandle = font.ToHfont();
_fonts[font] = fontHandle;
}
SendMessage(controlHandle, WM_SETFONT, fontHandle, IntPtr.Zero);
}
}
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
// Use these lines to reproduce the problem - Will increment HFONTS by 3
Font font = new Font("Arial", 10.5f);
textBox1.Font = font;
textBox2.Font = font;
textBox3.Font = font;
// This will reduce the number of handles but does not resize the text boxes
// Increments HFONTS by only one
/*
FontFactory.SetFont(new Font("Comic Sans MS", 12.5f), textBox1.Handle);
FontFactory.SetFont(new Font("Comic Sans MS", 12.5f), textBox2.Handle);
FontFactory.SetFont(new Font("Comic Sans MS", 12.5f), textBox3.Handle);
*/
}
private void button2_Click(object sender, EventArgs e)
{
Controls.Remove(textBox3);
textBox3.Dispose();
textBox3 = null;
GC.Collect();
}
}
我希望我能够很好地解释这个问题。提前感谢您的帮助!