如何让C#中System.Environment.GetEnvironmentVariable("USERNAME")兼容UTF-8?
解决C#获取含非ASCII字符用户名乱码的问题
问题根源
System.Environment.GetEnvironmentVariable("USERNAME")在Windows平台下默认调用ANSI编码的API(GetEnvironmentVariableA),当用户名包含非ASCII字符时,会被系统默认代码页转码导致字符丢失,出现????乱码。全局开启UTF-8测试版功能是让系统强制使用UTF-8作为默认代码页,但这会影响所有应用,并非最优解。
针对性解决方案
方案1:直接调用Windows Unicode API获取用户名(推荐)
通过P/Invoke调用Windows原生的GetUserNameW API(Unicode版本),直接获取原始Unicode格式的用户名,完全规避编码转换问题。
代码示例:
using System; using System.Text; using System.Runtime.InteropServices; public static class UserInfoHelper { [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] private static extern bool GetUserNameW(StringBuilder lpBuffer, ref uint lpnSize); public static string GetCurrentUserName() { uint bufferSize = 256; StringBuilder userNameBuffer = new StringBuilder((int)bufferSize); if (GetUserNameW(userNameBuffer, ref bufferSize)) { return userNameBuffer.ToString(); } // 获取失败时抛出Win32异常,可根据需求改为返回默认值 throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error()); } }
使用方式:
string userName = UserInfoHelper.GetCurrentUserName(); // userName会正确显示含非ASCII字符的用户名
方案2:仅为当前进程设置UTF-8代码页
通过API将当前进程的代码页设置为UTF-8,让Environment.GetEnvironmentVariable能正确解析含非ASCII字符的环境变量。但这种方法依赖环境变量的编码状态,可靠性不如方案1。
代码示例:
using System; using System.Runtime.InteropServices; class Program { [DllImport("kernel32.dll")] private static extern uint SetConsoleCP(uint codePage); [DllImport("kernel32.dll")] private static extern uint SetConsoleOutputCP(uint codePage); [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] private static extern bool SetLocaleInfo(uint locale, uint LCType, string lpLCData); static void Main(string[] args) { // 设置控制台输入输出为UTF-8 SetConsoleCP(65001); SetConsoleOutputCP(65001); // 设置进程区域设置为UTF-8 SetLocaleInfo(0, 0x00000001, "en-US.UTF-8"); // 此时获取环境变量应能正确解析非ASCII字符 string userName = Environment.GetEnvironmentVariable("USERNAME"); } }
内容的提问来源于stack exchange,提问作者Zayn
相关产品推荐
相关产品推荐

