2009-09-10 11 views
5

Come faccio a livello di codice (in C#) stabilire, se un'altra domanda estera (nativo, Java, .NET o qualsiasi altra cosa ...) è attualmente esigente input dell'utente? Questo può essere fatto completamente nel codice gestito?Scopri di programmazione se un processo è esigente input dell'utente

Quello che sto cercando è la realizzazione di:

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

Chiedendo l'input dell'utente che intendo quando un'applicazione richiede all'utente di inserire alcuni dati o uscire un messaggio di errore (le finestre di dialogo modale) e non è in grado di svolgere i suoi compiti normali più. Un'applicazione di disegno che attende che l'utente disegni qualcosa non è qui intesa.

PS: Dopo le modifiche in modo da riflettere i commenti in fondo e fare la preoccupazione più chiara, alcuni commenti e le risposte non possono essere al 100% in linea con la domanda. Prendi questo in considerazione quando valuti le risposte e le osservazioni.

+0

È possibile definire "in attesa di input dell'utente" in un'applicazione GUI? È un clic del mouse non anche l'input dell'utente? –

+0

Attendendo l'input dell'utente, intendo tutto ciò che imputa lo strumento di terze parti a proseguire automaticamente con il suo lavoro.Ciò include l'attesa per chiudere una finestra di dialogo (come una finestra di messaggio di errore nella maggior parte dei nostri casi) – jdehaan

+0

Ti capisco bene, che "lo strumento di terze parti" e "Un'altra domanda straniera" si riferiscono entrambi alla stessa applicazione, il cui stato vuoi controllare? –

risposta

9

In generale è impossibile. Prendiamo ad esempio un tipo comune di applicazione, un word processor. Al giorno d'oggi che esegue controlli ortografici in background, salva automaticamente il tuo documento, eccetera. Eppure dal punto di vista degli utenti è in attesa di input tutto il tempo.

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

In sintesi: "in attesa di input" è uno stato soggettivo e quindi non può essere determinata a livello di codice.

+0

impossibile da risolvere in senso generale. Il modello da applicare sarebbe una strategia; dovresti determinare come esaminare ciascuna applicazione di cui hai bisogno per risolvere questo problema e capire cosa costituisce uno stato di "attesa per l'input da parte dell'utente". Come mostra una delle altre risposte a questa domanda, Excel può essere risolto utilizzando una finestra di dialogo modale per "richiedere" l'input dell'utente. –

+0

Impossibile è nulla ;-) Sono d'accordo è una questione di definizione. Ho riscritto la domanda per essere più precisa, ci sono approcci definitivamente per risolvere il problema come quello che ho postato (il meglio che ho potuto ottenere e ne sono felice) – jdehaan

+0

non è impossibile nella maggior parte di queste domande. C'è solo "quanto male vuoi questo" –

0

Se ho capito bene, si può tentare di enumerare le discussioni del processo e controllare i loro stati. Task Manager di Windows fa qualcosa di simile. Questo però richiede funzioni Win32 - Thread32First e Thread32Next tra gli altri - ma è possibile raggiungere questo obiettivo con l'uso più semplice di P/Invoke in C#:

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

(firma precisa può differire).

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

+0

L'enumerazione dei thread e il controllo del loro stato non erano sufficienti, come osservato da MSalters, Input-Idle è lo stato in cui l'applicazione elabora i messaggi, non proprio al 100% che segnala una richiesta di input da parte dell'utente. – jdehaan

3

Come ti piace?

ho elaborato una soluzione che sembra funzionare, per favore mi notifica in caso di problemi con questo codice così ho anche ottenere beneficio di miglioramenti. Funziona per Excel per quanto ho provato. L'unico problema che non mi piace è che ho dovuto usare chiamate non gestite. Gestisce anche il caso quando 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; 
     } 
    } 
} 
+1

questa è probabilmente l'unica definizione di "attesa dell'input dell'utente" che è valida. una finestra di dialogo modale. dovremmo probabilmente chiamarlo "input utente esigente" – slf

+0

Buona idea! So che questo era più o meno importante per definizione. Si spera che questo pezzo di codice sia una buona base per altre persone che vogliono fare la stessa cosa. – jdehaan

+0

Uno svantaggio è che manca il rilevamento di un debugger jit attivato ... Qualche idea per risolverlo (non solo per uno speciale debugger jit)? – jdehaan

0

Se possibile, riscrivere il altro codice di essere un processore concomitante di ingresso (simile al algoritmo per un web server concorrente):

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

Naturalmente, si potrebbe avere ancora la funzione:

static Boolean IsWaitingForUserInput(String processName) { 
    return true; 
} 
Problemi correlati