C#中用WinAPI调用外部程序

    在使用别人的程序时,我们常发现一些好的功能,想通过自己的程序来重复调用。可偏偏这个程序没有留可编程接口,无法通过API、DLL、COM等方式实现调用。早些年与同仁们讨论时,常对此深表遗憾。最近,通过研究Windows API的使用方法,终于从理论上解决了这一问题,即可通WinAPI中SendMessage、EnumChildWindows等,从模拟操作的角度来调用指定程序的指定功能。
    我们知道,Windows是消息驱动的,即Windows窗口、控件的任何操作,都是通过消息事件来完成的。从理论上讲,在我们自己的程序中,只要能准确地找到相应功能所在的窗口或控件的句柄Handle,发出相应的消息,即可完成相应任务。从这个层面上,这种技术可以应用在所有windows程序上。只是这种技术的处理,需要非常细心。因为在实际应用中,从某一个程序中找到相应的控件(包括Parent/Child/Next等)还是比较麻琐的,一不小心,调用的功能就实法实现,还有可能导致程序甚至系统的崩溃。所以,这种技术的关键在于两个地方:一是找准句柄,二是找对消息。
    推荐分析一个窗体(控件)的句柄或消息的工具:SPY++,这在Visual Studio Tools中有,操作起来很简单。

    C#中实现外部程序调用,可以通过封装User32.dll中sendmessage等函数来实现。我已将常用的功能封装成一个类:
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;


namespace MuliCall
{
    
class WinApi
    {
        
#region  宏定义

        
public const int WM_KEYDOWN = 0x100;
        
public const int WM_KEYUP = 0x101;
        
public const int VK_CONTROL = 0x11;
        
public const int VK_F5 = 0x74;
        
public const int KEYEVENTF_KEYUP = 0x2;
        
public const int VK_MENU = 0x12;
        
public const int WM_SETTEXT = 0xC;
        
public const int WM_CLEAR = 0x303;
        
public const int BN_CLICKED = 0;
        
public const int WM_LBUTTONDOWN = 0x201;
        
public const int WM_LBUTTONUP = 0x202;
        
public const int WM_CLOSE = 0x10;
        
public const int WM_COMMAND = 0x111;
        
public const int WM_SYSKEYDOWN = 0x104;

        
#endregion

        
public delegate bool EnumChildWindowsProc(IntPtr hwnd, int lParam);         

        
#region  WinAPI定义

        [DllImport(
"User32.dll", EntryPoint = "SendMessage")]
        
public static extern int SendMessage(
            
int hWnd, // handle to destination window 
            int Msg, // message 
            int wParam, // first message parameter 
             int lParam // second message parameter 
        );
        [DllImport(
"User32.dll", EntryPoint = "SendMessage")]
        
public static extern int SendTxtMessage(
            
int hWnd, // handle to destination window 
            int Msg, // message 
            int wParam, // first message parameter 
            char[] lParam
            
// int  lParam // second message parameter 
        );
        [DllImport(
"user32.dll", EntryPoint = "PostMessage")]
        
public static extern int PostMessage(
            
int hwnd,
            
int wMsg,
            
int wParam,
            
int lParam
        );

        [DllImport(
"user32.dll", EntryPoint = "FindWindow")]
        
public static extern int FindWindow(
            
string lpClassName,
            
string lpWindowName
        );
        [DllImport(
"user32.dll", EntryPoint = "FindWindowEx")]
        
public static extern int FindWindowEx(
            
int hwndParent,
            
int hwndChildAfter,
            
string lpszClass,
            
string lpszWindow
        );
        [DllImport(
"user32.dll", EntryPoint = "EnumChildWindows")]
        
public static extern int EnumChildWindows(
            
int hWndParent,
            
int lpEnumFunc,
            
int lParam
        );

        [DllImport(
"user32.dll", EntryPoint = "EnumChildWindows")]
        
public static extern int EnumChildWindows(
            
int hWndParent,
            EnumChildWindowsProc lpEnumFunc,
            
int lParam
        );

        [DllImport(
"user32.dll", EntryPoint = "SetFocus")]
        
public static extern int SetFocus(
            
int hWnd
        );

        [DllImport(
"user32.dll", EntryPoint = "SetWindowText")]
        
public static extern int SetWindowText(
            
int hwnd,
            
string lpString
        );

        [DllImport(
"user32.dll", EntryPoint = "keybd_event")]
        
public static extern void keybd_event(
            
byte bVk,
            
byte bScan,
            
int dwFlags,
            
int dwExtraInfo
        );

        [DllImport(
"user32.dll", EntryPoint = "SetForegroundWindow")]
        
public static extern int SetForegroundWindow(
            
int hwnd
        );

        [DllImport(
"user32.dll", EntryPoint = "GetClassName")]
        
public static extern int GetClassName(
            IntPtr hwnd,
            StringBuilder lpClassName,
            
int nMaxCount
        );
        [DllImport(
"user32.dll", EntryPoint = "GetWindowText")]
        
public static extern int GetWindowText(
            IntPtr hwnd,
            StringBuilder lpString,
            
int cch
        ); 

        
#endregion
 
        //综合处理全局HWD
        private static int CurrnetFormHandle = 0;
        
//综合处理函数

        
public static void SetCurrnetFormHandle(string strWindow)
        {
            SetCurrnetFormHandle(
null, strWindow, false);
        }
        
public static void SetCurrnetFormHandle(string strClass, string strWindow, bool beForeground)
        {
            CurrnetFormHandle 
= FindWindow(strClass, strWindow);
            
if (beForeground)
                SetForegroundWindow(CurrnetFormHandle);
        }
        
public static void SetCurrnetFormHandle(int hwd, bool beForeground)
        {
            CurrnetFormHandle 
= hwd;
            
if (beForeground)
                SetForegroundWindow(CurrnetFormHandle);
        }

        
public static void SetCurrnetFormHandle(int hwd)
        {
            CurrnetFormHandle
=hwd;
        }
        
public static int GetCurrentFormHandle()
        {
            
return CurrnetFormHandle;
        }

        
//模拟单击按钮
        public static void ClickButton(string strWindow)
        {
            ClickButton(
"Button", strWindow);
        }

        
public static void ClickButton(string strClass, string strWindow)
        {
            ClickButton(CurrnetFormHandle, 
0, strClass, strWindow);
        }

        
public static void ClickButton(int hwdParent, int hwndChildAfter, string strClass, string strWindow)
        {
            
int hwdButton = FindWindowEx(hwdParent, hwndChildAfter, strClass, strWindow);
            SendMessage(hwdButton, WM_LBUTTONDOWN, 
00);
            SendMessage(hwdButton, WM_LBUTTONUP, 
00);
        }

        
//修改文本框内容
        public static void SetWindowsText(string Parnet_strClass, string Parnet_strText, string strClass, string strText)
        {
            
int hwdParent = FindWindowEx(CurrnetFormHandle, 0, Parnet_strClass, Parnet_strText);

            
//停止 ThunderRT6OptionButton
            int bntHwd = FindWindowEx(hwdParent, 0"ThunderRT6OptionButton""停止");

            
int hwdText = FindWindowEx(hwdParent, bntHwd, strClass, null);  //ThunderRT6TextBox
            SendTxtMessage(hwdText, WM_SETTEXT, 0, strText.ToCharArray());
        }
        
public static void SetWindowsText(string strClass,string strText)
        {
            SetWindowsText( strClass, 
null, strText);
        }
        
public static void SetWindowsText( string strClass, string strWindow, string strText)
        {
            SetWindowsText(CurrnetFormHandle, 
0, strClass, strWindow, strText);
        }
        
public static void SetWindowsText(int hwdParent, int hwndChildAfter, string strClass, string strWindow, string strText)
        {
            
int hwdText = FindWindowEx(hwdParent, hwndChildAfter, strClass, strText);
            SendTxtMessage(hwdText, WM_SETTEXT, 
0, strText.ToCharArray());
        }

        
//搜索子窗体
        public static void SearchChild(string strWindow)
        {
            EnumChildWindowsProc myEnumChild 
= new EnumChildWindowsProc(EumWinChiPro);
            
try
            {
                EnumChildWindows(CurrnetFormHandle, myEnumChild, 
0);
            }
            
catch (Exception ex)
            {
                ;   
// MessageBox.Show(ex.Message + "\r\n" + ex.Source + "\r\n\r\n" + ex.StackTrace.ToString());
            }

        }

        
public static bool EumWinChiPro(IntPtr hWnd, int lParam)
        {
            StringBuilder s 
= new StringBuilder(1256);
            GetClassName(hWnd, s, 
1257);
            
string ss = s.ToString();
            
if (ss == null)
                ss 
= "";
            ss 
= ss.Trim();
    
//        MessageBox.Show(ss);
            
// ThunderRT6TextBox

            StringBuilder s2 
= new StringBuilder(1256);
            GetWindowText(hWnd, s2, 
1257);
            ss 
= s2.ToString(); 
            
return true;
        }
    }
}
    使用这个类,在自己的程序中,比较方便地实现外部程序的调用。
  int hwnd = (int)MainHandlArray[i];
 WinApi.SetCurrnetFormHandle(hwnd);
 WinApi.SetWindowsText(textBox_Class_EditPanel.Text, textBox_Title_EditPanel.ToString(), textBox_Class_Edit.Text, textBoxWorkID.Text);
    使用这种方法,我写个程序多开器,主要实现启动多个实例,能给EDIT框付值,能定时调用其中按钮。  

    多开程序下载



posted @ 2007-10-31 12:14  元宝  阅读(5500)  评论(3编辑  收藏  举报
我最爱的地质软件?!……