控制其他程序按钮?? 我想写个程序控制其他程序的按钮,但是目标程序每次启动后系统给按钮分配的句柄都是不同的,所以保存句柄好像是行不通的。该怎么办????? 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 你可以调用API试试但是比较麻烦先获得对象窗体句柄 FindWindow最得到要控制的按钮的句柄 GetChildWindows(这个我记不准了,总之你能得到按钮句柄)让然后再在自己的程序中调用PostMessage大体就是这个意思,我没对.NET程序测试过,应该也可以的,都是消息循环么。 楼主去看看C#提供的UIAutomation的类 里面就已经提供了相应的方法了 例子:using System.Runtime.InteropServices;[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 );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, 0, null, "3" ); //获取按钮3 的句柄 IntPtr hwndPlus = FindWindowEx ( hwndCalc, 0, null, "+" ); //获取按钮 + 的句柄 IntPtr hwndTwo = FindWindowEx ( hwndCalc, 0, null, "2" ); //获取按钮2 的句柄 IntPtr hwndEqual = FindWindowEx ( hwndCalc, 0, null, "=" ); //获取按钮= 的句柄 SetForegroundWindow ( hwndCalc ); //将计算器设为当前活动窗口 System.Threading.Thread.Sleep ( 2000 ); //暂停2秒让你看到效果 SendMessage ( hwndThree, BM_CLICK, 0, 0 ); System.Threading.Thread.Sleep ( 2000 ); //暂停2秒让你看到效果 SendMessage ( hwndPlus, BM_CLICK, 0, 0 ); System.Threading.Thread.Sleep ( 2000 ); //暂停2秒让你看到效果 SendMessage ( hwndTwo, BM_CLICK, 0, 0 ); System.Threading.Thread.Sleep ( 2000 ); //暂停2秒让你看到效果 SendMessage ( hwndEqual, BM_CLICK, 0, 0 ); System.Threading.Thread.Sleep ( 2000 ); MessageBox.Show ("你看到结果了吗?"); } else { MessageBox.Show ("没有启动 [计算器]"); }} C# Readprocessmemory用法 C# GetWindowRect用法C# SendMessage用法程序编程 2010-11-28 10:01:54 阅读143 评论0 字号:大中小 订阅 函数功能:该函数将指定的消息发送到一个或多个窗口。此函数为指定的窗口调用窗口程序,直到窗口程序处理完消息再返回。该函数是应用程序和应用程序之间进行消息传递的主要手段之一。 函数原型:LRESULT SendMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM IParam); 参数: hWnd:其窗口程序将接收消息的窗口的句柄。如果此参数为HWND_BROADCAST,则消息将被发送到系统中所有顶层窗口,包括无效或不可见的非自身拥有的窗口、被覆盖的窗口和弹出式窗口,但消息不被发送到子窗口。 Msg:指定被发送的消息。 wParam:指定附加的消息指定信息。 IParam:指定附加的消息指定信息。 返回值:返回值指定消息处理的结果,依赖于所发送的消息。 备注:需要用HWND_BROADCAST通信的应用程序应当使用函数RegisterWindowMessage来为应用程序间的通信取得一个唯一的消息。 如果指定的窗口是由调用线程创建的,则窗口程序立即作为子程序调用。如果指定的窗口是由不同线程创建的,则系统切换到该线程并调用恰当的窗口程序。线程间的消息只有在线程执行消息检索代码时才被处理。发送线程被阻塞直到接收线程处理完消息为止。C#中使用该函数首先导入命名空间:using System.Runtime.InteropServices; 然后写API引用部分的代码,放入 class 内部[DllImport("user32.dll", EntryPoint = "SendMessage")]private static extern int SendMessage(IntPtr hwnd, int wMsg, int wParam, int lParam); 这个函数有四个参数,第一个是窗口句柄,窗口可以是任何类型的屏幕对象;第二个是用于区别其他消息的常量值;第三个通常是一个与消息有关的常量值,也可能是窗口或控件的句柄,第三个参数是可选参数,有的消息要,有的不需要,比如单击就不需要这个参数,别的消息,比如鼠标移动的可能需要在这里加上一些鼠标的参数;第四个通常是一个指向内存中数据的指针。在C#中消息需要定义成windows系统中的原始的16进制数字,比如 const int WM_Lbutton = 0x201; //定义了鼠标的左键点击消息。详细值在最后。例如:const int BM_CLICK = 0xF5;IntPtr maindHwnd = FindWindow(null, "QQ用户登录"); //获得QQ登陆框的句柄if (maindHwnd != IntPtr.Zero){ IntPtr childHwnd = FindWindowEx(maindHwnd, IntPtr.Zero, null, "登录"); //获得按钮的句柄 if (childHwnd != IntPtr.Zero) { SendMessage(childHwnd, BM_CLICK, 0, 0); //发送点击按钮的消息 } else { MessageBox.Show("没有找到子窗口"); }}else{ MessageBox.Show("没有找到窗口");} IntPtr hwndThree = FindWindowEx ( hwndCalc, 0, null, "3" ); //获取按钮3 的句柄 IntPtr hwndPlus = FindWindowEx ( hwndCalc, 0, null, "+" ); //获取按钮 + 的句柄 IntPtr hwndTwo = FindWindowEx ( hwndCalc, 0, null, "2" ); //获取按钮2 的句柄 IntPtr hwndEqual = FindWindowEx ( hwndCalc, 0, null, "=" ); //获取按钮= 的句柄你这个是已经知道那个按钮叫"3"、"2",但有的窗体控件根本就不知道它叫什么。那怎么办? 你有目标程序吗?运行它,试着用spy++探测一下。要想操作他,就得了解他,必须的。 就拿千千静听来说吧 我想控制播放 暂停 IntPtr WinHandle = proc.MainWindowHandle;//取窗体句柄 EnumChildWindow ecw = new EnumChildWindow(EnumChild); ApiFunction.EnumChildWindows(WinHandle, ecw, ""); //枚举窗体 private bool EnumChild(IntPtr handle, string num) { StringBuilder Title = new StringBuilder(); StringBuilder Type = new StringBuilder(); Title.Length = 100; Type.Length = 100; ApiFunction.GetWindowText(handle, Title, 100);//取Title ApiFunction.GetClassName(handle, Type, 100);//取类型 return true; }这是我自己写的枚举窗体控件。当枚举千千静听或酷狗时 跟本就获取不到title 这样就变成需要人为的去辨别按钮的功能,我是想第一次识别出各按钮功能后,生成配置文件下次就由程序自动识别了。但配置文件该保存什么呢?如果有title的按钮还好办,那没有title的按钮该怎么办? 千千静听我没控制过,我以前(很久很久了)控制过winamp(好像是这么拼的吧,也是播放MP3的)。你可以发送虚拟键,发快捷键。 我也很想知道答案。帮楼主顶吧!以下纯猜测想象:第一要得到控件的ID,因为控件是资源,它是编译时就已经存在的了。比如 #define IDC_DATA_TXT 10011001是在编译时确定的,不是运行时,所以它是固定的。第二得到控件所在窗体的句柄FindWindow得不到,你可以通过进程名,那个一定是固定的。第三hText = GetDlgItem(hMyWnd,IDC_DATA_TXT);得到句柄IDC_DATA_TXT是你第一得到的ID,hMyWnd是第二得到的窗体句柄。第四有了hText 你可发消息。我记得有写资源编辑器可以得到第一里提到的ID纯想象 对于句柄来说每次是不同的,但对于有些属性却是相同的,例如Text 用spy++探测,控件有类名的,相同的控件有相同的类名另外通过GetDlgCtrlID取得的id,在相同的千千静听版本中是绝对不会改变的,通常版本换了改变的可能性也很小你可以通过保留此ID,用来识别它们。通常用这种方法控制人家的窗口,你必须非常了解它才行 嗯 对啊 好像用这种方法控制其他程序的窗口不好用,例如我枚举酷狗的所有控件,结果出现的都是panel控件,根本就找不到button,还以为是自己枚举程序有问题,用UISpy.exe试下也一样。不知道有没有其他更好的办法。 嗯 对啊 好像用这种方法控制其他程序的窗口不好用,例如我枚举酷狗的所有控件,结果出现的都是panel控件,根本就找不到button,还以为是自己枚举程序有问题,用UISpy.exe试下也一样。不知道有没有其他更好的办法。 房主评价下我20楼的看法,有什么不妥。不太明白你的意思,我让你通过资源编辑器,取得ID,你怎么说到枚举上了。那就接着你的说。你得到panel是很正常的。人家做软件的时候一定方了panel,因为好布局么。在panel里放的才有可能是按钮,你第一此掉GetChildWindow得到的是panle你在用panel作为父窗体调用GetChildWindow就可以枚举到了啊。递归 不太明白你的意思,我让你通过资源编辑器,取得ID,你怎么说到枚举上了。那就接着你的说。你得到panel是很正常的。人家做软件的时候一定方了panel,因为好布局么。在panel里放的才有可能是按钮,你第一此掉GetChildWindow得到的是panle你在用panel作为父窗体调用GetChildWindow就可以枚举到了啊。递归我用的就是递归,但是就是找不到button。所以我觉得用这个办法控制窗体控件不通用。不过我又想到了另一个解决方案,那就是通过录制操作来控制,就跟按键精灵那样。 那对象窗口拉伸,缩放了还能行吗?没用过按键精灵。我比较期待hText = GetDlgItem(hMyWnd,IDC_DATA_TXT);呵呵你继续努力,我得下班了。 那对象窗口拉伸,缩放了还能行吗?没用过按键精灵。我比较期待hText = GetDlgItem(hMyWnd,IDC_DATA_TXT);呵呵你继续努力,我得下班了。这个我早料到了,那就是录制操作时记录窗体大小以及位置,要控制的时候按配置设置窗体的大小及位置即可。 DevExpress GridControl 问题 异步向站外URL Post数据,根据返回值再做数据库操作,怎么写? 我在管理多线程的时候碰到的问题,应该很普遍,大家进来看看. SQlserver2000中的中文显示问题 请教一个字符传输出的问题,急 读取xml文件??谢谢 我该怎么建立DATAGRID的分页功能呢?有源代码. 网页和Word文档的缩略图如何实现? 图片显示问题 在c#中怎样实现两个应用程序之间通信? Font到底是什么? 关于动态数组的实现关于自己的想法
但是比较麻烦
先获得对象窗体句柄 FindWindow
最得到要控制的按钮的句柄 GetChildWindows(这个我记不准了,总之你能得到按钮句柄)
让然后再在自己的程序中调用PostMessage大体就是这个意思,我没对.NET程序测试过,应该也可以的,都是消息循环么。
[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 );
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, 0, null, "3" ); //获取按钮3 的句柄 IntPtr hwndPlus = FindWindowEx ( hwndCalc, 0, null, "+" ); //获取按钮 + 的句柄
IntPtr hwndTwo = FindWindowEx ( hwndCalc, 0, null, "2" ); //获取按钮2 的句柄
IntPtr hwndEqual = FindWindowEx ( hwndCalc, 0, null, "=" ); //获取按钮= 的句柄
SetForegroundWindow ( hwndCalc ); //将计算器设为当前活动窗口
System.Threading.Thread.Sleep ( 2000 ); //暂停2秒让你看到效果
SendMessage ( hwndThree, BM_CLICK, 0, 0 );
System.Threading.Thread.Sleep ( 2000 ); //暂停2秒让你看到效果
SendMessage ( hwndPlus, BM_CLICK, 0, 0 );
System.Threading.Thread.Sleep ( 2000 ); //暂停2秒让你看到效果
SendMessage ( hwndTwo, BM_CLICK, 0, 0 );
System.Threading.Thread.Sleep ( 2000 ); //暂停2秒让你看到效果
SendMessage ( hwndEqual, BM_CLICK, 0, 0 ); System.Threading.Thread.Sleep ( 2000 );
MessageBox.Show ("你看到结果了吗?");
}
else
{
MessageBox.Show ("没有启动 [计算器]");
}
} C# Readprocessmemory用法 C# GetWindowRect用法
C# SendMessage用法程序编程 2010-11-28 10:01:54 阅读143 评论0 字号:大中小 订阅
函数功能:该函数将指定的消息发送到一个或多个窗口。此函数为指定的窗口调用窗口程序,直到窗口程序处理完消息再返回。该函数是应用程序和应用程序之间进行消息传递的主要手段之一。
函数原型:LRESULT SendMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM IParam); 参数: hWnd:其窗口程序将接收消息的窗口的句柄。如果此参数为HWND_BROADCAST,则消息将被发送到系统中所有顶层窗口,包括无效或不可见的非自身拥有的窗口、被覆盖的窗口和弹出式窗口,但消息不被发送到子窗口。 Msg:指定被发送的消息。 wParam:指定附加的消息指定信息。 IParam:指定附加的消息指定信息。 返回值:返回值指定消息处理的结果,依赖于所发送的消息。 备注:需要用HWND_BROADCAST通信的应用程序应当使用函数RegisterWindowMessage来为应用程序间的通信取得一个唯一的消息。 如果指定的窗口是由调用线程创建的,则窗口程序立即作为子程序调用。如果指定的窗口是由不同线程创建的,则系统切换到该线程并调用恰当的窗口程序。线程间的消息只有在线程执行消息检索代码时才被处理。发送线程被阻塞直到接收线程处理完消息为止。C#中使用该函数首先导入命名空间:
using System.Runtime.InteropServices; 然后写API引用部分的代码,放入 class 内部
[DllImport("user32.dll", EntryPoint = "SendMessage")]
private static extern int SendMessage(IntPtr hwnd, int wMsg, int wParam, int lParam); 这个函数有四个参数,第一个是窗口句柄,窗口可以是任何类型的屏幕对象;第二个是用于区别其他消息的常量值;第三个通常是一个与消息有关的常量值,也可能是窗口或控件的句柄,第三个参数是可选参数,有的消息要,有的不需要,比如单击就不需要这个参数,
别的消息,比如鼠标移动的可能需要在这里加上一些鼠标的参数;第四个通常是一个指向内存中数据的指针。在C#中消息需要定义成windows系统中的原始的16进制数字,比如 const int WM_Lbutton = 0x201; //定义了鼠标的左键点击消息。详细值在最后。例如:
const int BM_CLICK = 0xF5;
IntPtr maindHwnd = FindWindow(null, "QQ用户登录"); //获得QQ登陆框的句柄
if (maindHwnd != IntPtr.Zero)
{
IntPtr childHwnd = FindWindowEx(maindHwnd, IntPtr.Zero, null, "登录"); //获得按钮的句柄
if (childHwnd != IntPtr.Zero)
{
SendMessage(childHwnd, BM_CLICK, 0, 0); //发送点击按钮的消息
}
else
{
MessageBox.Show("没有找到子窗口");
}
}
else
{
MessageBox.Show("没有找到窗口");
}
IntPtr hwndTwo = FindWindowEx ( hwndCalc, 0, null, "2" ); //获取按钮2 的句柄
IntPtr hwndEqual = FindWindowEx ( hwndCalc, 0, null, "=" ); //获取按钮= 的句柄
你这个是已经知道那个按钮叫"3"、"2",但有的窗体控件根本就不知道它叫什么。那怎么办?
你有目标程序吗?运行它,试着用spy++探测一下。
要想操作他,就得了解他,必须的。
IntPtr WinHandle = proc.MainWindowHandle;//取窗体句柄
EnumChildWindow ecw = new EnumChildWindow(EnumChild);
ApiFunction.EnumChildWindows(WinHandle, ecw, ""); //枚举窗体
private bool EnumChild(IntPtr handle, string num)
{
StringBuilder Title = new StringBuilder();
StringBuilder Type = new StringBuilder(); Title.Length = 100;
Type.Length = 100;
ApiFunction.GetWindowText(handle, Title, 100);//取Title
ApiFunction.GetClassName(handle, Type, 100);//取类型
return true;
}这是我自己写的枚举窗体控件。
当枚举千千静听或酷狗时 跟本就获取不到title
帮楼主顶吧!
以下纯猜测想象:
第一要得到控件的ID,因为控件是资源,它是编译时就已经存在的了。
比如 #define IDC_DATA_TXT 1001
1001是在编译时确定的,不是运行时,所以它是固定的。
第二得到控件所在窗体的句柄FindWindow得不到,你可以通过进程名,那个一定是固定的。
第三hText = GetDlgItem(hMyWnd,IDC_DATA_TXT);得到句柄
IDC_DATA_TXT是你第一得到的ID,hMyWnd是第二得到的窗体句柄。
第四有了hText 你可发消息。我记得有写资源编辑器可以得到第一里提到的ID纯想象
用spy++探测,控件有类名的,相同的控件有相同的类名
另外通过GetDlgCtrlID取得的id,在相同的千千静听版本中是绝对不会改变的,
通常版本换了改变的可能性也很小
你可以通过保留此ID,用来识别它们。
通常用这种方法控制人家的窗口,你必须非常了解它才行
不知道有没有其他更好的办法。
不知道有没有其他更好的办法。
不太明白你的意思,我让你通过资源编辑器,取得ID,你怎么说到枚举上了。
那就接着你的说。
你得到panel是很正常的。
人家做软件的时候一定方了panel,因为好布局么。
在panel里放的才有可能是按钮,
你第一此掉GetChildWindow得到的是panle
你在用panel作为父窗体调用GetChildWindow就可以枚举到了啊。
递归
那就接着你的说。
你得到panel是很正常的。
人家做软件的时候一定方了panel,因为好布局么。
在panel里放的才有可能是按钮,
你第一此掉GetChildWindow得到的是panle
你在用panel作为父窗体调用GetChildWindow就可以枚举到了啊。
递归
我用的就是递归,但是就是找不到button。
所以我觉得用这个办法控制窗体控件不通用。不过我又想到了另一个解决方案,那就是通过录制操作来控制,就跟按键精灵那样。
没用过按键精灵。
我比较期待hText = GetDlgItem(hMyWnd,IDC_DATA_TXT);
呵呵
你继续努力,我得下班了。
没用过按键精灵。
我比较期待hText = GetDlgItem(hMyWnd,IDC_DATA_TXT);
呵呵
你继续努力,我得下班了。这个我早料到了,那就是录制操作时记录窗体大小以及位置,要控制的时候按配置设置窗体的大小及位置即可。