我不喜欢废话,上代码
/// <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 DEBUGfor (int i = 0; i < 20; i++) SendKeys.SendWait("{DELETE}");
#endifSendKeys.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;
}
}
elseThread.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;
}
上面的代码是各种情况的判断
涉及到知识点
- 窗体查找(遍历桌面窗体)
- 控件查找(子窗体,句柄循环)
- 使用windows API实现发送消息,为窗体置顶,设置焦点
今天到此为止,明天继续更新
转载请注明:http://www.cnblogs.com/Rolends
HAPPY EVERY DAY ! !
浙公网安备 33010602011771号