Win7 x64で32ビットプロセスからオンスクリーンキーボード(OSK.EXE)を起動できません

StackOverflow https://stackoverflow.com/questions/2929255

質問

90%の時間の起動できません osk.exe 32ビットプロセスから Win7 x64. 。もともとコードは次のものを使用していました。

Process.Launch("osk.exe");

ディレクトリ仮想化のため、x64では機能しません。私が考えた問題ではありません、私は仮想化を無効にし、アプリを起動し、それをもう一度有効にするだけです。 考え 物事を行う正しい方法でした。また、キーボードが最小化されている場合(正常に動作する場合)、キーボードを元に戻すためのコードを追加しました - コード(サンプルWPFアプリ)は次のようになりました。

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
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    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));
            }
        }
    }
}

しかし、このコードは、ほとんどの場合、次の例外をスローします osk.Start():

指定された手順は、system.diagnostics.process.startwithshellexecuteex(processstartinfo startinfo)で見つけることができませんでした

OSK.STARTラインの周りに眠っているコマンドを長いスレッドを入れてみましたが、それが人種状態ではないことを確認しましたが、同じ問題が持続します。誰かが私が何か間違ったことをしている場所を見つけたり、このための代替ソリューションを提供したりできますか?それ 思われる ノートパッドを起動するのに適切に動作するためには、画面上のキーボードでボールをプレイしません。

役に立ちましたか?

解決

あなたが取得している正確なエラーメッセージについて、私はあまり確かな説明を持っていません。しかし、リダイレクトを無効にすることで、.NETフレームワークが台無しになります。デフォルトでは、process.start()p/はshellexecuteex()API関数を呼び出してプロセスを開始します。この関数は、shell32.dllに存在します。これは、以前に行われていなかった場合にロードする必要があるDLLです。リダイレクトを無効にすると、間違っています。

そのための回避策は、processstartinfo.useshellexecuteをfalseに設定することです。ここでは必要ありません。

明らかに、リダイレクトを無効にすることは、実際には予測できない副作用を伴う危険なアプローチです。がある たくさん 需要ロードされたdllの。プラットフォームターゲット=任意のCPUでコンパイルする非常に小さなヘルパーexeは、問題を解決できます。

他のヒント

64ビットオペレーティングシステムで実行されている32ビットアプリケーションは、OSK.EXEの64ビットバージョンを開始する必要があります。以下に、C#で書かれたコードが表示され、画面キーボードの正しいものを起動することがわかります。

    private static void ShowKeyboard()
    {
        var path64 = @"C:\Windows\winsxs\amd64_microsoft-windows-osk_31bf3856ad364e35_6.1.7600.16385_none_06b1c513739fb828\osk.exe";
        var path32 = @"C:\windows\system32\osk.exe";
        var path = (Environment.Is64BitOperatingSystem) ? path64 : path32;
        Process.Start(path);
    }

MTAスレッドからOSK.EXEを開始する必要があるフードの下で特定のことが起こっています。その理由は、その呼びかけのようです Wow64DisableWow64FsRedirection 現在のスレッドのみに影響します。ただし、特定の条件下では Process.Start 別のスレッドから新しいプロセスを作成します。 UseShellExecute falseに設定されており、STAスレッドから呼び出されたときにも設定されています。

以下のコードは、アパートの状態をチェックしてから、MTAスレッドから画面上のキーボードを起動してください。

using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;

class Program
{
    [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);


    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    static extern IntPtr SendMessage(IntPtr hWnd, 
        UInt32 Msg, 
        IntPtr wParam, 
        IntPtr lParam);
    private const UInt32 WM_SYSCOMMAND = 0x112;
    private const UInt32 SC_RESTORE = 0xf120;

    private const string OnScreenKeyboardExe = "osk.exe";

    [STAThread]
    static void Main(string[] args)
    {
        Process[] p = Process.GetProcessesByName(
            Path.GetFileNameWithoutExtension(OnScreenKeyboardExe));

        if (p.Length == 0)
        {
            // we must start osk from an MTA thread
            if (Thread.CurrentThread.GetApartmentState() == ApartmentState.STA)
            {
                ThreadStart start = new ThreadStart(StartOsk);
                Thread thread = new Thread(start);
                thread.SetApartmentState(ApartmentState.MTA);
                thread.Start();
                thread.Join();
            }
            else
            {
                StartOsk();
            }
        }
        else
        {
            // there might be a race condition if the process terminated 
            // meanwhile -> proper exception handling should be added
            //
            SendMessage(p[0].MainWindowHandle, 
                WM_SYSCOMMAND, new IntPtr(SC_RESTORE), new IntPtr(0));
        }
    }

    static void StartOsk()
    {
        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);
        }


        ProcessStartInfo psi = new ProcessStartInfo();
        psi.FileName = OnScreenKeyboardExe;
        // We must use ShellExecute to start osk from the current thread
        // with psi.UseShellExecute = false the CreateProcessWithLogon API 
        // would be used which handles process creation on a separate thread 
        // where the above call to Wow64DisableWow64FsRedirection would not 
        // have any effect.
        //
        psi.UseShellExecute = true;
        Process.Start(psi);

        // Re-enable directory virtualisation if it was disabled.
        if (System.Environment.Is64BitOperatingSystem)
            if (sucessfullyDisabledWow64Redirect)
                Wow64RevertWow64FsRedirection(ptr);
    }
}

不器用な方法:

このバッチファイルを側面で実行します(64ビットエクスプローラーから開始):

:lab0
TIMEOUT /T 1 >nul
if exist oskstart.tmp goto lab2
goto lab0
:lab2
del oskstart.tmp
osk
goto lab0

キーボードが必要なときにファイルoskstart.tmpを作成します

「画面上のキーボードを開始できなかった」と直面している人のために、プロジェクトのプラットフォームターゲットをCPUに変更します。

Cambiar Las Propeidades de laaplicación。 Compilar -DesMarcar Check Preferencia 32ビット。

App Propertys Compilaを変更 - 「ベスト32ビット」(または類似)のチェックを解除する

あなたはこれを読むことができます:

http://blog.anthonybaker.me/2012/08/spawning-windows-on-screen-keyboard-osk.html

または、メインアプリからこのオプションとランチ(実行)を使用して他のアプリを実行します。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top