c# - SendInput not working after attaching thread input to a target process -
i'm making application needs work ui of program doesn't seem implement ui automation elements (inspect.exe shows main pane , no children).
so researched best ways implement features need were, , found sendinput(), apparently newer version of keybd_event() , mouse_event().
however, since requires keyboard focus , since can't afford set target window foreground (to avoid bothering user while runs), kept searching until found this answer. did skurmedel said, , joined application's thread target's window thread. now, if setfocus() target , sendinput(), target window won't affected.
my question either "why doesn't work?" or "what doing wrong?", guess code example sorting out:
threadhandler class
class threadhandler { #region p/invoking , 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 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 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 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 stringbuilder function storage unit stringbuilder namebuffer = new stringbuilder(64); foreach (var hwnd in handles) { //and compare caption of window requested name namebuffer.clear(); sendmessage(hwnd, wm_gettext, namebuffer.capacity, namebuffer); if (namebuffer.tostring() == windowname) { return new object[2] { getwindowthreadprocessid(hwnd), hwnd }; } } } return null; } }
main method of application
static void main(string[] args) { console.writeline("please input name of process hook: "); string pname = console.readline(); console.writeline("input name of specific window, or leave blank: "); string pwnd = console.readline(); threadhandler threadhandler; try { if(!string.isnullorwhitespace(pwnd)) threadhandler = new threadhandler(pname, pwnd); else threadhandler = new threadhandler(pname); } catch { console.writeline("error: " + pname +" not seem running."); console.readkey(); return; } if (!threadhandler.attachthreadinput()) { console.writeline("error: application tried attach input processing mechanism " + threadhandler.processname + ", failed."); console.readkey(); return; } console.writeline("input processing mechanism correctly attached " + threadhandler.processname + "."); threadhandler.setfocus(); inputsimulator.simulatetextentry("test"); //inputsimulator seemingly famous sendinput wrapper. replacing line code keystroke doesn't work. console.readline(); console.writeline("detaching input processing mechanism."); threadhandler.detachthreadinput(); }
thanks in advance if can elucidate me on arcane arts of sendinput().
make sure specific control sending keystrokes focused.
you should able use setfocus give focus control sending keystrokes to.
sendmessage , postmessage can used send keystrokes, it's bad practice , should avoided.
check out system.windows.forms.sendkeys information on sending keystrokes though forms class in .net.
in lot of cases, if don't need keystrokes themselves, can change text on window using sendmessage wm_settext if you're looking do.
Comments
Post a Comment