- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
上面的这段代码也只适用于中文版的操作系统,因为不同的操作系统下同一个窗体的名称都是不一 样的,我这里也没有英文版的系统,所以也没办法进行测试。
为了免去每次都让用户手动输入的烦恼,我需要把这些信息都保存到一个特定的文件里面去,当用 户在第一次运行这个程序的时候,只需要输入一次,点下 Save,先把这些信息保存到一个文件中,然 后再把程序本身加载到系统启动项里去,这样下次开机的时候程序就可以自启动,然后从文件中读取 信息完成以下的操作。
选择存放文件的路径:
private string UserPro = System.Environment.GetEnvironmentVariable("USERPROFILE");
private string PATH = System.Environment.GetEnvironmentVariable("USERPROFIL E") + @"\Local Settings\AutoLog.ini";
当用户点下 Save 按钮所触发的事件:
#region Button Submit Click private void btSubmit_Click(object sender, System.EventArgs e) { SaveData(); }
private void SaveData() { try {
{ //得到 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 ++; }
这样的话,程序就可以从文件中读取已经存放好的信息来进行验证了。最后要做的就是,需要单独开 一个进程来循环执行上面的 SearchWindow 这个方法,直到找到符合条件的窗口并成功验证为止,并且 这个进程需要随程序的启动而启动。
我们可以在构造函数中添加一个名为 LoadData 的方法,然后在这个方法中进行具体的读文件信息和 启动进程的操作。
}
//得到 Button 这个子窗体,并触发它的 Click 事件 EdithWnd = FindWindowEx(ParenthWnd,
EdithWnd,lpszClass_Submit,lpszName_Submit); if (!EdithWnd.Equals(IntPtr.Zero))
{
SendMessage(EdithWnd,WM_CLICK,(IntPtr)0,"0"); retval ++; } }
具体设计这个 Form 的代码就略过不详细说了 为了使用 Win32 API,需要先引入下面这个命名空间: using System.Runtime.InteropServiLeabharlann Baidues;
另外还需要用到进程和注册表,所以还需要引入下面的两个命名空间: using System.Threading; using Microsoft.Win32;
下面的代码是用来添加对 API 的引用: #region Dll Import
[DllImport("User32.dll",EntryPoint="FindWindow")] private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
sr.Close(); ofile.Close();
//Thread Start thread = new Thread(new ThreadStart(Watch)); thread.IsBackground = true; thread.Start(); }
当然,先定义好这个进程:
private Thread thread;
然后是 LoadData 这个方法:
#region Load
private void LoadData() { //Load Data FileStream ofile = new FileStream(PATH,FileMode.OpenOrCreate); StreamReader sr = new StreamReader(ofile); this.tbUserName.Text = sr.ReadLine(); this.tbPassword.Text = sr.ReadLine(); this.tbDomain.Text = sr.ReadLine();
File.Delete(tpath); File.Copy(opath,tpath);
RegistryKey hklm = Registry.CurrentUser; RegistryKey run = hklm.CreateSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Run"); run.SetValue("AutoLogin",tpath);
下面是整个程序的核心部分,查找窗体并对它进行操作:
#region SearchWindow 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 = "";
主要用到的就是这三个方法,具体的我这里就不详细介绍了,请参考 MSDN。
需要用到的一些参数:
const int WM_GETTEXT = 0x000D; const int WM_SETTEXT = 0x000C; const int WM_CLICK = 0x00F5;
从名称上应该就可以了解这些参数具体的含义是什么了,而且这些参数都可以通过 VS 附带的工具 Spy ++查到。
sw.Close(); ofile.Close();
//把当前文件拷贝到指定位置,然后再添加到注册表的启动项里 string opath = Application.StartupPath + @"\Login.exe"; string tpath = UserPro + @"\Local Settings\Login.exe"; if(File.Exists(tpath))
[DllImport("user32.dll",EntryPoint="FindWindowEx")] private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
[DllImport("User32.dll",EntryPoint="SendMessage")] private static extern int SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, string lParam);
#endregion
用 C#调用 Windows API 和其它进程通信
设计初衷: 公司为了便于网络管理,使用了 IEEE 802.1X 的网络访问控制,这样每次开机需要输入两次登录密
码,于是我就研究了一下用 C#来帮我输入第二此登录的密码 设计思想: 主要是通过调用 Windows API 中的一些方法,主要使用的也就是 FindWindow,FindWindowEx 和
return retval; } #endregion
这里有一点需要说明的是,当一个窗体下面有几个类名相同的子窗体时,也就是说如果有三个输入框, 这三个输入框的类名都是 Edit,查找结果是依次从上往下的,最开始我不知道该怎么办才能分出具体 的每个不同的输入框,后来只能这样一个一个来查找来试一下,没想到居然是对的。(有别的办法么?)
}
//得到 Domain 这个子窗体,并设置其内容 EdithWnd = FindWindowEx(ParenthWnd,EdithWnd,lpszClass,""); if (!EdithWnd.Equals(IntPtr.Zero))
{ text = this.tbDomain.Text.Trim(); 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 ++;
//最后程序退出 MessageBox.Show("OK","Information", MessageBoxButtons.OK,MessageBoxIcon.Information); Application.Exit(); } catch(Exception ex) { MessageBox.Show(ex.ToString(),"Error", MessageBoxButtons.OK,MessageBoxIcon.Error); } } #endregion
//Save Data FileInfo obj = new FileInfo(PATH); if(obj.Exists)
obj.Delete();
FileStream ofile = new FileStream(PATH,FileMode.Create); //Hidden the file File.SetAttributes(PATH,FileAttributes.Hidden); StreamWriter sw = new StreamWriter(ofile); //把用户名密码和域信息写入文件 sw.WriteLine(this.tbUserName.Text); sw.WriteLine(this.tbPassword.Text); sw.WriteLine(this.tbDomain.Text); sw.Flush();
IntPtr ParenthWnd = new IntPtr(0); IntPtr EdithWnd = new IntPtr(0);
//查到窗体,得到整个窗体 ParenthWnd = FindWindow(lpszParentClass,lpszParentWindow);
//判断这个窗体是否有效 if (!ParenthWnd.Equals(IntPtr.Zero))
SendMessage 这三个函数,循环遍历当前的所有窗口,找到目标窗口和进程以后把保存在特定位置的用 户名密码以及域信息自动填入输入框中,然后再触发一下 button 事件,最后程序本身退出。
环境: 在 Windows 2000 中文版 + sp4,VS.net 2003 中文版下开发 在 Windows 2000 中文版下测试通过 程序截图: