title: Unable to launch onscreen keyboard (osk.exe) from a 32-bit process on Win7 x64
body: <p>90% of the time I am unable to launch <code>osk.exe</code> from a 32bit process on <code>Win7 x64</code>. Originally the code was just using:</p>
  
  <pre><code>Process.Launch("osk.exe");
  </code></pre>
  
  <p>Which won't work on x64 because of the directory virtualization. Not a problem I thought, I'll just disable virtualization, launch the app, and enable it again, which I <em>thought</em> was the correct way to do things. I also added some code to bring the keyboard back up if it has been minimized (which works fine) - the code (in a sample WPF app) now looks as follows:</p>
  
  <pre><code>using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Text;
  using System.Windows;
  using System.Windows.Controls;
  using System.Windows.Data;
  using System.Windows.Documents;
  using System.Windows.Input;
  using System.Windows.Media;
  using System.Windows.Media.Imaging;
  using System.Windows.Navigation;using System.Diagnostics;
  using System.Runtime.InteropServices;
  
  namespace KeyboardTest
  {
      /// &lt;summary&gt;
      /// Interaction logic for MainWindow.xaml
      /// &lt;/summary&gt;
      public partial class MainWindow : Window
      {
          [DllImport("kernel32.dll", SetLastError = true)]
          private static extern bool Wow64DisableWow64FsRedirection(ref IntPtr ptr);
          [DllImport("kernel32.dll", SetLastError = true)]
          public static extern bool Wow64RevertWow64FsRedirection(IntPtr ptr);
  
          private const UInt32 WM_SYSCOMMAND = 0x112;
          private const UInt32 SC_RESTORE = 0xf120;
          [DllImport("user32.dll", CharSet = CharSet.Auto)]
          static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
  
          private string OnScreenKeyboadApplication = "osk.exe";
  
          public MainWindow()
          {
              InitializeComponent();
          }
  
          private void KeyboardButton_Click(object sender, RoutedEventArgs e)
          {
              // Get the name of the On screen keyboard
              string processName = System.IO.Path.GetFileNameWithoutExtension(OnScreenKeyboadApplication);
  
              // Check whether the application is not running 
              var query = from process in Process.GetProcesses()
                          where process.ProcessName == processName
                          select process;
  
              var keyboardProcess = query.FirstOrDefault();
  
              // launch it if it doesn't exist
              if (keyboardProcess == null)
              {
                  IntPtr ptr = new IntPtr(); ;
                  bool sucessfullyDisabledWow64Redirect = false;
  
                  // Disable x64 directory virtualization if we're on x64,
                  // otherwise keyboard launch will fail.
                  if (System.Environment.Is64BitOperatingSystem)
                  {
                      sucessfullyDisabledWow64Redirect = Wow64DisableWow64FsRedirection(ref ptr);
                  }
  
                  // osk.exe is in windows/system folder. So we can directky call it without path
                  using (Process osk = new Process())
                  {
                      osk.StartInfo.FileName = OnScreenKeyboadApplication;
                      osk.Start();
                      osk.WaitForInputIdle(2000);
                  }
  
                  // Re-enable directory virtualisation if it was disabled.
                  if (System.Environment.Is64BitOperatingSystem)
                      if (sucessfullyDisabledWow64Redirect)
                          Wow64RevertWow64FsRedirection(ptr);
              }
              else
              {
                  // Bring keyboard to the front if it's already running
                  var windowHandle = keyboardProcess.MainWindowHandle;
                  SendMessage(windowHandle, WM_SYSCOMMAND, new IntPtr(SC_RESTORE), new IntPtr(0));
              }
          }
      }
  }
  </code></pre>
  
  <p>But this code, most of the time, throws the following exception on <code>osk.Start()</code>:</p>
  
  <blockquote>
    <p>The specified procedure could not be found
    at System.Diagnostics.Process.StartWithShellExecuteEx(ProcessStartInfo startInfo)</p>
  </blockquote>
  
  <p>I've tried putting long Thread.Sleep commands in around the osk.Start line, just to make sure it wasn't a race condition, but the same problem persists. Can anyone spot where I'm doing something wrong, or provide an alternative solution for this? It <em>seems</em> to work fine launching Notepad, it just won't play ball with the onscreen keyboard.</p>