用C#调用Windows API和其它进程通信

转自http://www.cnblogs.com/index/archive/2005/01/16/92651.html

作者:边城浪子◎2005-01-16

关键字:
C#,API,FindWindow,FindWindowEx,SendMessage,进程,注册表

设计初衷:
公司为了便于网络管理,使用了IEEE 802.1X的网络访问控制,这样每次开机需要输入两次登录密码,于是我就研究了一下用C#来帮我输入第二此登录的密码

设计思想:
主要是通过调用Windows API中的一些方法,主要使用的也就是FindWindow,FindWindowEx和SendMessage这三个函数,循环遍历当前的所有窗口,找到目标窗口和进程以后把保存在特定位置的用户名密码以及域信息自动填入输入框中,然后再触发一下button事件,最后程序本身退出。

环境:
在Windows 2000中文版 + sp4,VS.net 2003中文版下开发
在Windows 2000中文版下测试通过

程序截图:

具体设计这个Form的代码就略过不详细说了

为了使用Win32 API,需要先引入下面这个命名空间:

using System.Runtime.InteropServices;

另外还需要用到进程和注册表,所以还需要引入下面的两个命名空间:

using System.Threading;
using Microsoft.Win32;

下面的代码是用来添加对API的引用:

    Dll Import #region Dll Import

    [DllImport(
"User32.dll",EntryPoint="FindWindow")]
   
private static extern IntPtr FindWindow(string lpClassName,
string lpWindowName);

    [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


主要用到的就是这三个方法,具体的我这里就不详细介绍了,请参考MSDN。

需要用到的一些参数:

    const int WM_GETTEXT = 0x000D ;
   
const int WM_SETTEXT = 0x000C ;
   
const int WM_CLICK = 0x00F5 ;

从名称上应该就可以了解这些参数具体的含义是什么了,而且这些参数都可以通过VS附带的工具Spy ++查到。

下面是整个程序的核心部分,查找窗体并对它进行操作:

SearchWindow #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 = "";

        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;
    }

   
#endregion


这里有一点需要说明的是,当一个窗体下面有几个类名相同的子窗体时,也就是说如果有三个输入框,这三个输入框的类名都是Edit,查找结果是依次从上往下的,最开始我不知道该怎么办才能分出具体的每个不同的输入框,后来只能这样一个一个来查找来试一下,没想到居然是对的。(有别的办法么?)

上面的这段代码也只适用于中文版的操作系统,因为不同的操作系统下同一个窗体的名称都是不一样的,我这里也没有英文版的系统,所以也没办法进行测试。

为了免去每次都让用户手动输入的烦恼,我需要把这些信息都保存到一个特定的文件里面去,当用户在第一次运行这个程序的时候,只需要输入一次,点下Save,先把这些信息保存到一个文件中,然后再把程序本身加载到系统启动项里去,这样下次开机的时候程序就可以自启动,然后从文件中读取信息完成以下的操作。

选择存放文件的路径:

private string UserPro =  
        System.Environment.GetEnvironmentVariable(
" USERPROFILE " );
   
private string PATH = System.Environment.GetEnvironmentVariable("USERPROFILE") + @" \Local Settings\AutoLog.ini " ;

当用户点下Save按钮所触发的事件:

Button Submit Click #region Button Submit Click
   
private void btSubmit_Click(object sender, System.EventArgs e)
   
{
        SaveData();
    }


   
private void SaveData()
   
{
       
try
       
{
           
//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();

            sw.Close();
            ofile.Close();

           
//把当前文件拷贝到指定位置,然后再添加到注册表的启动项里
            string opath = Application.StartupPath + @"\Login.exe";
           
string tpath = UserPro + @"\Local Settings\Login.exe";
           
if(File.Exists(tpath))
                File.Delete(tpath);
            File.Copy(opath,tpath);

            RegistryKey hklm
= Registry.CurrentUser;
            RegistryKey run
= 
hklm.CreateSubKey(
@"SOFTWARE\Microsoft\Windows\CurrentVersion\Run");
            run.SetValue(
"AutoLogin",tpath);

           
//最后程序退出
            MessageBox.Show("OK","Information",
MessageBoxButtons.OK,MessageBoxIcon.Information);
            Application.Exit();
        }

       
catch(Exception ex)
       
{
            MessageBox.Show(ex.ToString(),
"Error",
MessageBoxButtons.OK,MessageBoxIcon.Error);
        }

    }

   
#endregion


这样的话,程序就可以从文件中读取已经存放好的信息来进行验证了。最后要做的就是,需要单独开一个进程来循环执行上面的SearchWindow这个方法,直到找到符合条件的窗口并成功验证为止,并且这个进程需要随程序的启动而启动。

我们可以在构造函数中添加一个名为LoadData的方法,然后在这个方法中进行具体的读文件信息和启动进程的操作。

当然,先定义好这个进程:

private Thread thread;

然后是LoadData这个方法:

Load #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();

        sr.Close();
        ofile.Close();

       
//Thread Start
        thread = new Thread(new ThreadStart(Watch));
        thread.IsBackground
= true;
        thread.Start();
    }

        
   
private void Watch()
   
{
       
//循环查找这个窗口,直到成功为止
        while(true)
       
{
           
int i = this.SearchWindow();

           
if(i == 4)
               
break;
        }


       
//程序退出并释放资源
        Application.Exit();
       
this.Dispose();
       
this.Close();
        }


       
#endregion


好,到这里就介绍完毕了,当然还有很多需要改进的地方,比如说密码存在本机上应该用一种加密的方式来保存等等。我还是第一次接触用C#调用Windows API这方面的东西,很多东西也都是从网上查资料才得到的,不足之处,恳请指出。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C#网页版+客户端版聊天软件源码分享(C#+长连接+Sqllite数据库实现) 今天我给大家分享一个聊天程序的源码。 网页版加客户端版并存,可以互通 我相信对大家学习和扩展这一块知识是很有用的。 我们先来看下软件结构 一个Web版一个网页版,而客户端是连接的网页的 http://localhost:53947/wwwroot/Lesktop 这个路径 http://localhost:53947/wwwroot/这一部分是网页的地址,大家可以根据自己配置情况进行修改 然后浏览一下Default.aspx页面如下 这是负面版的,客户端的也是一样的,我们先来注册 一个账户 在这里我们注册两个账户还有一个是text用来聊天对话使用 注册的方法是一样的我就不多说了。 下面登录第一个账户看看 这是登录后的效果。 单击聊天室 然后我们再登录另外一个账户text 好了大家应该能看到效果了吧。 然后咱们再发个“你好” 收到了吧,再回复一个 对就是这个效果, 再来看看桌面版的 刚才的消息都在 这是桌面版的效果。 大家感觉怎么样。 我感觉大家可以在这个基础之上进行扩展,最少可以看看他的实现思路 源码分享给大家了 sufeinet.com即时通信_云骞.zip (3.25 MB, 下载次数: 1078) ReceiveResponsesHandler 类,这个主要是用来接收和维护长连接的 实现长连接的两个重要来代码预览 [C#] 纯文本查看 复制代码 ? 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 using System; using System.Collections.Generic; using System.Collections; using System.Text; using System.Web; using System.Xml; using System.Threading; namespace Core { public class ReceiveResponsesHandler : IHttpAsyncHandler { public ReceiveResponsesHandler() { } HttpContext m_Context = null; IAsyncResult IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData) { m_Context = context; string sessionId = context.Request.Params["SessionID"]; string clientVersion = context.Request.Params["ClientVersion"]; string serverVersion = context.Request.Params["ServerVersion"]; ResponsesListener asyncResult = new ResponsesListener(sessionId, cb, extraData); try { if (serverVersion != ServerImpl.Instance.Version) throw new IncompatibleException();

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值