I solved the problem. It turns out that Spy++ really is a Windows programmers best friend.
First, the window class of the input panel window turns out to be "IPTip_Main_Window". I use this to get the window handle like so:
HWND wKB = ::FindWindow(_TEXT("IPTip_Main_Window"), NULL);
It turns out that I can just post the same WM_COMMAND messages that its own menu is sending. Most of the operations are available from the menu: dock top, dock bottom and float. The code for sending those messages are:
::PostMessage(wKB, WM_COMMAND, MAKEWPARAM(X,0) , 0);
where X is 10021 for dock bottom, 10023 for dock top and 10020 for floating. The 0 in the high word indicates that the message is sent from a menu.
Finally, I wanted to be able to show and hide the input panel. I noticed that I could turn on a desk band which only includes a single button for toggling the visibility of the input panel. Spy++ing on the messages posted from this button revealed that it sends a global registered window message which is named "TabletInputPanelDeskBandClicked".
Sending this message to the input panel causes it to toggle its visibility.
The HideKeyboard() function now looks like this:
DWORD WM_DESKBAND_CLICKED =
::RegisterWindowMessage(_TEXT("TabletInputPanelDeskBandClicked"));
void HideKeyboard()
{
HWND wKB = ::FindWindow(_TEXT("IPTip_Main_Window"), NULL);
if(wKB != NULL && ::IsWindowVisible(wKB))
{
::PostMessage(wKB, WM_DESKBAND_CLICKED, 0, 0);
}
}
The ShowWindow() function is implemented similarly, but it will also start the keyboard if it is not running.
Update:
It seems that this inter-process messaging is disallowed in Windows Vista/7. When running this command in a non-elevated process it will fail with "access denied". My guess is that this is caused by User Interface Process Isolation (UIPI) protection found in Windows Vista/7. Since the Tablet PC Input Panel is running as a child process of a service it has higher integrity level than user programs, and thus cannot be sent any (or a very limited set of) messages to.
Update:
It turns out that the Tablet PC Input Panel is indeed running in high integrity level, whereas processes started by a limited user account is medium integrity level.