3

I'm currently designing an image viewer that allows the user to input her e-mail and get the images digitally. The part that troubles me is getting the on-screen keyboard to close. I use this piece of code to start the windows process:

string progFiles = @"C:\Program Files\Common Files\Microsoft Shared\ink";
string keyboardPath = Path.Combine(progFiles, "TabTip.exe");
Process keyboardProc = Process.Start(keyboardPath);

After which i open a VB InputBox to prompt for the e-mail address (for which i use the on-screen keyboard, since the application will be shown on a touch screen). After this prompt I want to close the process automatically.

I've tried to close the process with the following:

keyboardProc.Kill();
keyboardProc.Dispose();
keyboardProc.Close();
keyboardProc = null;

None of them works and simply throws the exception:

An unhandled exception of type 'System.InvalidOperationException' occurred in System.dll
Additional information: Cannot process request because the process has exited.

I also tried identifying the process by ID and closing it this way, didn't work either. I also had a look at: C#/.NET: Closing another process outside the main window but didn't get it working either.. :(

I'm pretty new to C# and this is the first time I've invoked a windows process from code - am I missing something?

Thank you very much in advance!

Community
  • 1
  • 1
Cassini
  • 33
  • 1
  • 1
  • 4
  • `.Kill()` works for me. Are you sure you only kill it once and there's nothing else you are doing that might cause the exception? – pascalhein May 30 '13 at 09:27
  • Did you try running your app as an admin? – Daniel May 30 '13 at 09:27
  • It is no harm to hide this ink UI, and no need to kill it? – David May 30 '13 at 09:32
  • 1
    `keyboardProc.CloseMainWindow()` [(MSDN)](http://msdn.microsoft.com/en-us/library/system.diagnostics.process.closemainwindow.aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-1) should do the trick. – John Willemse May 30 '13 at 09:45
  • Thank you for your comments, tried the .Kill(), .CloseMainWindow() - both throw an exception because the process already exited :s Will try with hiding now – Cassini May 30 '13 at 10:55
  • @csharpler I don't know what could cause the exception.. All I do is start the process, open an InputBox and prompt for input, then I want to close/kill the process – Cassini May 30 '13 at 11:07
  • Solved this by faking a mouse-click with a virtual mouse.. sketchy, but it did the job. [Here is the code](http://www.sourcepod.com/asczzd16-18920) – Cassini May 30 '13 at 11:55

4 Answers4

5
    /// <summary>
    /// Show the On Screen Keyboard
    /// </summary>
    #region ShowOSK
    public static void ShowOnScreenKeyboard()
    {
        ProcessStartInfo startInfo = new ProcessStartInfo(@"C:\Program Files\Common Files\Microsoft Shared\ink\TabTip.exe");
        Process.Start(startInfo);
    }
    #endregion ShowOSK

    /// <summary>
    /// Hide the On Screen Keyboard
    /// </summary>
    #region HideOSK
    public static void HideOnScreenKeyboard()
    {
        uint WM_SYSCOMMAND = 274;
        uint SC_CLOSE = 61536;
        IntPtr KeyboardWnd = FindWindow("IPTip_Main_Window", null);
        PostMessage(KeyboardWnd.ToInt32(), WM_SYSCOMMAND, (int)SC_CLOSE, 0);
    }
    #endregion HideOSK
Knarf
  • 2,077
  • 1
  • 16
  • 24
3

The following code will open & close Touch Keyboard on Window 10 the quickest, compared to executing / closing TabTip.exe directly. (tested on low power tablet).

    [return: MarshalAs(UnmanagedType.Bool)]
    [DllImport("user32.dll", SetLastError = true)]
    static extern bool PostMessage(IntPtr hWnd, uint Msg, UIntPtr wParam, IntPtr lParam);

    [DllImport("user32.dll", CharSet = CharSet.Unicode)]
    static extern IntPtr FindWindow(String sClassName, String sAppName);

    [DllImport("user32.dll", CharSet = CharSet.Unicode)]
    static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, String lpszClass, String lpszWindow);

    /// <summary>
    /// Show the On Screen Keyboard
    /// </summary>
    #region ShowOSK
    public static void ShowOnScreenKeyboard()
    {
        IntPtr parent = FindWindow("Shell_TrayWnd", null);
        IntPtr child1 = FindWindowEx(parent, IntPtr.Zero, "TrayNotifyWnd", "");
        IntPtr keyboardWnd = FindWindowEx(child1, IntPtr.Zero, "TIPBand", "Touch keyboard");

        uint WM_LBUTTONDOWN = 0x0201;
        uint WM_LBUTTONUP = 0x0202;
        UIntPtr x = new UIntPtr(0x01);
        UIntPtr x1 = new UIntPtr(0x0);
        IntPtr y = new IntPtr(0x0100020);
        PostMessage(keyboardWnd, WM_LBUTTONDOWN, x, y);
        PostMessage(keyboardWnd, WM_LBUTTONUP, x1, y);
    }
    #endregion ShowOSK

    /// <summary>
    /// Hide the On Screen Keyboard
    /// </summary>
    #region HideOSK
    public static void HideOnScreenKeyboard()
    {
        uint WM_SYSCOMMAND = 0x0112;
        UIntPtr SC_CLOSE = new UIntPtr(0xF060);
        IntPtr y = new IntPtr(0);
        IntPtr KeyboardWnd = FindWindow("IPTip_Main_Window", null);
        PostMessage(KeyboardWnd, WM_SYSCOMMAND, SC_CLOSE, y);
    }
    #endregion HideOSK
M Safwan
  • 71
  • 2
  • It worked for me partially. It hides keyboard but it doesn't show. – Jordi Espada Jun 16 '20 at 16:26
  • now it works. If not, or no longer work in future, then check the new name with Spy++ (VisualStudio>Tools>Spy++ which came with C++ package). Class name is "TIPBand", Caption is "Touch keyboard", and the x, x1 and y parameters can be read using the Message window. – M Safwan Sep 06 '20 at 01:23
2

I had trouble with this too. For some reason this works, although it kills all open TabTip processes.

            //Kill all on screen keyboards
            Process[] oskProcessArray = Process.GetProcessesByName("TabTip");
            foreach (Process onscreenProcess in oskProcessArray)
            {
                onscreenProcess.Kill();
            }
Panu Horsmalahti
  • 1,117
  • 9
  • 6
1

u can do:

            Process process = new Process();

            process.StartInfo.FileName = progFiles;//Filename
            process.Start();
            process.Close();
praks
  • 118
  • 1
  • 7