當前位置:
首頁 > 知識 > C井調用Windows API實現自動登錄

C井調用Windows API實現自動登錄

設計初衷:

公司為了便於網路管理,使用了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

privatevoid 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實現自動登錄

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 程序員小新人學習 的精彩文章:

sql語句的執行順序以及流程(詳細掌握)
js 截取字元串

TAG:程序員小新人學習 |