免责声明:我不是 .NET Framework 全球化方面的专家,因此它可能会在某处或其他地方包装等效功能。如果是这样,并且您可以找到它,那就太好了——改用它。我想也许Globalization.CultureInfo.CurrentCulture
会返回我们正在寻找的信息,但可惜它没有;相反,即使更改了键盘布局,它似乎也会返回系统默认区域性。我停止了调查。所描述的方法可以保证工作,尽管有一些额外的代码。
要确定与特定键盘布局关联的代码页,您可以调用 Win32GetLocaleInfo
函数,指定与当前键盘布局关联的语言 ID。LOCALE_IDEFAULTANSICODEPAGE
您使用常量请求这个。
要从 .NET 应用程序调用这些函数,您需要使用 P/Invoke。您还需要为一些基本宏定义等效函数。
const int LOCALE_IDEFAULTANSICODEPAGE = 0x1004;
const int LOCALE_RETURN_NUMBER = 0x20000000;
const int SORT_DEFAULT = 0x0;
static int LOWORD(IntPtr val)
{
return (unchecked((int)(long)val)) & 0xFFFF;
}
static int MAKELCID(int languageID, int sortID)
{
return ((0xFFFF & languageID) | (((0x000F) & sortID) << 16));
}
static int MAKELANGID(int primaryLang, int subLang)
{
return ((((ushort)(subLang)) << 10) | (ushort)(primaryLang));
}
[DllImport("kernel32.dll", SetLastError = true)]
static extern int GetLocaleInfo(int locale,
int lcType,
out uint lpLCData,
int cchData);
[DllImport("user32.dll")]
static extern IntPtr GetKeyboardLayout(uint idThread);
像这样使用它:
// Get the keyboard layout for the current thread.
IntPtr keybdLayout = GetKeyboardLayout(0);
// Extract the language ID from it, contained in its low-order word.
int langID = LOWORD(keybdLayout);
// Call the GetLocaleInfo function to retrieve the default ANSI code page
// associated with that language ID.
uint codePage = 0;
GetLocaleInfo(MAKELCID(langID, SORT_DEFAULT),
LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER,
out codePage,
Marshal.SizeOf(codePage));
使用美国英语键盘布局进行测试时,codePage
为 1252。切换到希腊键盘布局后,codePage
为 1253。同样,土耳其语返回 1254,各种西里尔语言返回 1251。与文档中的完全相同。
值得注意的是,在链接的文档中,这些 API 函数被指示为已被取代。在 Windows 的现代版本中,微软已经转向命名语言环境,首先是因为它们没有足够的空间容纳数字 ID,其次是为了支持自定义语言环境。但是您需要使用旧功能来完成您的工作。现代 Windows 应用程序也不使用 ANSI 代码页。
但是,您确实需要意识到这一事实,因为它可能会回来咬您。有些键盘布局没有关联的 ANSI 代码页。对于这些,只能使用 Unicode。上面的代码将返回CP_ACP
(相当于数值0
)。处理这取决于你。您要么需要显示错误,要么将文件保存为 Unicode(尽管会破坏其他应用程序,但符合用户期望)。
最后,我必须指出,如果您缓存该codePage
值,它可能会变得陈旧,因为用户可以随时更改键盘布局。不缓存值可能是最简单的,每次执行保存时都确定它。但是如果你想缓存它,你需要处理WM_INPUTLANGCHANGE
消息并更新你的缓存值作为响应。