Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Process.CloseMainWindow() not working

Tags:

c#

I start the Windows On-Screen-Keyboard like that:

s_onScreenKeyboard = new Process();
s_onScreenKeyboard.StartInfo = new ProcessStartInfo("osk.exe");
s_onScreenKeyboard.EnableRaisingEvents = true;
s_onScreenKeyboard.Exited += new EventHandler(s_onScreenKeyboard_Exited);
s_onScreenKeyboard.Start();

This works fine, but when I try to stop it using the following code, it does not work, i.e. the OSK keeps running and the method returns false:

s_onScreenKeyboard.CloseMainWindow();
if (!s_onScreenKeyboard.HasExited)
{
    if (!s_onScreenKeyboard.WaitForExit(1000))
    {
        s_onScreenKeyboard.Close();
        //s_onScreenKeyboard.Kill();
    }
}

When uncommenting s_onScreenKeyboard.Kill(); it is closed, but the problem is that osk.exe obviously uses another process called "msswchx.exe" which is not closed if I simply kill the OSK process. This way, I would end up with hundreds of these processes which is not what I want.

Another strange thing is that the CloseMainWindow() call worked at some time, but then it suddenly did not work anymore, and I do not remember what has changed.

Any ideas?

EDIT: I have found a solution myself. Please see my answer for details.

Background:
I am implementing an On-Screen-Keyboard for my application because it should work with a touchscreen. It is important that the keyboard layout matches the layout which is configured in Windows since the application will be shipped to many different countries. Therefore, instead of implementing a custom keyboard control with approx. 537 keyboard layouts (exaggerating a little here...), I wanted to utilize the Windows built-in On-Screen-Keyboard which adapts to the selected keyboard layout automatically, saving a lot of work for me.

like image 822
gehho Avatar asked Sep 07 '25 10:09

gehho


2 Answers

I have found the/a solution myself:

When I successfully retrieve the MainWindowHandle after the process has been started, the call to CloseMainWindow() is also successful later on. I do not understand the reason for this, but the important thing is: it works!

BTW, for others having the same problem: The MainWindowHandle is not available immediately after starting the process. Obviously, it takes some milliseconds until the MainWindow is started which is why I use the following code to retrieve the handle:

DateTime start = DateTime.Now;
IntPtr handle = IntPtr.Zero;

while (handle == IntPtr.Zero && DateTime.Now - start <= TimeSpan.FromSeconds(2))
{
    try
    {
        // sleep a while to allow the MainWindow to open...
        System.Threading.Thread.Sleep(50);
        handle = s_onScreenKeyboard.MainWindowHandle;
    }
    catch (Exception) { }
}

In this code I continuously get the MainWindowHandle every ~50ms as long as it is still equal to IntPtr.Zero. If the handle could not be retrieved after 2 seconds, I quit the loop to avoid an endless loop in case of error.

like image 156
gehho Avatar answered Sep 09 '25 02:09

gehho


You need to wait untill the process finishes initialization, run Process.WaitForInputIdle Method in order to do that.

like image 33
Kirill Avatar answered Sep 09 '25 01:09

Kirill