如何模拟点击一个非当前窗口的外部程序的按钮,打开一个对话框,在对话框中输入字符串,并模拟点击对话框的“打开”按钮?
实际工作中需要编写一个程序,自动点击一个非当前窗口的外部程序mtsatDealProgram的“打开文件”按钮,以打开一个对话框,在这个对话框的“文件名”文本框中自动输入文件名字符串,再点击对话框中的“打开”按钮。一开始用api函数mouse_event、keybd_event和SendKeys类实现,但是这种方法要求外部程序mtsatDealProgram处于当前窗口状态,在实际应用时受到很多限制。
后来尝试用api函数SendMessage和PostMessage来实现这个功能,代码如下;public void Run(string _mtsatDealProgramPath,string _fileName)
{
//启动鼠标和键盘锁定
//this.EnableKeyBoardCapture();
//this.EnableMouseCapture();
//判断程序是否已经运行,如果没有则启动之
bool isRun = this.IsProgramAlreadyRunned();
if (!isRun)
{
this.RunProgram(_mtsatDealProgramPath);
//延迟两秒后继续执行
Thread.Sleep(2000);
}
//获得程序主窗体的句柄
int mtsatMainWindowHandle = GetProgramMainWindowHandle() ;
//使主窗体在所有窗体之前,为当前窗体
this.SetWindowToTopMost(mtsatMainWindowHandle);
//获取“打开文件”按钮控件的句柄
int buttonHandleOfOpenFile = this.GetButtonHandleOfOpenFile(mtsatMainWindowHandle);
//利用PostMessage函数将点击命令传递给“打开文件”按钮控件
//int lResult = SendMessage(buttonHandleOfOpenFile, BM_CLICK, 0, 0);
while (!PostMessage(buttonHandleOfOpenFile, BM_CLICK, 0, 0))
{
Thread.Sleep(100);
}
//延迟1.5秒后继续执行
Thread.Sleep(1500);
//获得“打开”对话框的句柄
int openFileDialogHandle = GetOpenFileDialogHandle(mtsatMainWindowHandle);
//获得输入文件名的文本框的句柄
int fileNameTextHandle = GetFileNameTextHandle(openFileDialogHandle);
//利用SendMessage函数把文件名传递给输入文件名的文本框
SendMessage(fileNameTextHandle, WM_SETTEXT, 0, _fileName);
//获得输入获得“打开”按钮的句柄
int openButtonHandle = GetOpenButtonHandle(openFileDialogHandle);
//利用SendMessage函数将点击命令传递给“打开”按钮
SendMessage(openButtonHandle, BM_CLICK, 0, 0);
//取消主窗体的顶层窗口状态
CancelWindowTopMost(mtsatMainWindowHandle);
//解除鼠标和键盘盘锁定
//this.DisableKeyBoardCapture();
//this.DisableMouseCapture();
}
但是同样有很多问题存在:
1、同样要求mtsatDealProgram处于当前窗口状态下,当mtsatDealProgram在非当前窗口状态下,有时候能正常运行,但更多时候在执行到
//利用PostMessage函数将点击命令传递给“打开文件”按钮控件
while (!PostMessage(buttonHandleOfOpenFile, BM_CLICK, 0, 0))
{
Thread.Sleep(100);
}
时就停住了,无法打开“打开”对话框,不知为何?
2、通过
//使主窗体在所有窗体之前,为当前窗体
this.SetWindowToTopMost(mtsatMainWindowHandle);
使程序运行时,mtsatDealProgram程序在当前窗口状态下,程序能正常运行。但是,只要过程中,人工移动鼠标,就会对程序造成影响,在执行到
//利用PostMessage函数将点击命令传递给“打开文件”按钮控件
while (!PostMessage(buttonHandleOfOpenFile, BM_CLICK, 0, 0))
{
Thread.Sleep(100);
}
时就停住了,无法打开“打开”对话框,这是什么原因那?
3、在将
while (!PostMessage(buttonHandleOfOpenFile, BM_CLICK, 0, 0))
{
Thread.Sleep(100);
}
处改用int lResult = SendMessage(buttonHandleOfOpenFile, BM_CLICK, 0, 0);
时,能够打开“打开”对话框,但程序无法执行下去,也即lResult无法获得返回值,只有手动将“打开”对话框关闭时,程序才能执行下去,但也就无法实现程序功能了。
4、//启动鼠标和键盘锁定
this.EnableKeyBoardCapture();
this.EnableMouseCapture();
执行这两句代码会造成1、2中问题,而且好像也没法锁死鼠标和键盘。EnableKeyBoardCapture()和EnableMouseCapture()这两个函数定义如下:
private bool EnableKeyBoardCapture()
{
KeyBoardHookProcedure = new HookProc(this.KeyBoardHookProc);
Process currentProcess = Process.GetCurrentProcess();
//安装全局键盘钩子
hhookKeyBoard = SetWindowsHookEx(WH_KEYBOARD, KeyBoardHookProcedure, currentProcess.MainModule.BaseAddress, 0);
if (hhookKeyBoard == 0)
return false;
return true;
}
private int KeyBoardHookProc(int nCode, IntPtr wParam, IntPtr lParam)
{
//如果nCode<0,直接调用CallNextHookEx返回
if (nCode < 0)
//return CallNextHookEx(hhookKeyBoard, nCode, wParam, lParam);
return 1;
//函数将消息向下传递,下一个钩子处理将截获这一消息
//if (nCode != HC_ACTION)
//return CallNextHookEx(hhookKeyBoard, nCode, wParam, lParam);
return 1;
}
private bool EnableMouseCapture()
{
MouseHookProcedure = new HookProc(this.MouseHookProc);
Process currentProcess = Process.GetCurrentProcess();
//安装全局鼠标钩子
hhookMouse = SetWindowsHookEx(WH_MOUSE, MouseHookProcedure, currentProcess.MainModule.BaseAddress, 0);
if (hhookMouse == 0)
return false;
return true;
}
private int MouseHookProc(int nCode, IntPtr wParam, IntPtr lParam)
{
//如果nCode<0,直接调用CallNextHookEx返回
if (nCode < 0)
//return CallNextHookEx(hhookMouse,nCode,wParam,lParam);
return 1;
//函数将消息向下传递,下一个钩子处理将截获这一消息
//if(nCode!= HC_ACTION)
// return CallNextHookEx(hhookMouse, nCode, wParam, lParam);
return 1;
}
5、要如何才能使外部程序mtsatDealProgram在处于非当前窗口状态时,实现自动打开的功能,不受其它事情(如有人在使用键盘、鼠标)的影响?
问题可能太多了,分不够另开贴给分,谢谢支持! --------------------编程问答-------------------- 这个问题太复杂了~~~
楼主可以尝试使用注入,注入程序去调用TranslateMessage函数。
另外你最好到VC板块去问问
.net里面做这方面的人比较少 --------------------编程问答-------------------- 变通的办法就是激活该窗口
然后发送消息
然后恢复原来的激活窗口
估计这么做你也不同意
呵呵 --------------------编程问答-------------------- 你可以给伴水发消息
他Delphi比较牛
应该做过类似的 --------------------编程问答-------------------- up --------------------编程问答-------------------- 没人吗?救命啊!
--------------------编程问答-------------------- lovefootball(蟑螂(生活就是扯淡--做人要放低姿态)) :
谢谢你的答复?注入程序从来没有接触过,需要哪些相关背景知识吗? --------------------编程问答-------------------- http://blog.csdn.net/NicX/archive/2007/08/02/1721980.aspx
看看这个 --------------------编程问答-------------------- FindWindow
SetForegroudWindow
--------------------编程问答-------------------- 不懂,路过,帮顶一下 --------------------编程问答-------------------- 注入程序好像很难哪!
如果非当前窗口状态实现不了的话,使用以下两个函数:
void SetWindowToTopMost(int _mainWindowHandle)
{
SetWindowPos(_mainWindowHandle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
}
void CancelWindowTopMost(int _mainWindowHandle)
{
SetWindowPos(_mainWindowHandle, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
}
来实现将非当前窗口设置为当前窗口。那么需要解决的一个问题是,在实现功能时必须排除键盘和鼠标输入的干扰。之前使用:
//启动鼠标和键盘锁定
this.EnableKeyBoardCapture();
this.EnableMouseCapture();
这段代码却没有把键盘、鼠标锁定,那如何才能锁定键盘、鼠标,又不影响SendMessage的使用? --------------------编程问答-------------------- up --------------------编程问答-------------------- 这不就是反射吗
有点自动化测试的意思
using System.Reflection; --------------------编程问答-------------------- 没有怎么明白,看样水还不事很深 --------------------编程问答-------------------- virusplayer() ,能说详细一点吗?mtsatDealProgram这个外部程序是用VC++写的。 --------------------编程问答-------------------- 如果你允许激活窗口的话
屏蔽鼠标
http://asp2net.net/Article/bianchengwenda/C/2007-5-28/2007052823264120.html
屏蔽键盘
http://topic.csdn.net/t/20020325/22/599562.html --------------------编程问答-------------------- 那就要用SPY++看看它的层次结构
然后初始化它,调用它 --------------------编程问答-------------------- 利用底层键盘钩子屏蔽任意按键
http://blog.csdn.net/goodname008/archive/2004/08/21/80827.aspx --------------------编程问答-------------------- using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Reflection;
namespace 鼠标键盘钩子实例
{
public partial class Form1 : Form
{
#region 锁定鼠标和键盘
//有关鼠标和键盘钩子的相关定义
static int hhookMouse = 0;
static int hhookKeyBoard = 0;
public const int WH_MOUSE_LL = 14;
private const int WH_KEYBOARD_LL = 13;
public const int HC_ACTION = 0;
public delegate int HookProc(int nCode, IntPtr wParam, IntPtr iParam);
HookProc MouseHookProcedure, KeyBoardHookProcedure;
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hinstance, int threadid);
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern int CallNextHookEx(int idHook, int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern bool UnhookWindowsHookEx(int idHook);
/// <summary>
/// 钩子处理方法(鼠标锁定)
/// </summary>
/// <param name="nCode"></param>
/// <param name="wParam"></param>
/// <param name="lParam"></param>
/// <returns></returns>
private int MouseHookProc(int nCode, IntPtr wParam, IntPtr lParam)
{
//如果nCode<0,直接调用CallNextHookEx返回
if (nCode < 0)
//return CallNextHookEx(hhookMouse,nCode,wParam,lParam);
return 1;
//函数将消息向下传递,下一个钩子处理将截获这一消息
//if(nCode!= HC_ACTION)
// return CallNextHookEx(hhookMouse, nCode, wParam, lParam);
return 1;
}
/// <summary>
/// 启动鼠标锁定
/// </summary>
/// <returns></returns>
private bool EnableMouseCapture()
{
MouseHookProcedure = new HookProc(this.MouseHookProc);
Process currentProcess = Process.GetCurrentProcess();
//安装全局鼠标钩子
hhookMouse = SetWindowsHookEx(WH_MOUSE_LL, MouseHookProcedure, currentProcess.MainModule.BaseAddress, 0);
if (hhookMouse == 0)
return false;
return true;
}
/// <summary>
/// 解除鼠标锁定
/// </summary>
/// <returns></returns>
private bool DisableMouseCapture()
{
return UnhookWindowsHookEx(hhookMouse);
}
/// <summary>
/// 钩子处理方法(键盘锁定)
/// </summary>
/// <param name="nCode"></param>
/// <param name="wParam"></param>
/// <param name="lParam"></param>
/// <returns></returns>
private int KeyBoardHookProc(int nCode, IntPtr wParam, IntPtr lParam)
{
//如果nCode<0,直接调用CallNextHookEx返回
if (nCode < 0)
return CallNextHookEx(hhookKeyBoard, nCode, wParam, lParam);
//return 1;
//函数将消息向下传递,下一个钩子处理将截获这一消息
if (nCode != HC_ACTION)
return CallNextHookEx(hhookKeyBoard, nCode, wParam, lParam);
return 1;
}
/// <summary>
/// 启动键盘锁定
/// </summary>
/// <returns></returns>
private bool EnableKeyBoardCapture()
{
KeyBoardHookProcedure = new HookProc(this.KeyBoardHookProc);
Process currentProcess = Process.GetCurrentProcess();
//安装全局键盘钩子
hhookKeyBoard = SetWindowsHookEx(WH_KEYBOARD_LL, KeyBoardHookProcedure, currentProcess.MainModule.BaseAddress, 0);
if (hhookKeyBoard == 0)
return false;
return true;
}
/// <summary>
/// 解除键盘锁定
/// </summary>
/// <returns></returns>
private bool DisableKeyBoardCapture()
{
return UnhookWindowsHookEx(hhookKeyBoard);
}
#endregion
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
EnableKeyBoardCapture();
EnableMouseCapture();
}
}
}
各位,上面这段代码单独试验过了,可行。但是把它合并到我的程序当中去就不行,具体表现在EnableMouseCapture()后,不能锁死鼠标,移动鼠标时,鼠标还是能跳跃式移动,但移动非常缓慢,不能完全锁死鼠标。 --------------------编程问答-------------------- 同时锁死鼠标后,对我的程序有影响,表现在PostMessage(buttonHandleOfOpenFile, BM_CLICK, 0, 0));不能起作用了。难道说通过PostMessage发送的BM_CLICK消息也被当作实体鼠标消息截获了? --------------------编程问答-------------------- 这几天都没人来看看吗?
看来我的问题是很难都能解决了!唉!
问题3、在将
while (!PostMessage(buttonHandleOfOpenFile, BM_CLICK, 0, 0))
{
Thread.Sleep(100);
}
处改用int lResult = SendMessage(buttonHandleOfOpenFile, BM_CLICK, 0, 0);
时,能够打开“打开”对话框,但程序无法执行下去,也即lResult无法获得返回值,只有手动将“打开”对话框关闭时,程序才能执行下去,但也就无法实现程序功能了!
这个问题有人知道是怎么回事吗?
我猜可能是SendMessage需要一个结果才能返回导致程序执行不下去,那是不是要对“打开”对话框进行某项操作才能使SendMessage有结果呢?! --------------------编程问答-------------------- 我向楼主请教一下,如果点击一个当前窗口按钮后弹出文件选择窗口,我想在这个对话框的“文件名”文本框中自动输入文件名字符串,再点击对话框中的“确认”按钮。 怎么做?我是一个新手,尝试了很多方法都不行.能给给例子吗?
补充:.NET技术 , C#