不太明白,一般登录界面上不都有几个复选框吗?
1,保存密码。
2,自动登录。
这些 cs 程序,是客户公司之前已经开发好了的,现在我就是要对这些cs 程序做单点登录呢,就是让cs程序自动打开,再自己登录上去!用户只需点击一下就能进入到相应的软件界面中!
@challengesoflife: 我没法详细的了解你的场景,所以不能给出解决方案,只能把单点登录的原理叙述一遍,你可以参照原理来结合你的场景中的各种因素来提出解决方案。当用户已登录后,你的CS程序必须能够通过某种方式知道当前使用此CS程序的用户已经通过别的方式(比如B/S)登录成功并在线,此判断成功后,当前CS程序不需要用户再履行登录流程,而直接进入系统。
@Launcher: 嗯,我说说我的需求嘛!
公司有个客户,这个客户的公司之前有很多系统,当然有bs/cs了,因为每天开发的公司不一样,所以,程序的放言也就各异,现在客户希望我们为他们公司做一个单点登录系统,是bs形式的系统,这个系统简单的说有这样一些功能,1.注册为单点登录用户 2.配置管理自己在各个系统中的账号与密码 3.登录我们制作的单点登录系统,点击相应的应用程序,就可以自动的登录到程序的主页,而不需要再次的输入用户名和密码。
客户的这些系统,没有统一的接口,语言也不一致的!!
@challengesoflife: 这样看来,你的问题实际上不是解决单点登录的问题,更明确的说是通过软件模拟填写用户名和密码,那么这就相对简单的多了。你具有一个能够保存用户名和密码的管理程序A,在A的应用程序列表里,用户单击应用程序图标后,使用 CreateProcess 启动该应用程序,这时候你能拿到启动进程的句柄,通过此句柄,可以查询到进程的窗体,然后按照你自己写的方式来给窗体上对应控件填写值,并触发其上的登录按钮。这些你都做了,你现在的问题是,如果焦点从编辑框移开后,你写入值时会失败。那么你可以这样尝试,先将目标窗体隐藏起来,然后在send WM_SETTEXT之前,先为目标编辑框发送 WM_SETFOCUS,当一切都填写完成后,你再显示窗口,并触发登录按钮。
@Launcher: 可以隐藏啊,嗯,这个有讲究,我去看看呢,呵呵!
@Launcher: 可以隐藏啊,嗯,这个有讲究,我去看看呢,呵呵!
哦,对了,我在测试的过程中,遇到这样的问题,就是在写入值时,我是用 SendKeys,这种方法好像对系统有要求,我的机子是win2003,测试程序总是无法摸拟登录,而在xp上却行!
Launcher有没有什么好的摸拟按键 的方法呢?
@challengesoflife: SendKeys 应该是模拟的回车,你可以尝试使用Win32 API,使用 SendMessage WM_KEYDOWN 来替代,或者通过找到“登录” Button,发送 NM_CLICK 消息。
@Launcher: OK,收到。先测试去了。万分感谢 :)
@Launcher: Launcher你好,从昨天下午到现在,我一直有一个问题没有解决到--就是这个密码输入不了!
我的代码如下(vs2008 web):
protected void Win32Api_WinExec_Click(object sender, EventArgs e) { //启动程序 WinExec(@"D:\Program Files\AliWangWang\AliIM.exe", 5); Thread.Sleep(1000); var WM_SETTEXT = 0x000C; var WM_SETFOCUS = 0x0007; //自动登录 string name = "username"; string pwd = "userpwd123"; IntPtr hWnd1 = FindWindow(null, "阿里旺旺"); // 阿里旺旺2009 【父窗体】 IntPtr hWnd2 = FindWindowEx(hWnd1, IntPtr.Zero, null, "登录窗口"); // 登录窗口 【子窗体】 IntPtr hWnd30 = FindWindowEx(hWnd2, IntPtr.Zero, "StandardButton", null); // 淘宝网/旺旺选择按钮 【子窗体中的子窗体】 IntPtr hWnd31 = FindWindowEx(hWnd2, hWnd30, "EditComponent", null); // 淘宝网 【子窗体中的子窗体】 IntPtr hWnd32 = FindWindowEx(hWnd2, hWnd31, "EditComponent", null); // 会员名 【子窗体中的子窗体】 //输入用户名 SendMessage(hWnd32, WM_SETFOCUS, 0, 0); SendMessage(hWnd32, WM_SETTEXT, IntPtr.Zero, name); IntPtr hWnd3A = FindWindowEx(hWnd2, IntPtr.Zero, "AliEdit", null); // 密 码 IntPtr hWnd3B = FindWindowEx(hWnd3A, IntPtr.Zero, null, null); IntPtr hWnd3C = FindWindowEx(hWnd3B, IntPtr.Zero, "ATL:Edit", null); //密码输入框 MessageBox.Show(hWnd3C.ToString("X")); //输入密码 SendMessage(hWnd3C, WM_SETFOCUS, 0, 0); SendMessage(hWnd3C, WM_SETTEXT, IntPtr.Zero, pwd); Thread.Sleep(2000); SetForegroundWindow(hWnd1); SendKeys.SendWait("{enter}"); }
输入 密码哪里,我停了两秒截了个图:
密码框里出现了 alt:9.0 这是为什么呢?
@challengesoflife: 应该是一个用ATL写的ActiveX控件,默认的绘制文字就是ATL的版本号。你可以用SPY++分析一下该控件,有可能此控件在得到焦点的时候会使用一个标准的Edit控件来覆盖自身。
@Launcher:
哦,刚刚忘记给你说了,使用
SendKeys.SendWait(“”)
这种方式可以输入进入哈!
我这就去分析看看
@Launcher: 我看了一下SPY++,我不是很看得懂哟。
@challengesoflife: 你这是显式的控件处理的消息,你可以通过此处来观察,你通过手动输入密码时,控件都处理了哪些消息,从而你可以推断出用什么消息来模拟。你可以通过查看属性来分析控件实现的一些细节。
@Launcher: 在我把鼠标焦点放入密码框后,输入密码,再敲键盘上的回车键之前,一直没有新的消息!
然后再次返回spy++窗口中(输入的是错误的用户名和密码),查看每个窗口的属性,和输入密码之前都没有变化,这说明了些什么?
难道向 密码文本框 wm_settext 的“
SendMessage(hWnd3C, WM_SETTEXT, IntPtr.Zero, pwd); " 这句代码有问题?!
@challengesoflife: 消息监视的是某个窗口的,有可能它在得到焦点后用一个标准的Edit控件覆盖了。
@Launcher:
嗯,好的谢谢你了Launcher!
可能旺旺的密码不能用sendmessage 输入嘛,sendkeys 可以就好了,这会儿我正在看 SendInput 。
这是我现在的代码测试通过!!!
//启动程序 WinExec(@"D:\Program Files\AliWangWang\AliIM.exe", 5); Thread.Sleep(1000); var WM_SETTEXT = 0x000C; var WM_SETFOCUS = 0x0007; //自动登录 string name = "username"; string pwd = "userpwd123"; IntPtr hWnd1 = FindWindow(null, "阿里旺旺"); // 阿里旺旺2009 【父窗体】 IntPtr hWnd2 = FindWindowEx(hWnd1, IntPtr.Zero, null, "登录窗口"); // 登录窗口 【子窗体】 IntPtr hWnd30 = FindWindowEx(hWnd2, IntPtr.Zero, "StandardButton", null); // 淘宝网/旺旺选择按钮 【子窗体中的子窗体】 IntPtr hWnd31 = FindWindowEx(hWnd2, hWnd30, "EditComponent", null); // 淘宝网 【子窗体中的子窗体】 IntPtr hWnd32 = FindWindowEx(hWnd2, hWnd31, "EditComponent", null); // 会员名 【子窗体中的子窗体】 //输入用户名 SendMessage(hWnd32, WM_SETFOCUS, 0, 0); SendMessage(hWnd32, WM_SETTEXT, IntPtr.Zero, name); IntPtr hWnd3A = FindWindowEx(hWnd2, IntPtr.Zero, "AliEdit", null); // 密 码 IntPtr hWnd3B = FindWindowEx(hWnd3A, IntPtr.Zero, null, null); IntPtr hWnd3C = FindWindowEx(hWnd3B, IntPtr.Zero, null, null); //密码输入框 //MessageBox.Show(hWnd3C.ToString("X")); //输入密码 SendMessage(hWnd3C, WM_SETFOCUS, 0, 0); //SendMessage(hWnd3C, WM_SETTEXT, IntPtr.Zero, pwd); //PostMessage(hWnd3C, WM_SETTEXT, 0, pwd); //SetForegroundWindow(hWnd3C); Thread.Sleep(500); SendKeys.SendWait(pwd); //foreach (char p in pwd) //{ // SendKeys.SendWait(p.ToString()); // Thread.Sleep(500); //} //Thread.Sleep(2000); SetForegroundWindow(hWnd1); SendKeys.SendWait("{enter}");
你是通过模拟键盘输入的吧,所以焦点不能离开登陆界面。 考虑通过抓进程句柄,以及控件的ID/Class 来强行赋值。需要SPY++先找出控件ID。
我现在就是 通过进程句柄,找出换件的ID来赋值的!
也是通过 SPY++找出控件ID,输入用户名密码是用的 SendKeys.SendWait("")这种方式!
就是这种方式,在输入用户名密码的时候不能动鼠标的!
string name = "username"; string pwd = "userpwd"; IntPtr hWnd1 = FindWindow(null, "阿里旺旺"); // 阿里旺旺2009 SetForegroundWindow(hWnd1); IntPtr hWnd2 = FindWindowEx(hWnd1, IntPtr.Zero, null, "登录窗口"); // 登录窗口 IntPtr hWnd30 = FindWindowEx(hWnd2, IntPtr.Zero, "StandardButton", null); // 淘宝网/旺旺选择按钮 IntPtr hWnd31 = FindWindowEx(hWnd2, hWnd30, "EditComponent", null); // 淘宝网 IntPtr hWnd32 = FindWindowEx(hWnd2, hWnd31, "EditComponent", null); // 会员名 MessageBox.Show(hWnd32.ToString("X")); SetForegroundWindow(hWnd32); foreach (char n in name) { SendKeys.SendWait(n.ToString()); Thread.Sleep(500); } IntPtr hWnd3A = FindWindowEx(hWnd2, IntPtr.Zero, "AliEdit", null); // 密 码 IntPtr hWnd3B = FindWindowEx(hWnd3A, IntPtr.Zero, null, null); IntPtr hWnd3C = FindWindowEx(hWnd3B, IntPtr.Zero, null, null); //摸拟缓慢输入信息[太快有时会不成功] SetForegroundWindow(hWnd3C); foreach (char p in pwd) { SendKeys.SendWait(p.ToString()); Thread.Sleep(500); } IntPtr hWnd33 = FindWindowEx(hWnd2, hWnd3A, "StandardWindow", null); // 密 码 IntPtr hWnd4 = FindWindowEx(hWnd2, hWnd33, "StandardButton", null); // 淘宝网 SetForegroundWindow(hWnd4); SendKeys.SendWait("{ENTER}"); //winio.KeyPress(SuperKeys.WinIoSys.Key.VK_RETURN);
这是我的测试代码,测试的前,我是先手动打开了软件的!
@challengesoflife: 试一试 automation 命名空间
using System.Windows.Automation;
AutomationElement theMainWindow = null;
theMainWindow = AutomationElement.RootElement.FindFirst(System.Windows.Automation.TreeScope.Children,
new PropertyCondition(AutomationElement.ProcessIdProperty, aProcess.Id));
。。。。这个命名空间,常被用来做自动化测试。可以考虑通过automationelement 方法定位空间,在直接setvalue。
@Lee Zhang: 嗯,好的谢谢哈!
在软件安装的路径加个TXT文件记录用户ID,密码,下次登录就读 TXT文件的内容。
这里主要的问题不是用户名和密码的问题,而是自动登录问题!