C# 如何使用模式窗口将WM_INPUTLANGCHANGEREQUEST发送到应用程序?

C# 如何使用模式窗口将WM_INPUTLANGCHANGEREQUEST发送到应用程序?,c#,winapi,modal-dialog,postmessage,C#,Winapi,Modal Dialog,Postmessage,我编写了一个键盘切换器,它工作得很好,但如果当前应用程序打开了模式窗口,它就会失败。在键盘开关上,我执行以下操作 hwnd = GetForegroundWindow(); PostMessage(hwnd, WM_INPUTLANGCHANGEREQUEST, IntPtr.Zero, handle); 在哪里 但语言并没有改变 我将如何做到这一点 添加get root owner改善了这种情况,但并没有完全起到帮助作用 添加对GetDesktopWindow的调用没有帮助: hwnd =

我编写了一个键盘切换器,它工作得很好,但如果当前应用程序打开了模式窗口,它就会失败。在键盘开关上,我执行以下操作

hwnd = GetForegroundWindow();
PostMessage(hwnd, WM_INPUTLANGCHANGEREQUEST, IntPtr.Zero, handle);
在哪里

但语言并没有改变

我将如何做到这一点


添加get root owner改善了这种情况,但并没有完全起到帮助作用

添加对
GetDesktopWindow
的调用没有帮助:

hwnd = GetDesktopWindow();
InputLangChangeRequest(hwnd, language);
hwnd = GetRootOwner();
InputLangChangeRequest(hwnd, language);

代码在这里

使用

通过遍历父窗口和子窗口的链来检索拥有的根窗口 GetParent返回的所有者窗口

如果存在模式窗口或模式窗口链,则应返回主UI窗口

hwnd = GetForegroundWindow();
hwnd = GetAncestor(hwnd, GA_ROOTOWNER); //#define GA_ROOTOWNER 3

显然,如果目标本身是基于对话框的应用程序(我不知道为什么!),则
WM\u INPUTLANGCHANGEREQUEST
失败。要解决此问题,您可以将
WM\u INPUTLANGCHANGEREQUEST
消息发布到对话框的子体(除了
WM\u INPUTLANGCHANGEREQUEST
消息发布到对话框本身)


可能的副本没有帮助。可能任务是相反的?需要找到最深的子代窗口,而不是祖先?我用WinSpy++检查了窗口句柄,发现:(1)上面的序列不正确地找到了窗口;(2)如果我依赖于其他进程(跟踪前景窗口更改)并获得相同的十六进制句柄,发送消息仍然无法切换语言我有部分错误:句柄在两个方面都是正确的(不正确的hadnler是由于切换到调试器),但语言仍然没有更改。我记得您说过,当窗口顶部没有模式对话框时,它可以工作。因此,如果
getconcenter
返回正确的窗口句柄,它应该可以工作。我用记事本测试了这个。当记事本的“关于”对话框处于活动状态时,它也可以工作。使用
加载键盘布局(“00000408”,KLF_激活)
进行测试。请注意,这只会更改键盘语言。是的,您是对的,我已经检查过了,它可以与
记事本中的模式窗口(文件->打开)一起工作。但若应用程序只有一个窗口并且是模态的(
Pageant
),它就不起作用了
hwnd = GetForegroundWindow();
hwnd = GetAncestor(hwnd, GA_ROOTOWNER); //#define GA_ROOTOWNER 3
static bool MyEnumProc(IntPtr hwnd, IntPtr lParam)
{
    PostMessage(hwnd, WM_INPUTLANGCHANGEREQUEST, IntPtr.Zero, lParam);
    return true;
}

static void Foo()
{
    //Greek input for testing:
    var hkl = LoadKeyboardLayout("00000408", KLF_ACTIVATE);
    var hwnd = GetForegroundWindow();
    if (hwnd != null)
    {
        hwnd = GetAncestor(hwnd, GA_ROOTOWNER);
        PostMessage(hwnd, WM_INPUTLANGCHANGEREQUEST, IntPtr.Zero, (IntPtr)hkl);

        StringBuilder buf = new StringBuilder(100);
        GetClassName(hwnd, buf, 100);

        //if this is a dialog class then post message to all descendants 
        if (buf.ToString() == "#32770")
            EnumChildWindows(hwnd, MyEnumProc, (IntPtr)hkl);
    }
}