我解决了这个问题。事实证明,Spy++ 确实是 Windows 程序员最好的朋友。
首先,输入面板窗口的窗口类是“IPTip_Main_Window”。我用它来获取窗口句柄,如下所示:
HWND wKB = ::FindWindow(_TEXT("IPTip_Main_Window"), NULL);
事实证明,我可以只发布它自己的菜单发送的相同 WM_COMMAND 消息。大多数操作都可以从菜单中获得:停靠顶部、停靠底部和浮动。发送这些消息的代码是:
::PostMessage(wKB, WM_COMMAND, MAKEWPARAM(X,0) , 0);
其中 X 是 10021 用于底座底部,10023 用于底座顶部,10020 用于浮动。高位字中的 0 表示消息是从菜单发送的。
最后,我希望能够显示和隐藏输入面板。我注意到我可以打开一个桌带,它只包含一个用于切换输入面板可见性的按钮。对从此按钮发布的消息进行窥探显示,它发送了一个名为“TabletInputPanelDeskBandClicked”的全局注册窗口消息。
将此消息发送到输入面板会导致它切换其可见性。
HideKeyboard() 函数现在如下所示:
DWORD WM_DESKBAND_CLICKED =
::RegisterWindowMessage(_TEXT("TabletInputPanelDeskBandClicked"));
无效隐藏键盘()
{
HWND wKB = ::FindWindow(_TEXT("IPTip_Main_Window"), NULL);
if(wKB != NULL && ::IsWindowVisible(wKB))
{
::PostMessage(wKB, WM_DESKBAND_CLICKED, 0, 0);
}
}
ShowWindow() 函数实现类似,但是如果它没有运行它也会启动键盘。
更新:
在 Windows Vista/7 中似乎不允许这种进程间消息传递。在非提升进程中运行此命令时,它将失败并显示“拒绝访问”。我的猜测是这是由 Windows Vista/7 中的用户界面进程隔离 (UIPI) 保护引起的。由于 Tablet PC 输入面板作为服务的子进程运行,因此它具有比用户程序更高的完整性级别,因此无法向其发送任何(或非常有限的一组)消息。
更新:
事实证明,Tablet PC 输入面板确实以高完整性级别运行,而由受限用户帐户启动的进程是中等完整性级别。