使用SystemParametersInfo提供帮助

时间:2012-03-12 14:52:16

标签: c# .net windows winapi pinvoke

我在尝试使用SystemParametersInfo时遇到困难。我使用Dvorak键盘,所以我想创建一个exe,我可以双击每当我想要更改键盘布局。我在C#中使用SystemParametersInfo。我可以很好地检索当前的输入语言。但是当我尝试设置输入语言时,我得到的返回值为false,输入语言不会改变。

提前感谢您的帮助。

以下是我正在使用的代码:

class KeyboardSwitcher
{
    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern bool SystemParametersInfo(uint uiAction, uint uiParam, ref uint pvParam, uint fWinIni);

    private const uint SPI_GETDEFAULTINPUTLANG = 0x0059;
    private const uint SPI_SETDEFAULTINPUTLANG = 0x005A;
    private const uint SPIF_UPDATEINIFILE = 0x01;
    private const uint SPIF_SENDWININICHANGE = 0x02;
    private const uint DVORAK = 0xF0020409;
    private const uint QWERTY = 0x04090409;

    static void Main(string[] args)
    {
        uint currentLayout = 0;
        uint newLayout = 0;
        bool result = false;
        int error = 0;

        SystemParametersInfo(SPI_GETDEFAULTINPUTLANG, 0, ref currentLayout, 0);
        if(currentLayout != DVORAK) {
            newLayout = DVORAK;
            /*result = SystemParametersInfo(SPI_SETDEFAULTINPUTLANG, 0, ref newLayout, SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE);*/
            result = SystemParametersInfo(SPI_SETDEFAULTINPUTLANG, 0, ref newLayout, SPIF_SENDWININICHANGE);
            error = Marshal.GetLastWin32Error();
        }
        else {
            newLayout = QWERTY;
            /*result = SystemParametersInfo(SPI_SETDEFAULTINPUTLANG, 0, ref newLayout, SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE);*/
            result = SystemParametersInfo(SPI_SETDEFAULTINPUTLANG, 0, ref newLayout, SPIF_SENDWININICHANGE);
            error = Marshal.GetLastWin32Error();
        }

        Console.WriteLine(">>> Current Layout <<<");
        Console.WriteLine("0x" +currentLayout.ToString("X"));
        Console.WriteLine(">>> New Layout <<<");
        Console.WriteLine("0x" +newLayout.ToString("X"));
        Console.WriteLine("Change Successful >>> " +result);
        Console.WriteLine(error);
        Console.WriteLine(">>> Final Layout <<<");
        uint finalLayout = 0;
        SystemParametersInfo(SPI_GETDEFAULTINPUTLANG, 0, ref finalLayout, 0);
        Console.WriteLine("0x" +finalLayout.ToString("X"));
        Console.WriteLine("Press any key to continue...");
        Console.ReadKey(true);
    }
}

更新:

我投入了Console.WriteLine(Marshal.GetLastWin32Error());与其余的print语句一起返回0.在阅读注释之前,我还通过导入Kernel32.dll尝试了GetLastError()并返回0.感谢您的回复。

更新2:我更改了代码以显示我对GetLastWin32Error()的使用。

当我将Dvorak设置为默认输入语言时,这是输出。

>>> Current Layout <<<
0xF0020409
>>> New Layout <<<
0x4090409
Change Successful >>> True
Error Code >>> 0
>>> Final Layout <<<
0x4090409
Press any key to continue...

当我将Qwerty设置为默认输入语言时,这是输出。

>>> Current Layout <<<
0x4090409
>>> New Layout <<<
0xF0020409
Change Successful >>> True
Error Code >>> 0
>>> Final Layout <<<
0xF0020409
Press any key to continue...

当我将每个布局设置为默认值时,我得到布局的十六进制值使用SPI_GETDEFAULTINPUTLANG。您认为它返回的值可能与我需要发送的值不同吗?

我已经对InputLanguage类进行了一些研究,我认为它不适合这种情况,因为DefaultInputLanguage属性没有setter,也没有其他方法可以设置默认输入语言。

更新3: 当我将SystemParametersInfo的第四个参数更改为SPIF_SENDWININICHANGE时,它变得更接近工作。 SET的结果为True,当我背靠背运行程序时,它会来回切换语言。所以这意味着Windows中的某些东西确实在改变。但是,更改是新的反映在控制面板中,键盘实际上没有更改。我觉得我确实需要SPIF_UPDATEINIFILE来推动变革。我使用的价值是正确的,不是吗?我还更新了代码和输出,以便输出更详细。

1 个答案:

答案 0 :(得分:1)

要通知应用程序语言已更改而不重新启动它,您需要向应用程序窗口发送WM_INPUTLANGCHANGEREQUEST,后跟WM_INPUTLANGCHANGE消息,其中lParam是区域设置标识符。