質問

他の外部アプリケーション(ネイティブ、java、.NETなど)が現在ユーザー入力を要求しているかどうかをプログラムで(C#で)判断するにはどうすればよいですか?マネージコードでこれを完全に行うことはできますか?

私が探しているのは、次の実装です:

static Boolean IsWaitingForUserInput(String processName)
{
    ???
}

ユーザー入力を要求するということは、アプリケーションがユーザーにデータの入力またはエラーメッセージの終了(モーダルダイアログ)を要求し、通常のタスクを実行できなくなることを意味します。ユーザーが何かを描くのを待っている描画アプリケーションは、ここでは意味がありません。

PS:下部のコメントを反映して懸念を明確にするために編集した後、一部のコメントと回答は質問と100%一致しない場合があります。回答と発言を評価するとき、これを考慮してください。

役に立ちましたか?

解決

それは一般的に不可能です。たとえば、一般的な種類のアプリケーションであるワープロを考えてみましょう。最近では、バックグラウンドでスペルチェックを実行しますが、定期的にドキュメントなどを自動保存します。しかし、ユーザーの観点からは、常に入力を待っています。

別の一般的なケースは、スライドショービューアです。いつでもキーを押してスライドを進めることができます。しかし、一般的なユーザーはこれを「入力待ち」とは見なしません。

要約すると:「入力待ち」主観的な状態であるため、プログラムで決定することはできません。

他のヒント

これはどうですか?

機能しているように見える解決策を作成しました。このコードに問題がある場合は通知してください。改善の恩恵も受けます。私がテストした限りでは、Excelで機能します。私が嫌いな唯一の問題は、アンマネージドコールを使用しなければならなかったことです。また、アプリケーションがCDialogから派生したMFCなどのダイアログに基づいている場合も処理します。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Threading;
using System.Diagnostics;

namespace Util
{
    public class ModalChecker
    {
        public static Boolean IsWaitingForUserInput(String processName)
        {
            Process[] processes = Process.GetProcessesByName(processName);
            if (processes.Length == 0)
                throw new Exception("No process found matching the search criteria");
            if (processes.Length > 1)
                throw new Exception("More than one process found matching the search criteria");
            // for thread safety
            ModalChecker checker = new ModalChecker(processes[0]);
            return checker.WaitingForUserInput;
        }

        #region Native Windows Stuff
        private const int WS_EX_DLGMODALFRAME = 0x00000001;
        private const int GWL_EXSTYLE = (-20);
        private delegate int EnumWindowsProc(IntPtr hWnd, int lParam);
        [DllImport("user32")]
        private extern static int EnumWindows(EnumWindowsProc lpEnumFunc, int lParam);
        [DllImport("user32", CharSet = CharSet.Auto)]
        private extern static uint GetWindowLong(IntPtr hWnd, int nIndex);
        [DllImport("user32")]
        private extern static uint GetWindowThreadProcessId(IntPtr hWnd, out IntPtr lpdwProcessId);
        #endregion

        // The process we want the info from
        private Process _process;
        private Boolean _waiting;

        private ModalChecker(Process process)
        {
            _process = process;
            _waiting = false; //default
        }

        private Boolean WaitingForUserInput
        {
            get
            {
                EnumWindows(new EnumWindowsProc(this.WindowEnum), 0);
                return _waiting;
            }
        }

        private int WindowEnum(IntPtr hWnd, int lParam)
        {
            if (hWnd == _process.MainWindowHandle)
                return 1;
            IntPtr processId;
            GetWindowThreadProcessId(hWnd, out processId);
            if (processId.ToInt32() != _process.Id)
                return 1;
            uint style = GetWindowLong(hWnd, GWL_EXSTYLE);
            if ((style & WS_EX_DLGMODALFRAME) != 0)
            {
                _waiting = true;
                return 0; // stop searching further
            }
            return 1;
        }
    }
}

あなたのことをよく理解しているなら、プロセスのスレッドを列挙して、その状態を確認してみてください。 Windowsタスクマネージャーも同様の処理を行います。ただし、これにはWin32関数-とりわけThread32FirstおよびThread32Nextが必要になりますが、C#でP / Invokeを最も簡単に使用することでこれを実現できます。

    [DllImport("Executor.dll")]
    public static extern bool Thread32First(IntPtr handle, IntPtr threadEntry32);

(正確な署名は異なる場合があります)。

編集:OK、.NETライブラリには対応する関数があります。

可能であれば、他のコードを並行入力プロセッサーに書き換えます(並行Webサーバーのアルゴリズムと同様):

Wait for input
Fork process
  Parent: Repeat
  Child: (Worker) handle input

もちろん、あなたはまだあなたの機能を持つことができます:

static Boolean IsWaitingForUserInput(String processName) {
    return true;
}
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top