我不喜歡廢話,上代碼windows
/// <summary>
/// 運行程序返回進程pid
/// </summary>
/// <param name="qqPath"></param>
/// <returns></returns>
static public int RunProgram(string qqPath)
{
int pid = 0;
Process pro = Process.Start(qqPath);
if (pro != null)
{
pid = pro.Id;
}
try
{
ChannelName = null;
Console.WriteLine("Register");
RemoteHooking.IpcCreateServer<HookedInterface>(ref ChannelName, WellKnownObjectMode.SingleCall);
Console.WriteLine("IpcCreateServer");
RemoteHooking.Inject(pid, "QqMonInject.dll", "QqMonInject.dll", ChannelName);
HookedSender.Init();
WndManager.Init();
}
catch (Exception ExtInfo)
{
Console.WriteLine("There was an error while connecting to target:\r\n{0}", ExtInfo.ToString());
}
return pid;
}上面的代碼實現了運行QQ,並使用EasyHook加載鉤子,因爲。net沒法實現全局鉤子,故使用EasyHook來實現,EasyHook是一個開源項目,你們能夠google
/// <summary>
/// 登錄,成功後返回窗體句柄
/// </summary>
/// <param name="mainQQ"></param>
/// <param name="mainQQPwd"></param>
/// <returns></returns>
static public IntPtr Logon(string mainQQ, string mainQQPwd, ref string errorText)
{
IntPtr hWnd = IntPtr.Zero;
string qqPath = SqliteHelper.GetValue("select SC_QQPROPATH from sys_config").ToString();
int pid = RunProgram(qqPath);
if (pid < 100)
{
errorText = "沒法運行QQ進程";
WriteLog(errorText);
return hWnd;
}
Thread.Sleep(SysConfig.QQProcessStartSleppTime);
//bool ad = !false;
//while (ad) { Thread.Sleep(2000); }
IntPtr hLogonWnd = GetLogonWnd(pid);
if (hLogonWnd == IntPtr.Zero) hLogonWnd = GetLogonWnd2(pid);
if (hLogonWnd == IntPtr.Zero)
{
errorText = "沒有登錄窗口";
WriteLog(errorText);
return hWnd;
}
var cons = WndHelper.GetVisableControl(hLogonWnd, "ATL:30A561F0");
if (cons.Count < 1)
{
errorText = "沒有找到登錄QQ輸入框";
WriteLog(errorText);
return hWnd;
} //沒有找到QQ輸入框
int retvar = WinAPIHelper.SendMessage(cons[0], WinAPIHelper.WM_SETTEXT, IntPtr.Zero, new StringBuilder(mainQQ));
if (retvar == 0)
{
errorText = "沒法設置登錄QQ號碼";
WriteLog(errorText);
return hWnd;
}//沒法設置登錄QQ號碼
cons = WndHelper.GetVisableControl(hLogonWnd, "Edit");
if (cons.Count < 1)
{
errorText = "沒有找到密碼輸入框";
WriteLog(errorText);
return hWnd;
}//沒有找到密碼輸入框
SETPASSWARD:
while (true)
{
if (WndHelper.IsWindowTopMost(hLogonWnd))
{
if (!WinAPIHelper.BringWindowToTop(hLogonWnd))
{
Console.WriteLine("登錄窗體置頂失敗");
continue;
}
}
Console.WriteLine("登錄窗體設置焦點");
IntPtr hFocus = WinAPI.GetForegroundWindow();
if (hFocus == IntPtr.Zero)
{
Thread.Sleep(200);
Console.WriteLine("獲取焦點窗體失敗");
continue;
}
if (hFocus != hLogonWnd)
{
if (!WinAPIHelper.SetForegroundWindow(hLogonWnd))
{
Thread.Sleep(200);
Console.WriteLine("登錄窗體設置焦點失敗");
//continue;
}
}
bool result = WinAPIHelper.SetForegroundWindow(hLogonWnd);
//if (!result) goto SETPASSWARD;
retvar = WinAPIHelper.SendMessage(cons[0], WinAPIHelper.WM_SETFOCUS, 0x001a0494, 0);
break;
//if (retvar == 0) goto SETPASSWARD;
}
Console.WriteLine("密碼:" + mainQQPwd);
Console.WriteLine("輸入密碼");
#if DEBUG
for (int i = 0; i < 20; i++) SendKeys.SendWait("{DELETE}");
#endif
SendKeys.SendWait(mainQQPwd.Replace("+", "{+}").Replace("^", "{^}").Replace("%", "{%}"));
WndHelper.ClickWnd(hLogonWnd, 0x00c9012d);
if (WaitLogon(pid, ref errorText))
{
Console.WriteLine("登錄完成");
}
else
{
return IntPtr.Zero;
}
WindowEventArgs mainWea = WndManager.GetDesktopWnds(pid).Find(p => p.Pid == pid && p.ClassName == "TXGuiFoundation" && p.Title == "QQ2010");
if (mainWea != null)
{
const int width = 270;
const int height = 600;
WinAPIHelper.MoveWindow(mainWea.Hwnd, Screen.PrimaryScreen.WorkingArea.Width - width - 20, 20, width, height, true);
return mainWea.Hwnd;
}
return IntPtr.Zero;
}
登錄部分代碼,關鍵點是WM_SETTEXT消息設置QQ號碼,SendKeys.SendWait設置密碼,而後模擬點擊,實現登錄網絡
static public bool WaitLogon(int pid, ref string errorText)
{
DateTime beginTime = DateTime.Now;
while (true)
{
TimeSpan ts = TimeSpan.FromTicks(DateTime.Now.Ticks - beginTime.Ticks);
if (ts.TotalMilliseconds > SysConfig.QQLogonTimeOut)
{
KillProcess(pid);
errorText = "登錄超時";
WriteLog(errorText);
return false;
}
var wnds = WndManager.GetDesktopWnds(pid);
WindowEventArgs pwdErrorWea = wnds.Find(p => p != null && p.Pid == pid && p.ClassName == "TXGuiFoundation" && p.Title == "密碼驗證錯誤");
if (pwdErrorWea != null)
{
bool result = WinAPIHelper.IsWindowVisible(pwdErrorWea.Hwnd);
if (result)
{
KillProcess(pid);
errorText = "密碼錯誤";
WriteLog(errorText);
return false;
}
}
WindowEventArgs pwdErrorNet = wnds.Find(p => p != null && p.Pid == pid && p.ClassName == "TXGuiFoundation" && p.Title == "提示" && p.Size.Width == 350 && p.Size.Height == 160);
if (pwdErrorNet != null)
{
bool result = WinAPIHelper.IsWindowVisible(pwdErrorNet.Hwnd);
if (result)
{
KillProcess(pid);
errorText = "網絡鏈接錯誤";
WriteLog(errorText);
return false;
}
}
WindowEventArgs mainWea = wnds.Find(p => p != null && p.Pid == pid && p.ClassName == "TXGuiFoundation" && p.Title == "QQ2010" && WinAPIHelper.IsWindowVisible(p.Hwnd));
if (mainWea != null)
{
bool result = WinAPIHelper.IsWindowVisible(mainWea.Hwnd);
if (result && mainWea.Size.Height > 338)
break;
}
WindowEventArgs codeWea = wnds.Find(p => p != null && p.Pid == pid && p.ClassName == "TXGuiFoundation" && p.Title == "賬號存在異常");
if (codeWea != null)
{
if (SysConfig.IsSkipValidateCode)
{
bool result = WinAPIHelper.IsWindowVisible(codeWea.Hwnd);
if (result)
{
KillProcess(pid);
errorText = "須要輸入驗證碼";
WriteLog(errorText);
return false;
}
}
else
Thread.Sleep(1000);
}
WindowEventArgs saleWea = wnds.Find(p => p != null && p.Pid == pid && p.ClassName == "TXGuiFoundation" && p.Title == "賬號需解除限制後才能登陸");
if (saleWea != null)
{
bool result = WinAPIHelper.IsWindowVisible(saleWea.Hwnd);
if (result)
{
KillProcess(pid);
errorText = "帳號被限制";
WriteLog(errorText);
return false;
}
}
Thread.Sleep(1000);
}
return true;
}
上面的代碼是各類狀況的判斷
涉及到知識點post
- 窗體查找(遍歷桌面窗體)
- 控件查找(子窗體,句柄循環)
- 使用windows API實現發送消息,爲窗體置頂,設置焦點
今天到此爲止,明天繼續更新ui