Domanda

Come posso programmare (in C #) a livello di codice, se UN'ALTRA applicazione straniera (nativa, Java, .NET o altro ...) richiede attualmente input da parte dell'utente? Questo può essere fatto completamente nel codice gestito?

Quello che sto cercando è l'implementazione di:

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

Per richiesta di input dell'utente intendo quando un'applicazione chiede all'utente di inserire alcuni dati o uscire da un messaggio di errore (finestre di dialogo modali) e non è più in grado di svolgere le sue normali attività. Un'applicazione di disegno in attesa che l'utente disegni qualcosa non è qui.

PS: dopo le modifiche per riflettere i commenti in fondo e rendere più chiara la preoccupazione, alcuni commenti e risposte potrebbero non essere coerenti al 100% con la domanda. Tenerne conto durante la valutazione delle risposte e delle osservazioni.

È stato utile?

Soluzione

In generale è impossibile. Prendi ad esempio un tipo comune di applicazione, un elaboratore di testi. Oggi che eseguirà i controlli ortografici in background, salva periodicamente automaticamente il tuo documento, eccetera. Tuttavia, dal punto di vista degli utenti è in attesa di input in ogni momento.

Un altro caso comune sarebbe un visualizzatore di presentazioni. In qualsiasi momento puoi premere un tasto per avanzare di una diapositiva. Tuttavia, il tuo tipico utente non lo vedrebbe come "in attesa di input".

Per riassumere: " in attesa di input " è uno stato soggettivo e pertanto non può essere determinato a livello di programmazione.

Altri suggerimenti

Come ti piace questo?

Ho elaborato una soluzione che sembra funzionare, per favore avvisami in caso di problemi con questo codice in modo da ottenere anche dei miglioramenti. Funziona per Excel per quanto ho testato. L'unico problema che non mi piace è che ho dovuto usare chiamate non gestite. Gestisce anche il caso in cui un'applicazione si basa su una finestra di dialogo come per MFC, derivata da CDialog.

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;
        }
    }
}

Se ti capisco bene, potresti provare a enumerare i thread del processo e verificarne lo stato. Task Manager di Windows fa qualcosa di simile. Ciò richiederà tuttavia le funzioni Win32 - Thread32First e Thread32Next tra gli altri - ma puoi ottenerlo con l'uso più semplice di P / Invoke in C #:

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

(La firma precisa potrebbe essere diversa).

EDIT: Ok, ci sono funzioni corrispondenti nella libreria .NET.

Se possibile, riscrivi l'altro codice in modo che sia un processore di input simultaneo (simile all'algoritmo per un server Web concorrente):

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

Naturalmente, potresti comunque avere la tua funzione:

static Boolean IsWaitingForUserInput(String processName) {
    return true;
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top