• C#用 SendKyes 结合 Process 或 API FindWindow、SendMessage(PostMessage) 等控制外部程序[转]


    首页,要说明几个概念:

    • Win32 平台是 消息驱动模式
    • .Net 框架是 事件驱动模式
    • 标题所指的 “控制外部程序”,外部程序是指与本程序无内在相关性的另外一个程序

     基于上面提到的,对于.NET的winform程序,在默认情况下(即未对接收消息的事件做自定义处理,说白了:就是没有 重写/覆写(override)窗体(Form)的DefWndProc 事件),.Net 的 winform 程序,是不响应所接收到的自定义消息的。

    我们这里要讨论的内容,就分为两种情况:

    1. C#/.NET的程序,控制外部的 win32程序(win16不做考虑)
    2. C#/.NET的程序,控制外部的 .NET程序

    从标题,大家也看到, C# 对外部程序的控制, 我们也分为两种情况来讨论:

    1. .NET 平台自带的 SendKeys 和 Process 结合的方式
    2. 完全利用 Windows API 的消息机制 的方式

    一、.NET平台自带的 Process 和 SendKeys 结合的方式

    本例子,用 C# 的一个Winform程序,创建一个指定路径的文本文件,写入某些内容后,并保存。

    为了看清效果,将 Form 的 TopMost 设为 true

    Code
      private void button1_Click( object sender, EventArgs e )
      {
          
    //启动notepad.exe 记事本程序,并在d:\下创建 或 打开 text_test.txt文件
          System.Diagnostics.Process txt = System.Diagnostics.Process.Start ( @"notepad.exe"@"d:\text_test.txt" );
          txt.StartInfo.WindowStyle 
    = ProcessWindowStyle.Normal;

          
    //等待一秒,以便目标程序notepad.exe输入状态就绪
          txt.WaitForInputIdle ( 1000 );

          
    //如果目标程序 notepad.exe 没有停止响应,则继续
          if ( txt.Responding )
          {
            
    //开始写入内容
            SendKeys.SendWait ( "-----下面的内容是外部程序自动写入-----\r\n" );

            SendKeys.SendWait ( 
    this.textBox1.Text );     //将文本框内的内容写入

            SendKeys.SendWait ( 
    "{Enter}{Enter}" );     //写入2个回车
            SendKeys.SendWait ( "文档创建时间:" );
            SendKeys.SendWait ( 
    "{F5}" );          //发送F5按键
            SendKeys.SendWait ("{Enter}");       //发送回车键
            SendKeys.SendWait ( "^s" );       //发送 Ctrl + s 键
            SendKeys.SendWait ( "%{F4}" );      // 发送 Alt + F4 键

            MessageBox.Show (
    "文件已经保存成功!");
          }
      }

     

    注: SendKeys 发送的按键的接收窗体,必须是当前的活动窗体

    二、C# 利用 Windows API 控制 外部的 win32 程序

    我们这里,用控制 “计算器”程序,算一个 3 + 2 = 5 的算式来做示例。

    API 中我们要用到的函数有 FindWindowFindWindowExSendMessageSetForegroundWindow

    对于API的引用方法,大家去看 API 手册,我这里提供一个VB自带的API查询程序

    要使用API,需要引入命名空间

     

    Code
    using System.Runtime.InteropServices;

     

    下面的API引用部分的代码,放入 class 内部

     

    Code
    [DllImport ( "user32.dll", EntryPoint = "FindWindow", SetLastError = true )]
    private static extern IntPtr FindWindow( string lpClassName, string lpWindowName );

    [DllImport ( 
    "user32.dll", EntryPoint = "FindWindowEx", SetLastError = true )]
    private static extern IntPtr FindWindowEx( IntPtr hwndParent, uint hwndChildAfter, string lpszClass, string lpszWindow );

    [DllImport ( 
    "user32.dll", EntryPoint = "SendMessage", SetLastError = true, CharSet = CharSet.Auto )]
    private static extern int SendMessage( IntPtr hwnd, uint wMsg, int wParam, int lParam );

    [DllImport ( 
    "user32.dll", EntryPoint = "SetForegroundWindow", SetLastError = true )]
    private static extern void SetForegroundWindow( IntPtr hwnd );

     

    Code
    private void button1_Click( object sender, EventArgs e )
    {
        
    const uint BM_CLICK = 0xF5//鼠标点击的消息,对于各种消息的数值,大家还是得去API手册

        IntPtr hwndCalc 
    = FindWindow ( null"计算器" ); //查找计算器的句柄

        
    if ( hwndCalc != IntPtr.Zero )
        {
        IntPtr hwndThree 
    = FindWindowEx ( hwndCalc, 0null"3" ); //获取按钮3 的句柄

        IntPtr hwndPlus 
    = FindWindowEx ( hwndCalc, 0null"+" );  //获取按钮 + 的句柄
        IntPtr hwndTwo = FindWindowEx ( hwndCalc, 0null"2" );  //获取按钮2 的句柄
        IntPtr hwndEqual = FindWindowEx ( hwndCalc, 0null"=" ); //获取按钮= 的句柄
        SetForegroundWindow ( hwndCalc );    //将计算器设为当前活动窗口
        System.Threading.Thread.Sleep ( 2000 );   //暂停2秒让你看到效果
        SendMessage ( hwndThree, BM_CLICK, 00 );
        System.Threading.Thread.Sleep ( 
    2000 );   //暂停2秒让你看到效果
        SendMessage ( hwndPlus, BM_CLICK, 00 );
        System.Threading.Thread.Sleep ( 
    2000 );   //暂停2秒让你看到效果
        SendMessage ( hwndTwo, BM_CLICK, 00 );
        System.Threading.Thread.Sleep ( 
    2000 );   //暂停2秒让你看到效果
        SendMessage ( hwndEqual, BM_CLICK, 00 );

        System.Threading.Thread.Sleep ( 
    2000 );
        MessageBox.Show (
    "你看到结果了吗?");
        }
        
    else
        {
        MessageBox.Show (
    "没有启动 [计算器]");
        }
    }
  • 相关阅读:
    P3396 哈希冲突 TJ
    U135884 膜法问题 TJ
    U135075 简单数列 TJ
    U135649 皇室战争 TJ
    SF&SJJG-ST表
    牛客NOIP集训三S 牛半仙的妹子数 TJ
    UVA297 四分树 Quadtrees TJ
    UVA679 小球下落 Dropping Balls TJ
    [ACM] CF水题记
    Hoppz的收藏夹
  • 原文地址:https://www.cnblogs.com/sofire/p/1760698.html
Copyright © 2020-2023  润新知