用C#操作API实现填写桌面窗体内的textbox,并点击窗体内按钮
不对啊。我sendmessage()函数里面msg是被传送的内容,最后两个参数是什么?
新的问题又来了,游戏是用DirectX写的,有遮罩层,我找到了文本框的句柄也写进去内容了,但是发送的按钮是画上去的,我取鼠标坐标取到了也能点该区域,但是我怎么通过句柄获得这个坐标呢?不同屏显不同尺寸怎么才能都合适?以哪个句柄窗体为主为好?是最近的一个还是说第一个? 展开
首先通俗地讲:wparam和lparam是sendmessage的两个参数。也就是说,它会随着wMsg所代表的消息的不同而不同,所以理解起来有一定的难度。
我想你的疑问来自于API定义里面的WPARAM wParam,LPARAM IParam吧
WPARAM 和LPARAM 这两个结构体在C#中没有定义(这也是C#操作API不方便的诸多地方之一,很多结构都需要转换成C#相应类型,这大大提高了C#操作API的入门难度)。下表的内容对你用C#掉API有帮助:
C++ 输入输出 C#
==================================
char chr[255] O StringBuilder
KCA_DIR I int
LPCSTR I string
int I int
LPSTR O StringBuilder
int* O out int
DWORD I int
DWORD* O out int
BOOL I bool
Rc_DBMgr I IntPtr
long* O out long
继续说明这两个参数使用场合,一下举例:
1、向某窗口发送一个WM_SETTEXT消息,获得该窗口的文本
string tempstr = "要设置的值";
SendMessage(hWnd,WM_SETTEXT,IntPtr.Zero,tempstr);
说明:WM_SETTEXT是设置文本消息,相应地, 此时的lParam为要设置的值,wParam参数不需要我们给IntPtr.Zero。
2、向某控件发送一个BM_CLICK消息
SendMessage(hWnd,BM_CLICK,IntPtr.Zero,IntPtr.Zero)
说明:BM_CLICK此时的wParam和lParam均没有作用,所以为IntPtr.Zero
如果你抽时间多了解一下API的话会发现这两个结构体使用频率很高。不用多想,就当做两个普通结构来对待就可以。上表的结构在转C#类型的时候不需要开发人员去处理,这种转换在C#进行调用的时候是自动进行的。
上面几位已经把获得窗口句柄讲的很详细了,我就不再费口舌了。
如果仍有疑问可以联系我。
------------------------------------------------------------
恩,果然遇到我最担心的问题了,看来躲是躲不掉,呵呵。
引用前辈们的解决方法吧:
1.打开要操作的程序
2.把这个程序窗口置顶!也就算是激活了(主窗口的句柄你可以得到!)
3.获得这个窗口在屏幕上的位置信息(程序窗口左上角的坐标值)
设为(x,y)
4.获得你要操作的按钮在窗口上的坐标信息(a,b),那么这个按钮在整个屏幕里的坐标值就是(x+a,y+b)
5.移动鼠标到(x+a,y+b)这个位置!
6.模拟单击
补充:第4步中的a和b的值你可能不能得到,因为你得不到按钮的句柄,但是你可以打开那个程序,然后用qq截图功能从窗口的左上角开始拖拉鼠标,直到移动到按钮的中间位置,这时候,左上角有截图大小信息,也就是坐标信息了! 这样我们就可以估算一个坐标值,把它付给a和b! 呵呵!就达到我们的目的了!
使用findwindows(string winclass,string wintitle)来返回句柄
然后使用sendMessage();函数发消息驱动键盘输入或者点击button来发送。
填写textbox,首先用API FindWindow 查找窗口,然后用API FindWindowEx 查找textbox的句柄,你可以用Spy++查看一下窗口的结构,类名之类的信息用来查找。然后用API SendMessage发送一个SendMessage 发送一个 WM_SETTEXT,声明这个API的时候把最后一个参数类型声明成StringBuilder吧(没试验过)或者用API SetWindowText设置内容。
点击按钮那个,用同样的方法找到按钮的句柄,然后SendMessage发送一个WM_LBUTTONUP 消息。
下面是整个程序的部分,查找窗体并对它进行操作
private int SearchWindow()
{
int retval = 0; //增加一个返回值用来判断操作是否成功
//下面的这些参数都可以用Spy++查到
string lpszParentClass = "#32770"; //整个窗口的类名
string lpszParentWindow = "本地连接"; //窗口标题
string lpszClass = "Edit"; //需要查找的子窗口的类名,也就是输入框
string lpszClass_Submit = "Button"; //需要查找的Button的类名
string lpszName_Submit = "确定"; //需要查找的Button的标题
string text = "";
IntPtr ParenthWnd = new IntPtr(0);
IntPtr EdithWnd = new IntPtr(0);
//查到窗体,得到整个窗体
ParenthWnd = FindWindow(lpszParentClass,lpszParentWindow);
//判断这个窗体是否有效
if (!ParenthWnd.Equals(IntPtr.Zero))
{
//得到User Name这个子窗体,并设置其内容
EdithWnd = FindWindowEx(ParenthWnd,EdithWnd,lpszClass,"");
if (!EdithWnd.Equals(IntPtr.Zero))
{
text = this.tbUserName.Text.Trim();
//调用SendMessage方法设置其内容
SendMessage(EdithWnd, WM_SETTEXT, (IntPtr)0, text);
retval ++;
}
//得到Password这个子窗体,并设置其内容
EdithWnd = FindWindowEx(ParenthWnd,EdithWnd,lpszClass,"");
if (!EdithWnd.Equals(IntPtr.Zero))
{
text = this.tbPassword.Text.Trim();
SendMessage(EdithWnd, WM_SETTEXT, (IntPtr)0, text);
retval ++;
}
//得到Domain这个子窗体,并设置其内容
EdithWnd = FindWindowEx(ParenthWnd,EdithWnd,lpszClass,"");
if (!EdithWnd.Equals(IntPtr.Zero))
{
text = this.tbDomain.Text.Trim();
SendMessage(EdithWnd, WM_SETTEXT, (IntPtr)0, text);
retval ++;
}
//得到Button这个子窗体,并触发它的Click事件
EdithWnd = FindWindowEx(ParenthWnd,
EdithWnd,lpszClass_Submit,lpszName_Submit);
if (!EdithWnd.Equals(IntPtr.Zero))
{
SendMessage(EdithWnd,WM_CLICK,(IntPtr)0,"0");
retval ++;
}
}
return retval;
}
里面有调用API给窗口textbox赋值的方法,很详细,有问题再咨询我