当前位置:编程学习 > C#/ASP.NET >>

如何模拟点击一个非当前窗口的外部程序的按钮,打开一个对话框,在对话框中输入字符串,并模拟点击对话框的“打开”按钮?

实际工作中需要编写一个程序,自动点击一个非当前窗口的外部程序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#
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,