我正在製作一個應用程序,需要使用似乎不實現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()的神祕藝術中闡明我。
你是怎麼解決的?我正在使用PostMessage將密鑰發送到窗口。 – SMUsamaShah
@ LifeH2O可悲的是,我不認爲我曾經解決過它。要使用PostMessage,您的應用程序需要運行Windows事件循環,但是如果您嘗試與之交互的窗口沒有焦點,則IIRC根本無法工作。 – KappaG3