7

グローバル ホットキーを登録するための C# API を作成する必要があります。WM_HOTKEY メッセージを受信するには、 を使用し、 を使用しSystem.Windows.Forms.NativeWindowて独自のメッセージ ループを実行しますSystem.Windows.Forms.Application.Run(ApplicationContext)。ユーザーがホットキーを登録したい場合、RegisterHotkey()でメッセージ ループを停止し、 (P/Invoke) 関数でホットキーを登録して、メッセージ ループを再開System.Windows.Forms.ApplicationContext.ExitThread()するというメソッドを実行する必要があります。ウィンドウを作成したのと同じスレッド内で呼び出す必要があり、メッセージ ループを実行する同じスレッド内で再度インスタンス化する必要があるRegisterHotKey()ため、これが必要です。RegisterHotKey()

問題は、ユーザーがRegisterHotkey()メッセージ ループを実行しているスレッドを開始した直後にメソッドを呼び出すと、そのApplicationContext.ExitThread()前に呼び出されるApplication.Run(ApplicationContext)ため、アプリケーションが無期限にブロックされることです。メッセージループが開始されるのを待つためのアプローチを知っている人はいますか?

前もって感謝します!

4

4 に答える 4

5

そのRegisterHotKeyため、ウィンドウを作成してメッセージ ループを開始したのと同じスレッドから呼び出す必要があります。の実行をRegisterHotKeyカスタム メッセージ ループ スレッドに挿入してみませんか? そうすれば、メッセージ ループを停止して再開する必要がなくなります。最初に開始したものを再利用すると同時に、奇妙な競合状態を回避できます。

インスタンスISynchronizeInvoke.Invokeをホストするスレッドにそのデリゲートをマーシャリングするを使用して、別のスレッドにデリゲートを挿入できます。ISynchronizeInvokeこれがどのように行われるかです。

void Main()
{
  var f = new Form();

  // Start your custom message loop here.
  new Thread(
    () =>
    {
      var nw = NativeWindow.FromHandle(f.Handle);
      Application.Run(new ApplicationContext(f));
    }

  // This can be called from any thread.
  f.Invoke(
    (Action)(() =>
    {
      RegisterHotKey(/*...*/);
    }), null);
}

わかりません...あなたが求めてUnregisterHotKeyいる行動によっては、あなたも電話したくなるかもしれません。私はこれらの API にあまり詳しくないので、それらがどのように使用されるかについてコメントすることはできません。

その任意のインスタンスを作成したくない場合は、メソッドが自動的に提供するのと同じ効果を得るために、カスタムメッセージをスレッドなどに送信して処理することでFormおそらく逃げることができます。SendMessageNativeWindow.WndProcISynchronizeInvoke

于 2011-09-12T19:58:00.057 に答える
1

より良い方法があるかどうかはわかりませんが、を使用して、Mutex呼び出すときにリセットし、を呼び出すときに使用Application.Runすることができます。Mutex.Wait()Applicationcontext.ExitThread()

于 2011-09-12T19:04:00.397 に答える
1

Application.Idle イベントが発生するまで待って、ユーザーが RegisterHotKey を呼び出せるようにすることもできます。

于 2011-09-12T19:12:06.547 に答える
0

このスレッドが古いことは知っていますが、問題を解決しようとしてここに来て、受け入れられた回答を見て時間を費やしました。もちろん基本的には正しいのですが、このままではコードがコンパイルされず、作成したスレッドが起動せず、修正しても f が作成される前に f.Invoke を呼び出すため、例外がスローされます。

私はそれをすべて修正し、作業コードを以下に示します。回答のコメントに入れたかったのですが、十分な担当者がいません。それを行った後、この方法で Application.Run を呼び出す前にフォームを強制的に作成すること、またはあるスレッドで「新しいフォーム」を実行してから別のスレッドに渡して完全に作成することの妥当性について少し確信が持てません(特にこれは簡単に回避できるため):

static void Main(string[] args)
{
    AutoResetEvent are = new AutoResetEvent(false);
    Form f = new Form();
    Console.WriteLine(Thread.CurrentThread.ManagedThreadId);

    new Thread(
        () =>
        {
            Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
            var nw = NativeWindow.FromHandle(f.Handle);
            are.Set();
            Application.Run(f);
        }).Start();

    are.WaitOne(new TimeSpan(0, 0, 2));

    f.Invoke(
        (Action)(() =>
        {
            Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
        }), null);

    Console.ReadLine();
}
于 2016-01-17T13:53:20.900 に答える