2013-07-17 72 views
0

我正在製作一個應用程序,需要使用似乎不實現UI自動化元素的程序的UI(Inspect.Exe僅顯示主窗格和沒有孩子)。將線程輸入附加到目標進程後,SendInput不工作

因此,我研究了實現我需要的功能的最佳方法,並找到了SendInput(),它顯然是keybd_event()和mouse_event()的更新版本。但是,由於它需要鍵盤焦點,並且由於我無法將目標窗口設置爲前景(爲了避免在運行時困擾用戶),我一直在搜索,直到找到this answer。我做了什麼Skurmedel說,並加入我的應用程序的線程到目標的窗口線程。但是現在,即使我將SetFocus()設置爲目標,然後是SendInput(),目標窗口也不會受到影響。

我的問題要麼是「爲什麼這不工作?」或 「我是什麼做錯了嗎?」,但我想一個代碼示例將幫助整理了這一點:

ThreadHandler類

class ThreadHandler 
{ 
    #region P/Invoking and constants definition 
    const uint WM_GETTEXT = 0x000D; 

    [DllImport("user32.dll")] 
    static extern IntPtr SetFocus(IntPtr hWnd); 

    [DllImport("user32.dll")] 
    private static extern int GetWindowThreadProcessId(IntPtr hWnd, uint lpdwProcessId = 0); 

    delegate bool EnumThreadDelegate(IntPtr hWnd, IntPtr lParam); 
    [DllImport("user32.dll")] 
    static extern bool EnumThreadWindows(int dwThreadId, EnumThreadDelegate lpfn, 
     IntPtr lParam); 

    [DllImport("user32.dll")] 
    static extern bool AttachThreadInput(int idAttach, int idAttachTo, bool fAttach); 

    [DllImport("kernel32.dll")] 
    static extern int GetCurrentThreadId(); 

    [DllImport("user32.dll", CharSet = CharSet.Auto)] 
    static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, int wParam, StringBuilder lParam); 

    #endregion 

    public readonly string ProcessName, WindowName; 
    protected readonly int TargetThreadID, CurrentThreadID; 
    protected readonly IntPtr TargetWindowHandle; 

    public ThreadHandler(string processName, string windowName) 
    { 
     CurrentThreadID = GetCurrentThreadId(); 
     ProcessName = processName; 
     WindowName = windowName; 

     object[] objs = GetWindowThread(processName, windowName); 
     if (objs == null) 
     { 
      throw new ArgumentException("Could not find the specified process/window."); 
     } 

     TargetThreadID = (int)objs[0]; 
     TargetWindowHandle = (IntPtr)objs[1]; 
    } 

    public ThreadHandler(string processName) 
    { 
     CurrentThreadID = GetCurrentThreadId(); 
     ProcessName = processName; 

     var processes = Process.GetProcessesByName(ProcessName); 
     if (processes.Length == 0) 
     { 
      throw new ArgumentException("Could not find the specified process."); 
     } 
     var appProc = processes[0]; 

     WindowName = appProc.MainWindowTitle; 
     TargetThreadID = GetWindowThreadProcessId(appProc.MainWindowHandle); 
     TargetWindowHandle = appProc.MainWindowHandle; 
    } 

    public bool AttachThreadInput() 
    { 
     return AttachThreadInput(CurrentThreadID, TargetThreadID, true); 
    } 

    public bool DetachThreadInput() 
    { 
     return AttachThreadInput(CurrentThreadID, TargetThreadID, false); 
    } 

    public void SetFocus() 
    { 
     SetFocus(TargetWindowHandle); 
    } 

    static object[] GetWindowThread(string processName, string windowName) 
    { 
     var processes = Process.GetProcessesByName(processName); 
     if (processes.Length > 0) 
     { 
      //Fill a list of handles 
      var handles = new List<IntPtr>(); 
      foreach (ProcessThread thread in processes[0].Threads) 
       EnumThreadWindows(thread.Id, 
        (hWnd, lParam) => { handles.Add(hWnd); return true; }, IntPtr.Zero); 

      //Create a stringbuilder to function as storage unit 
      StringBuilder nameBuffer = new StringBuilder(64); 
      foreach (var hWnd in handles) 
      { 
       //And finally compare the caption of the window with the requested name 
       nameBuffer.Clear(); 
       SendMessage(hWnd, WM_GETTEXT, nameBuffer.Capacity, nameBuffer); 
       if (nameBuffer.ToString() == windowName) 
       { 
        return new object[2] { GetWindowThreadProcessId(hWnd), hWnd }; 
       } 
      } 
     } 
     return null; 
    } 
} 

應用的主要方法

在此先感謝您,如果您可以在SendInput()的神祕藝術中闡明我。

+0

你是怎麼解決的?我正在使用PostMessage將密鑰發送到窗口。 – SMUsamaShah

+0

@ LifeH2O可悲的是,我不認爲我曾經解決過它。要使用PostMessage,您的應用程序需要運行Windows事件循環,但是如果您嘗試與之交互的窗口沒有焦點,則IIRC根本無法工作。 – KappaG3

回答

1

確保您正在發送擊鍵的特定控件已正確聚焦。

您應該能夠使用SetFocus來關注您要發送按鍵的控件。

SendMessagePostMessage也可以用來發送擊鍵,但它是BAD PRACTICE,應該避免。

有關通過.NET中的Forms類發送鍵擊的信息,請參閱System.Windows.Forms.SendKeys

在很多情況下,如果您自己不需要按鍵,則只需使用SendMessageWM_SETTEXT即可更改窗口上的文本,如果這是您期望的操作。

+0

我正在做記事本的測試,顯然它不起作用。我會嘗試使用SendKeys並回報。編輯:我認爲你以意想不到的方式幫助了我。調用Send方法會導致以下異常: 由於應用程序未處理Windows消息,SendKeys無法在此應用程序內運行。請將應用程序更改爲處理消息,或使用SendKeys.SendWait方法。 我認爲是這個問題。 – KappaG3

+0

韋爾普,看來我是對的。我只是將我的代碼移植到Windows Form項目中,並且工作正常。我會感謝您的答覆,但是,SetFocus不僅僅是設置鍵盤焦點,還會將目標窗口帶到前臺。猜猜我回到了根零。 – KappaG3