我们知道,Windows是消息驱动的,即Windows窗口、控件的任何操作,都是通过消息事件来完成的。从理论上讲,在我们自己的程序中,只要能准确地找到相应功能所在的窗口或控件的句柄Handle,发出相应的消息,即可完成相应任务。从这个层面上,这种技术可以应用在所有windows程序上。只是这种技术的处理,需要非常细心。因为在实际应用中,从某一个程序中找到相应的控件(包括Parent/Child/Next等)还是比较麻琐的,一不小心,调用的功能就实法实现,还有可能导致程序甚至系统的崩溃。所以,这种技术的关键在于两个地方:一是找准句柄,二是找对消息。
推荐分析一个窗体(控件)的句柄或消息的工具:SPY++,这在Visual Studio Tools中有,操作起来很简单。
![](https://i-blog.csdnimg.cn/blog_migrate/0cec163e05c698dc020f82e91dfa6500.jpeg)
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, 0 , 0 );
SendMessage(hwdButton, WM_LBUTTONUP, 0 , 0 );
}
// 修改文本框内容
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 ;
}
}
}
使用这个类,在自己的程序中,比较方便地实现外部程序的调用。
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, 0 , 0 );
SendMessage(hwdButton, WM_LBUTTONUP, 0 , 0 );
}
// 修改文本框内容
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框付值,能定时调用其中按钮。
WinApi.SetCurrnetFormHandle(hwnd);
WinApi.SetWindowsText(textBox_Class_EditPanel.Text, textBox_Title_EditPanel.ToString(), textBox_Class_Edit.Text, textBoxWorkID.Text);
多开程序下载