2009-09-10 34 views
5

Làm thế nào tôi có thể lập trình (trong C#) xác định, nếu ứng dụng nước ngoài KHÁC (bản địa, java, .NET hoặc bất cứ điều gì ...) hiện đang yêu cầu đầu vào của người dùng? Điều này có thể được thực hiện đầy đủ trong mã được quản lý không?Tìm hiểu lập trình nếu quá trình yêu cầu người dùng nhập

Những gì tôi đang tìm kiếm là việc thực hiện:

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

Bằng cách yêu cầu đầu vào người sử dụng tôi có nghĩa là khi một ứng dụng yêu cầu người dùng nhập vào một số dữ liệu hoặc bỏ một thông báo lỗi (hộp thoại Modal) chứ không phải là có thể thực hiện các tác vụ bình thường của nó nữa. Một ứng dụng vẽ đang chờ người dùng vẽ thứ gì đó không có nghĩa là ở đây.

PS: Sau khi chỉnh sửa để phản ánh các nhận xét ở dưới cùng và làm cho mối quan tâm rõ ràng hơn, một số nhận xét và câu trả lời có thể không phù hợp 100% với câu hỏi. Hãy tính đến điều này khi đánh giá các câu trả lời và nhận xét.

+0

Bạn có thể xác định "đang chờ người dùng nhập" trong ứng dụng GUI không? Là một cú click chuột không phải là đầu vào của người dùng? –

+0

Bằng cách đợi đầu vào của người dùng, tôi có nghĩa là mọi thứ đã làm cho công cụ của bên thứ ba tự động tiếp tục công việc của mình.Điều này bao gồm việc chờ bỏ một hộp thoại (giống như hộp thông báo lỗi trong hầu hết các trường hợp của chúng tôi) – jdehaan

+0

Tôi hiểu rõ bạn rằng "công cụ của bên thứ ba" và "ứng dụng nước ngoài KHÁC" đều tham chiếu đến cùng một ứng dụng, có trạng thái bạn muốn kiểm tra? –

Trả lời

9

Nói chung là không thể. Lấy ví dụ một loại ứng dụng phổ biến, một trình xử lý văn bản. Ngày nay sẽ chạy kiểm tra chính tả trong nền, nó định kỳ tự động lưu tài liệu của bạn, v.v. Tuy nhiên, từ góc nhìn của người dùng, nó luôn chờ đầu vào.

Một trường hợp phổ biến khác sẽ là trình xem trình chiếu. Bất cứ lúc nào bạn cũng có thể nhấn một phím để mở một trang trình bày. Tuy nhiên, người dùng thông thường của bạn sẽ không xem điều này là "đang chờ đầu vào".

Để tóm tắt: "đang chờ đầu vào" là trạng thái chủ quan và do đó không thể được xác định theo chương trình.

+0

không thể giải quyết theo nghĩa chung. Mô hình áp dụng sẽ là một chiến lược; bạn phải xác định cách kiểm tra từng ứng dụng bạn cần để giải quyết vấn đề này và tìm ra điều gì cấu thành trạng thái "chờ người dùng nhập". Là một trong những câu trả lời khác cho câu hỏi này cho thấy, nó có thể được giải quyết cho Excel bằng cách sử dụng một hộp thoại phương thức để "yêu cầu" đầu vào của người dùng. –

+0

Impossible là không có gì ;-) Tôi đồng ý đó là vấn đề về định nghĩa. Tôi viết lại câu hỏi để chính xác hơn, có những cách tiếp cận dứt khoát để giải quyết vấn đề như vấn đề tôi đăng (tốt nhất tôi có thể và tôi hài lòng với nó) – jdehaan

+0

không có gì là không thể trong hầu hết các câu hỏi này. Chỉ có "làm thế nào xấu bạn muốn điều này" –

0

Nếu tôi hiểu rõ bạn, bạn có thể thử liệt kê các chủ đề của quy trình và kiểm tra trạng thái của chúng. Trình quản lý tác vụ Windows thực hiện tương tự. tuy nhiên điều này sẽ đòi hỏi chức năng Win32 - Thread32First và Thread32Next số những người khác - nhưng bạn có thể đạt được điều này bằng cách sử dụng đơn giản nhất của P/Invoke trong C#:

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

(chữ ký chính xác có thể khác nhau).

EDIT: Ok, có các hàm tương ứng trong thư viện .NET.

+0

Liệt kê các chủ đề và kiểm tra trạng thái của chúng là chưa đủ, như MSalters nhận xét, Input-Idle là trạng thái mà ứng dụng xử lý các thông điệp, không thực sự 100% báo hiệu nhu cầu về đầu vào từ người dùng. – jdehaan

3

Bạn thích điều này như thế nào?

Tôi đã tìm ra giải pháp có vẻ hoạt động, vui lòng thông báo cho tôi trong trường hợp có vấn đề với mã này để tôi cũng có được lợi ích của các cải tiến. Nó hoạt động cho Excel như xa như tôi đã thử nghiệm. Vấn đề duy nhất tôi không thích là tôi phải sử dụng các cuộc gọi không được quản lý. Nó cũng xử lý các trường hợp khi một ứng dụng dựa trên một hộp thoại như cho MFC, bắt nguồn từ 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

đây có lẽ là định nghĩa duy nhất của "chờ người dùng nhập". một hộp thoại phương thức. có lẽ chúng ta nên gọi nó là "yêu cầu người dùng nhập" – slf

+0

Ý tưởng hay! Tôi biết điều này ít nhiều là vấn đề về định nghĩa. Đoạn mã này hy vọng là cơ sở tốt cho những người khác muốn làm điều tương tự. – jdehaan

+0

Một nhược điểm của nó là nó bỏ lỡ phát hiện của một trình gỡ lỗi jit kích hoạt ... Bất kỳ ý tưởng để giải quyết nó (không chỉ cho một trình gỡ lỗi jit đặc biệt)? – jdehaan

0

Nếu có thể, viết lại các mã khác là một bộ xử lý đồng thời đầu vào (tương tự như thuật toán cho một máy chủ web cùng lúc):

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

Tất nhiên, bạn vẫn có thể có chức năng của bạn:

static Boolean IsWaitingForUserInput(String processName) { 
    return true; 
} 
Các vấn đề liên quan