我想模拟用户input到其他窗口可靠。 我为此使用sendinput ,但是之后我需要等到目标应用程序在发送更多消息之前处理input。 据我所知, sendinput ,尽pipe它的名字,真正的消息发送到队列,不等待,直到他们被处理。
我的尝试是基于这个想法,直到消息队列至less一次是空的。 因为我不能直接检查其他线程消息队列(至less我不知道这样做),所以我使用AttachThreadInput将目标线程的队列附加到该线程的队列,然后使用PeekMessage进行检查。
为了检查function,我使用一个窗口和一个button的小应用程序。 当点击button时,我调用Thread.Sleep(15000)有效地停止消息处理,从而确保在接下来的15s消息队列不能为空。
msdeploy和web deploy有什么区别?
自我安装的WInService
获取磁盘和/或具有未知文件格式的驱动器的大小,C#.NET框架?
是否有一个原因MailItem.display方法的z顺序行为不同机器?
检查另一个进程在.NET中是否具有pipe理员权限
public static void WaitForWindowInputIdle(IntPtr hwnd) { var currentThreadId = GetCurrentThreadId(); var targetThreadId = GetwindowThreadProcessId(hwnd,IntPtr.Zero); Func<bool> checkIfMessageQueueIsEmpty = () => { bool queueEmpty; bool threadsAttached = false; try { threadsAttached = AttachThreadInput(targetThreadId,currentThreadId,true); if (threadsAttached) { NativeMessage nm; queueEmpty = !PeekMessage(out nm,hwnd,RemoveMsg.PM_norEMOVE | RemoveMsg.PM_NOYIELD); } else throw new ThreadStateException("AttachThreadInput Failed."); } finally { if (threadsAttached) AttachThreadInput(targetThreadId,false); } return queueEmpty; }; var timeout = TimeSpan.FromMilliseconds(15000); var retryInterval = TimeSpan.FromMilliseconds(500); var start = DateTime.Now; while (DateTime.Now - start < timeout) { if (checkIfMessageQueueIsEmpty()) return; Thread.Sleep(retryInterval); } } [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] static extern bool PeekMessage(out NativeMessage lpMsg,IntPtr hWnd,uint wMsgFilterMin,uint wMsgFilterMax,RemoveMsg wRemoveMsg); [StructLayout(LayoutKind.Sequential)] public struct NativeMessage { public IntPtr handle; public uint msg; public IntPtr wParam; public IntPtr lParam; public uint time; public System.Drawing.Point p; } [Flags] private enum RemoveMsg : uint { PM_norEMOVE = 0x0000,PM_REMOVE = 0x0001,PM_NOYIELD = 0x0002,} [DllImport("user32.dll",SetLastError = true)] private static extern bool AttachThreadInput(uint idAttach,uint idAttachTo,bool fAttach); [DllImport("user32.dll")] private static extern uint GetwindowThreadProcessId(IntPtr hWnd,IntPtr processId); [DllImport("kernel32.dll")] private static extern uint GetCurrentThreadId();
现在,由于某种原因,这不起作用。 它始终返回消息队列为空。 有人知道我做错了什么,或者有其他的方法来实现我所需要的吗?
编辑:关于为什么我需要等待在第一个地方。 如果其他操作立即被模拟而没有暂停,我会遇到只有部分input文本的情况。 例如,当焦点位于某个文本框时,我通过sendinput模拟了“abcdefgh”,之后再点击一下鼠标。 我得到的是“abcde”input,然后点击。 如果我把sendinput后面的Thread.Sleep(100) – 这个问题在我的机器上是不可重现的,但是在低硬件的情况下在VM上很less重现。 所以我需要更可靠的方法来等待正确的时间。
我猜测可能发生的事情与TranslateMessage函数有关 :
将虚拟键消息转换为字符消息。 字符消息被发送到调用线程的消息队列,在下一次线程调用GetMessage或PeekMessage函数时读取。
所以,我给sendinput调用了“abcdefgh” – 一组input消息发布到线程队列中。 然后开始按FIFO顺序处理这些消息,翻译“abcde”,并将每个字符的消息发布到队列的尾部。 然后在“abcde”的字符消息之后模拟鼠标点击。 然后翻译完成,但翻译消息“fgh”发生在鼠标点击后。 最后,app看到“abcde”,然后点击“fgh” – 显然会出错
使用远程桌面的远程计算机的MachineName
向GAC注册/安装大会的“正确”方式是什么?
自动更新C#程序
Windows Server 2008上的最大tcp / ip连接
这是UI自动化中的常见需求。 它实际上是通过WindowPattern.WaitForInputIdle()方法在.NET中实现的。
你可以使用System.Windows.Automation命名空间来实现这个功能。 但是这个方法很容易实现。 您可以从Reference Source或反编译器中查看。 这让我很吃惊,但是看起来很稳定。 而不是试图猜测消息队列是否为空,它只是查看拥有该窗口的UI线程的状态。 如果它被阻塞,并且不等待内部系统操作,那么你有一个非常强烈的信号,即线程正在等待Windows传递下一条消息。 我是这样写的:
using namespace System.Diagnostics; ... public static bool WaitForInputIdle(IntPtr hWnd,int timeout = 0) { int pid; int tid = GetwindowThreadProcessId(hWnd,out pid); if (tid == 0) throw new ArgumentException("Window not found"); var tick = Environment.TickCount; do { if (IsThreadIdle(pid,tid)) return true; System.Threading.Thread.Sleep(15); } while (timeout > 0 && Environment.TickCount - tick < timeout); return false; } private static bool IsThreadIdle(int pid,int tid) { Process prc = System.Diagnostics.Process.GetProcessById(pid); var thr = prc.Threads.Cast<Processthread>().First((t) => tid == t.Id); return thr.ThreadState == ThreadState.Wait && thr.WaitReason == ThreadWaitReason.UserRequest; } [System.Runtime.InteropServices.DllImport("User32.dll")] private static extern int GetwindowThreadProcessId(IntPtr hWnd,out int pid);
调用sendinput()之前,在代码中调用WaitForInputIdle()。 你必须通过的窗口句柄是非常灵活的,只要窗口句柄由进程的UI线程拥有,窗口句柄就会执行。 Process.MainWindowHandle已经是一个非常好的候选人。 请注意,如果进程终止,该方法将抛出异常。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。