Pergunta

Como posso programaticamente (em C #) determinar, se outra aplicação externa (nativo, java, .NET ou qualquer outra coisa ...) está exigindo a entrada do usuário? isso pode ser feito totalmente em código gerenciado?

O que eu estou procurando é a implementação de:

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

Ao exigir a entrada do usuário que quero dizer quando um aplicativo pede ao usuário para inserir alguns dados ou sair uma mensagem de erro (diálogos modais) e não é capaz de desempenhar as suas tarefas normais anymore. Um aplicativo de desenho que está aguardando o usuário desenhar algo que não se quer dizer aqui.

PS: Depois de edições para refletir os comentários na parte inferior e fazer a preocupação mais clara, alguns comentários e respostas podem não ser 100% compatível com a pergunta. Leve isso em conta ao avaliar as respostas e observações.

Foi útil?

Solução

É no impossível geral. Tomemos por exemplo um tipo comum de aplicação, um processador de texto. Hoje em dia, que será executado verificação ortográfica em segundo plano, periodicamente auto-salva seu documento, etcetera. No entanto, a partir de uma perspectiva de usuários está esperando para a entrada de todo o tempo.

Outro caso comum seria um visualizador de slideshow. A qualquer momento no tempo, você poderia pressionar uma tecla para avançar um slide. No entanto, o usuário típico não iria ver isso como "aguardando entrada".

Para resumir:. "Aguardando entrada" é um estado subjetivo e, portanto, não pode ser determinado por meio de programação

Outras dicas

Como você gosta disso?

Eu trabalhei uma solução que parece funcionar, por favor avise-me em caso de problemas com este código para que eu também ganhar o benefício de melhorias. Ele trabalha para Excel, tanto quanto eu testei. O único problema que eu não gosto é que eu tive que usar chamadas não gerenciados. Ele também lida com o caso quando um aplicativo é baseado em um diálogo como para MFC, derivada de 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 eu entendi bem, você pode tentar enumerar tópicos do processo e verificar seus estados. O Windows Task Manager faz algo semelhante. Este, porém, exigirá funções Win32 - Thread32First e Thread32Next entre outros - mas você pode conseguir isto, o uso mais simples de P / Invoke em C #:

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

(assinatura Precise podem diferir).

EDIT: Ok., Não são funções correspondentes na biblioteca .NET

Se possível, reescrever o outro código para ser um processador de entrada em simultâneo (similar ao algoritmo para um servidor web concorrente):

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

É claro, você ainda pode ter sua função:

static Boolean IsWaitingForUserInput(String processName) {
    return true;
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top