You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在.NET WinForms应用中获取系统密码字符并避免句柄创建错误?

问题

我在WinForms控件的构造函数中通过以下代码获取系统密码字符:

TextBox textBox = new TextBox();
textBox.UseSystemPasswordChar = true;
char passwordChar = (char)NativeMethods.SendMessage(textBox.Handle,
    NativeMethods.EM_GETPASSWORDCHAR, IntPtr.Zero, IntPtr.Zero);
textBox.Dispose();

客户反馈在执行大量并行单元测试后,这段代码出现System.ComponentModel.Win32Exception: Error creating window handle.错误,原因是大量并行测试耗尽了API资源池。请问在.NET WinForms应用中,是否有其他方法可以获取系统密码字符以避免此问题?

解决方法

以下几种方法可以避免频繁创建窗口句柄导致的资源耗尽问题:

1. 缓存系统密码字符

只在首次需要时创建一次TextBox获取密码字符,之后复用这个值,无需每次都创建新控件:

private static char? _systemPasswordChar;

public static char GetSystemPasswordChar()
{
    if (_systemPasswordChar.HasValue)
        return _systemPasswordChar.Value;

    using (var textBox = new TextBox())
    {
        textBox.UseSystemPasswordChar = true;
        _systemPasswordChar = (char)NativeMethods.SendMessage(textBox.Handle,
            NativeMethods.EM_GETPASSWORDCHAR, IntPtr.Zero, IntPtr.Zero);
    }
    return _systemPasswordChar.Value;
}

整个应用生命周期内仅创建一次TextBox句柄,彻底避免资源耗尽问题。

2. 直接读取系统注册表(无需创建控件)

系统密码字符存储在Windows注册表中,可直接读取对应项获取,完全跳过WinForms控件创建步骤:

using Microsoft.Win32;

public static char GetSystemPasswordCharFromRegistry()
{
    const string regPath = @"Control Panel\Desktop";
    const string regKeyName = "PasswordChar";

    using (var key = Registry.CurrentUser.OpenSubKey(regPath))
    {
        if (key == null)
            return '*'; // 默认回退字符

        var value = key.GetValue(regKeyName) as string;
        return string.IsNullOrEmpty(value) ? '*' : value[0];
    }
}

该注册表项对应当前用户设置的密码字符,与系统默认行为一致,用户修改设置时值会同步更新。若需实时获取最新值,可按需读取而非缓存。

3. 单元测试中复用资源

如果必须在单元测试中保留原逻辑,可以通过复用控件实例或限制并行数量减少句柄创建:

// 测试类中复用TextBox实例
private static TextBox _sharedTextBox;

[ClassInitialize]
public static void ClassInitialize(TestContext context)
{
    _sharedTextBox = new TextBox();
    _sharedTextBox.UseSystemPasswordChar = true;
}

[ClassCleanup]
public static void ClassCleanup()
{
    _sharedTextBox.Dispose();
}

[TestMethod]
public void TestPasswordChar()
{
    char passwordChar = (char)NativeMethods.SendMessage(_sharedTextBox.Handle,
        NativeMethods.EM_GETPASSWORDCHAR, IntPtr.Zero, IntPtr.Zero);
    // 断言逻辑
}

内容的提问来源于stack exchange,提问作者Tecman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 09:51:12