QQ机器人 http://www.cnblogs.com/sukyboor/archive/2007/01/03/610451.html
2007-10-29 16:37
567 查看
这个元旦假期过的比较奇怪,为了向远方的GF表示忠诚。除了1号和同学吃了个大锅饭之外,尽量做到了大门不出二门不迈,躲在闺房守岁:)。
在家闲着也不能干闲着,总得做点事情,想起前段时间一个师兄交代给我的任务:把若干个qq群串在一起。X国的政策一向比较Bt,你说开个群还要限制人数。H大在深圳有几千校友,一个群怎么可能放的下那么多人。好多在tx工作的师兄,明确告诉:我买通tx的人是不大可能了,搞一个传话筒才是解决之道。
事情虽小,但也着实麻烦。你说要去分析QQ具体数据包,万一哪天tx一高兴把数据给改了,或者接口开放了,也够我郁闷一壶的了。那就找个最简单的办法吧,左一顿baidu,又一顿google. “QQ接口”搜出来的结果绝大多数是关于tx qq的http接口,既然大家那么推崇,那我就从Http接口下手,于是把我以前写的AJAX给拆了,在把所谓的qq接口研究成果给鼓捣在一起,然后去webqq(http://webqq.qq.com)上大抢一遍,那家伙,天昏地暗,相当的&(&(。
代码我是用script写的:
异步AJAX会话类
1
//异步AJAX会话类
2
if(typeof(AjaxSession) == 'undefined')
3
var AjaxSession = function()
{
4
5
//创建会话
6
this.CreateSession = function()
7
{
8
if (window.ActiveXObject)
{ // IE
9
try
{
10
return new ActiveXObject('Microsoft.XMLHTTP');
11
}catch(e)
{}
12
13
try
{
14
return new ActiveXObject('Msxml2.XMLHTTP');
15
}catch(ee)
{}
16
}else
{ //Mozilla, Safari
17
var s = new XMLHttpRequest();
18
if (s.readyState == null)
{
19
s.readyState = 1;
20
s.addEventListener("load", function ()
{
21
s.readyState = 4;
22
if (typeof(s.onreadystatechange) == "function")
23
s.onreadystatechange();
24
}, false);
25
}
26
27
return s;
28
}
29
30
return null;
31
}
32
33
//进行请求
34
this.Request = function(url, params, callback)
35
{
36
37
var s = this.CreateSession();
38
if(null == s)
39
alert("对不起,您的浏览器不支持某些特性。");
40
else
41
s.abort();
42
43
var isAsync = typeof(callback) == 'function';
44
var method = !params ? "GET" : "POST";
45
46
if(isAsync) s.onreadystatechange = function()
47
{
48
try
{
49
alert(s.status);
50
if ((4 == s.readyState) && (200 == s.status || 304 == s.status))
51
callback(this.Response(s));
52
else
53
alert("请求错误,错误原因:" + s.statusText);
54
}catch(e)
{}
55
}
56
57
s.open(method, url, isAsync);
58
s.setRequestHeader("Connection","Keep-Alive");
59
s.setRequestHeader("Content-Type","text/html; charset=gb2312");
60
//s.setRequestHeader("Content-Type","text/plain; charset=UTF-8");
61
62
if(method == "POST")
63
{
64
s.setRequestHeader("Content-Length",params.length)
65
s.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
66
67
}
68
69
alert(params);
70
s.send(params);
71
72
73
if(!isAsync)
74
return this.Response(s);
75
}
76
77
//返回应答信息
78
this.Response = function(s)
79
{
80
if(s.status == 200 || 304 == s.status)
81
{
82
if(s.responseXML != null && s.responseXML.xml != null && s.responseXML.xml != '')
83
return s.responseXML;
84
else
85
return s.responseText;
86
}
87
}
88
89
//对字符串进行编码
90
this.UncCoding = function(s)
91
{
92
var output = '';
93
for(var i = 0 ;i< s.length;i++)
{
94
output = output + '%' + s.charCodeAt(i);
95
}
96
97
return output;
98
}
99
100
//获取xml结构
101
this.GetDom = function(s)
{
102
var doc = new ActiveXObject('Microsoft.XMLDOM');
103
doc.async = false;
104
doc.loadXML(s) ;
105
return doc;
106
}
107
108
return this;
109
}
//QQ会话类
1
//会话类
2
if(typeof(QQSession) == 'undefined')
3
var QQSession = function()
{
4
this.UIN = 0;
5
this.Md5PasswordStr = "";
6
this.WebQQUrl = "http://tqq.tencent.com:8000/";
7
this.qs = null;
8
this.isLogin = false;
9
this.SeqIndex = null;
10
11
//用户登陆
12
this.Login = function(uin,passwd,vcode,qs)
{
13
var m5 = new MD5();
14
this.UIN = uin;
15
this.Md5PasswordStr = m5.calcMD5(passwd);
16
var CmdStr = "VER=1.0&CMD=1&SEQ=" + this.GetNewSEQ() + "&UIN=" + uin + "&PS=" + this.Md5PasswordStr + "&STATUS=10&VCODE=" + vcode + "&QQSESSION=" + qs ;
17
18
//if(!this.qs)
19
// this.qs = new AjaxSession();
20
window.frames["proxy"].request(this.WebQQUrl,CmdStr);
21
//this.qs.Request(this.WebQQUrl,CmdStr,this.ShowMsg);
22
23
//document.getElementById("ssl_login").callback = this.ShowMsg;
24
//document.getElementById("ssl_login").src = "https://webqq-proxy.qq.com/webqq/l?"+ CmdStr;
25
}
26
27
//用户信息
28
this.GetInfo = function()
{
29
var CmdStr = "VER=1.0&CMD=10&SEQ=" + this.GetNewSEQ() + "&UIN=" + this.UIN + "&FUIN=" + this.UIN;
30
this.qs.Request(this.WebQQUrl,CmdStr,this.ShowMsg);
31
//window.frames["proxy"].request(this.WebQQUrl,CmdStr);
32
}
33
34
//获取好友列表
35
this.GetList = function()
{
36
var CmdStr = "VER=1.0&CMD=2&SEQ=" + this.GetNewSEQ() + "&UIN=" + this.UIN + "&NPOS=0";
37
this.qs.Request(this.WebQQUrl,CmdStr,this.ShowMsg);
38
}
39
40
//获得新的SEQ
41
this.GetNewSEQ = function()
{
42
if(!this.SeqIndex)
{
43
var d = new Date();
44
this.SeqIndex = d.getTime()
45
}
46
47
this.SeqIndex ++;
48
return this.SeqIndex;
49
}
50
51
this.ShowMsg = function(s)
{
52
alert(s);
53
}
54
55
return this;
56
}
我在那用天真的眼神,盼望着能从这个地方掏出点东西来。可偏偏我这个比较倒霉的孩子,碰到了极其复杂的网络问题(家穷人丑,只好用手机上网,速度回到上世纪90年代),掏了半天啥也没弄到,返回的尽是12152错误。
去翻MSDN时,遇到几个头疼的单词(鄙人英语着实差劲,单词量屈指可数),很习惯的就去开金山词霸。等等,金山词霸能把别的窗口的信息给拽出来,为什么我就不能。于是我就抛弃了前面的工作,从QQ对话窗口下手。nndx,偶就不信了,偶还灭不了你。
说干就干,那就先勾吧,.net好象是干不了这事,但是winapi还是能干这活的。win32编程嘛,不就几个消息循环(—(—……*(—
WinApi调用
1
using System;
2
using System.Drawing;
3
using System.Runtime.InteropServices;
4
5
namespace TQQ
6
{
7
/**//// <summary>
8
/// WinApi调用
9
/// </summary>
10
public class WinApi
11
{
12
/**//// <summary>
13
/// 根据鼠标位置获取窗体
14
/// </summary>
15
/// <param name="lpPoint"></param>
16
/// <returns></returns>
17
[DllImport("user32.dll")]
18
public static extern IntPtr WindowFromPoint(Point lpPoint);
19
20
/**//// <summary>
21
/// 获取鼠标位置
22
/// </summary>
23
/// <param name="lpPoint"></param>
24
/// <returns></returns>
25
[DllImport("user32.dll")]
26
public static extern int GetCursorPos(out Point lpPoint);
27
28
/**//// <summary>
29
/// 获取鼠标位置下的窗体
30
/// </summary>
31
/// <returns></returns>
32
public static IntPtr GetLocalWindow()
33
{
34
Point point;
35
GetCursorPos(out point);
36
return WindowFromPoint(point);
37
}
38
39
/**//// <summary>
40
/// 申请内存空间
41
/// </summary>
42
/// <param name="hProcess"></param>
43
/// <param name="lpAddress"></param>
44
/// <param name="dwSize"></param>
45
/// <param name="flAllocationType"></param>
46
/// <param name="flProtect"></param>
47
/// <returns></returns>
48
[ DllImport( "Kernel32.dll" )]
49
public static extern Int32 VirtualAllocEx(IntPtr hProcess,Int32 lpAddress,Int32 dwSize,Int16 flAllocationType,Int16 flProtect);
50
51
/**//// <summary>
52
/// 读取内存空间
53
/// </summary>
54
/// <param name="hProcess"></param>
55
/// <param name="lpBaseAddress"></param>
56
/// <param name="lpBuffer"></param>
57
/// <param name="nSize"></param>
58
/// <param name="lpNumberOfBytesWritten"></param>
59
/// <returns></returns>
60
[ DllImport( "Kernel32.dll" )]
61
public static extern int ReadProcessMemory(IntPtr hProcess, Int32 lpBaseAddress,byte[] lpBuffer,long nSize,long lpNumberOfBytesWritten);
62
63
/**//// <summary>
64
/// 写内存空间
65
/// </summary>
66
/// <param name="hProcess"></param>
67
/// <param name="lpBaseAddress"></param>
68
/// <param name="lpBuffer"></param>
69
/// <param name="nSize"></param>
70
/// <param name="lpNumberOfBytesWritten"></param>
71
/// <returns></returns>
72
[ DllImport( "Kernel32.dll" )]
73
public static extern int WriteProcessMemory(IntPtr hProcess, Int32 lpBaseAddress,byte[] lpBuffer,long nSize,long lpNumberOfBytesWritten);
74
75
/**//// <summary>
76
/// 根据类/标题查找窗口
77
/// </summary>
78
/// <param name="lpClassName"></param>
79
/// <param name="lpWindowName"></param>
80
/// <returns></returns>
81
[DllImport("User32.dll",EntryPoint="FindWindow")]
82
public static extern IntPtr FindWindow(string lpClassName,string lpWindowName);
83
84
/**//// <summary>
85
/// 获取窗口子对象
86
/// </summary>
87
/// <param name="hwndParent"></param>
88
/// <param name="hwndChildAfter"></param>
89
/// <param name="lpszClass"></param>
90
/// <param name="lpszWindow"></param>
91
/// <returns></returns>
92
[DllImport("user32.dll",EntryPoint="FindWindowEx")]
93
public static extern IntPtr FindWindowEx(IntPtr hwndParent,IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
94
95
/**//// <summary>
96
/// 发送windows消息
97
/// </summary>
98
/// <param name="hWnd"></param>
99
/// <param name="Msg"></param>
100
/// <param name="wParam"></param>
101
/// <param name="lParam"></param>
102
/// <returns></returns>
103
[DllImport("User32.dll")]
104
public static extern IntPtr SendMessage(IntPtr hWnd,int Msg,IntPtr wParam,IntPtr lParam);
105
106
/**//// <summary>
107
/// 发送windows消息
108
/// </summary>
109
/// <param name="hWnd"></param>
110
/// <param name="Msg"></param>
111
/// <param name="wParam"></param>
112
/// <param name="lParam"></param>
113
/// <returns></returns>
114
[DllImport("User32.dll",EntryPoint="SendMessage")]
115
public static extern int SendMessage(IntPtr hWnd,int Msg, IntPtr wParam, string lParam);
116
117
/**//// <summary>
118
/// 发送windows消息
119
/// </summary>
120
/// <param name="hwnd"></param>
121
/// <param name="wMsg"></param>
122
/// <param name="wParam"></param>
123
/// <param name="lParam"></param>
124
/// <returns></returns>
125
[DllImport("user32.dll", CharSet = CharSet.Auto)]
126
public static extern int SendMessage( IntPtr hwnd, int wMsg, int wParam,string lParam);
127
128
/**//// <summary>
129
/// 发送windows消息
130
/// </summary>
131
/// <param name="hwnd"></param>
132
/// <param name="wMsg"></param>
133
/// <param name="wParam"></param>
134
/// <param name="lParam"></param>
135
/// <returns></returns>
136
[DllImport("user32.dll", CharSet = CharSet.Auto)]
137
public static extern int SendMessage( IntPtr hwnd, int wMsg, int wParam,int lParam);
138
139
/**//// <summary>
140
/// 发送windows消息
141
/// </summary>
142
/// <param name="hwnd"></param>
143
/// <param name="wMsg"></param>
144
/// <param name="wParam"></param>
145
/// <param name="lParam"></param>
146
/// <returns></returns>
147
[DllImport("user32.dll", CharSet = CharSet.Auto)]
148
public static extern int SendMessage( IntPtr hwnd, int wMsg, int wParam,System.Text.StringBuilder lParam);
149
150
public const int WM_GETTEXT = 0x000D;
151
public const int WM_GETTEXTLENGTH = 0x000E;
152
public const int WM_SETTEXT = 0x000C;
153
public const int WM_CLICK = 0x00F5;
154
public const int WM_CHAR = 0x0102;
155
public const int EM_SETSEL = 0x00B1;
156
public const int EM_REPLACESEL = 0x00C2;
157
158
}
159
}
QQ钩子
1
/**//// <summary>
2
/// QQ钩子
3
/// </summary>
4
public class QQHooks
5
{
6
/**//// <summary>
7
/// 发送消息
8
/// </summary>
9
/// <param name="windowName">窗口标题</param>
10
/// <param name="strMsg">消息内容</param>
11
public static void SendMsg(string windowName,string strMsg)
12
{
13
string lpszParentClass = "#32770"; //整个窗口的类名
14
string lpszParentWindow = windowName; //窗口标题
15
IntPtr ip = WinApi.FindWindow(lpszParentClass,lpszParentWindow);
16
IntPtr EdithParentWnd = WinApi.FindWindowEx(ip,new IntPtr(0),"#32770","");
17
IntPtr EdithWnd = WinApi.FindWindowEx(EdithParentWnd,new IntPtr(0),"AfxWnd42","");
18
19
string lpszClass_Text = "RICHEDIT"; //消息输入窗口
20
string lpszName_Text = ""; //消息输入窗口
21
IntPtr THandle = WinApi.FindWindowEx(EdithWnd,new IntPtr(0),lpszClass_Text,lpszName_Text);
22
23
StringBuilder sb = new StringBuilder(strMsg);
24
WinApi.SendMessage(THandle,WinApi.EM_SETSEL,-1,-1);//
25
WinApi.SendMessage(THandle,WinApi.EM_REPLACESEL,0,sb);
26
27
string lpszClass_Submit = "Button"; //需要查找的Button的类名
28
string lpszName_Submit = "发送(&S)"; //需要查找的Button的标题
29
IntPtr TButtonHandle = WinApi.FindWindowEx(EdithParentWnd,new IntPtr(0),lpszClass_Submit,lpszName_Submit);
30
WinApi.SendMessage(TButtonHandle,WinApi.WM_CLICK,new IntPtr(0),"");//发送消息到目标控件使它执行click事件
31
}
32
33
/**//// <summary>
34
/// 获取消息
35
/// </summary>
36
/// <param name="windowName">窗口标题</param>
37
/// <returns></returns>
38
public static string GetMsg(string windowName)
39
{
40
string lpszParentClass = "#32770"; //整个窗口的类名
41
string lpszParentWindow = windowName; //窗口标题
42
IntPtr ip = WinApi.FindWindow(lpszParentClass,lpszParentWindow);
43
IntPtr EdithWnd = WinApi.FindWindowEx(ip,new IntPtr(0),"#32770","");
44
45
string lpszClass_Text = "RichEdit20A"; //查找历史记录类
46
string lpszName_Text = ""; //查找历史记录类的标题
47
IntPtr THandle = WinApi.FindWindowEx(EdithWnd,new IntPtr(0),lpszClass_Text,lpszName_Text);
48
49
StringBuilder sb = new StringBuilder(300000);
50
WinApi.SendMessage(THandle,WinApi.WM_GETTEXT,255,sb);//发送消息到目标控件
51
WinApi.SendMessage(THandle,WinApi.WM_SETTEXT,0,"");
52
return sb.ToString();
53
}
54
}
东西到手了,传话筒的工作基本上算是完成了,接下来就让它显示出来:
1
/**//// <summary>
2
/// 时钟事件
3
/// </summary>
4
/// <param name="sender"></param>
5
/// <param name="e"></param>
6
private void tmGetMsg_Tick(object sender, System.EventArgs e)
7
{
8
//群1里的消息
9
string strMsg = QQHooks.GetMsg(txtGroupWinName1.Text);
10
string str = "";
11
12
if(!string.Empty.Equals(strMsg))
13
{
14
ArrayList msgList = ParseMsg.Parse(strMsg);
15
16
foreach(QQMsg msg in msgList)
17
{
18
if("253822559" == msg.Number.ToString())continue;
19
20
if(string.Empty.Equals(msg.Msg.Trim()))
21
str = string.Format("{0}在群1里做了个表情/r/n",msg.Name,msg.Msg);
22
else
23
str = string.Format("{0}在群1里说:/r/n{1}/r/n",msg.Name,msg.Msg);
24
25
lbGroupMsgList1.Items.Add(str);
26
//save msg
27
28
//发送消息
29
QQHooks.SendMsg(txtGroupWinName2.Text,str);
30
QQHooks.SendMsg(txtGroupWinName3.Text,str);
31
32
}
33
}
34
}
这里的txtGroupWinName1是让输入qq窗口标题。以前用asm32做程序的时候就觉的微软够BT的,要是每个窗口编译的时候就给限制个GUID多好—()—*)((—
至此大功算是告成了,完美交差。拿着这东东,改天狠狠的宰我师兄几顿.
(07-01-04)续:
要的人太多了,我还是主动把东西传上来吧,要不然有骗 email地址之嫌
源代码和相关资料下载:/Files/sukyboor/Q.rar
附,说明:先介绍一下http方法:
1,qq接口.txt
是我在网络上找的一篇“C#编写QQ接口软件--QQ协议篇” 里面有QQhttp协议访问的详细的介绍,协议标准是v1.1。但是经过我是没调通,好象是http://tqq.tencent.com:8000被封了,你有没有好的运气我就不知道了。tx的webqq用的端口是http://webqq-proxy.qq.com:8080/这个就是慢点,用还是能用的。
2,Maxthon_Appin 文件夹下面有2个文件QQTest.txt ,GetQQSession.txt。maxthon有个简易收集面板你可以动态的去调试脚本.用maxthon打开http://webqq.qq.com后装入qqtest.txt你会发现访问过程的一举一动都在你的监视之中。Log.txt就是这么来的。GetQQSession.txt操作同上,用于获取一个新的sessionid
3,log.txt是监视http://webqq.qq.com的访问过程后得来的.你可以参考qq接口.txt看。不过tx的webqq用的是v1.0的接口,但大体上是相似的,相信聪明的你是可以看懂的。
4,webqq文件夹下放着http://webqq.qq.com被我下到本地的页面。有兴趣的可以去看看里面的脚本,尤其是js/web_cmd.js虽然写的比我还烂,但还是值得一看。
5,WQQ文件夹下放着我写的测试页面。不过我家的破电脑调不通。如果你运气好的话,在这个基础上继续干吧。不过别忘记了,到时候把做好的东西发给我一份(sukyboor·163.com)。
好了,下面说说钩子方法
项目在TQQ文件夹下面,注释写的挺详细的,自己看吧。
就提醒4点,
1 是app.config里面的qqnum一定要配置成你的qq号,否则你就等着别人骂你sx吧。
2 主窗口上的几个输入框一定要配置成群聊窗口的标题,否则它啥也干不了
3 别告诉我你还用qq2005
4 消息被转发以后在窗口里是看不到的,得点聊天记录按纽以后才能看的见
license.txt
里面堆的是一堆套话,有空就瞅2眼.
第一种办法不是不能用,可能是我网络的问题。
我这里收了很多资料,有兴趣的朋友可以下下去看
代码写的不是一般的烂,砖头的不要
hj821111@gmail.com
谢谢..
DoublePSD@sohu.com
谢谢
ruanyu83@gmail.com
3Q
classweb #126.com,谢谢.
dohu1234@21cn.com
haaron.john@gmail.com 谢谢
scotoma@163.com
看上去不错也想要一份谢谢了....
为什么有现成的不用。
PYTHON社区早有人写过QQ桥,以前我们就用他,几个群的消息共通。使用SVN下载。要PYTHON相关环境
Trac:http://trac.easiest.cn/cgi-bin/trac.cgi
svn:http://www.easiest.cn/svn/Python-QQ
缺省用户名和密码为Python-QQ
缺省用户名和密码只有读的权利,无写入权利。
引:
2006-12-19 公司三个站点整和到一起了,开通了论坛,大家可以到bbs.easiest.cn提出问题.
2006-7-22 修改数据包为2006,并修改了根登陆服务器地址。能正常login和list还有发送接收消息了.
2005-10-9 桥接了四个群,测试中。
2005-10-9 增加了对群消息的处理,将Python-QQ-bri做了两个群的桥接。
2005-09-26 将tea算法部分的中文注释提交上来了。
2005-09-10 能发送消息了,不过不稳定。
2005-09-09 增加了qqlib的部分注释。对qqlib的处理方法做了小调整。
2005-09-09 修改了GUI部分,能得到好友列表了,但是发送消息未完成。
2005-09-09 修改了GUI部分,能够正常登陆了。
2005-09-08 增加了对发送消息不成功的判断,但是未自动重发。
2005-08-11 增加了qq.login属性,为1时登陆成功。
2005-08-01 修改了消息处理方式,目前只处理了好友消息和陌生人消息。修正了改变当前状态的一处错误。
2005-07-30 按照limodou和其他朋友的提意,将编码改变为UTF-8,并通过os模块本程序自动在win和*uix下切换编码。将qqlib独立处理,分别进行控制台和图形界面的分工工作。hhgs.efhilt@gmail.com朋友提供了一个gui的程序,但是没有调试通过。将输入密码的地方使用了getpass模块。加上了登陆成功的提示。
2005-07-29 yxxyun@gmail.com朋友的提醒下,发现了一个命令定义错误。更改过来。
2005-07-28 因为朋友们反映在linux下不能使用,于是进行测试,发现2.3不支持某种方法的字典操作,更改update方法后,在FreeBSD 5.3下运行成功。
2005-07-27 释放出第一个版本,环境支持需要Python 2.4 以及twisted 2.01。目前实现的功能有:登陆、发送活动包、列好友、列在线好友、发送消息、接受好友消息、退出登陆。
在家闲着也不能干闲着,总得做点事情,想起前段时间一个师兄交代给我的任务:把若干个qq群串在一起。X国的政策一向比较Bt,你说开个群还要限制人数。H大在深圳有几千校友,一个群怎么可能放的下那么多人。好多在tx工作的师兄,明确告诉:我买通tx的人是不大可能了,搞一个传话筒才是解决之道。
事情虽小,但也着实麻烦。你说要去分析QQ具体数据包,万一哪天tx一高兴把数据给改了,或者接口开放了,也够我郁闷一壶的了。那就找个最简单的办法吧,左一顿baidu,又一顿google. “QQ接口”搜出来的结果绝大多数是关于tx qq的http接口,既然大家那么推崇,那我就从Http接口下手,于是把我以前写的AJAX给拆了,在把所谓的qq接口研究成果给鼓捣在一起,然后去webqq(http://webqq.qq.com)上大抢一遍,那家伙,天昏地暗,相当的&(&(。
代码我是用script写的:
异步AJAX会话类
1
//异步AJAX会话类
2
if(typeof(AjaxSession) == 'undefined')
3
var AjaxSession = function()
{
4
5
//创建会话
6
this.CreateSession = function()
7
{
8
if (window.ActiveXObject)
{ // IE
9
try
{
10
return new ActiveXObject('Microsoft.XMLHTTP');
11
}catch(e)
{}
12
13
try
{
14
return new ActiveXObject('Msxml2.XMLHTTP');
15
}catch(ee)
{}
16
}else
{ //Mozilla, Safari
17
var s = new XMLHttpRequest();
18
if (s.readyState == null)
{
19
s.readyState = 1;
20
s.addEventListener("load", function ()
{
21
s.readyState = 4;
22
if (typeof(s.onreadystatechange) == "function")
23
s.onreadystatechange();
24
}, false);
25
}
26
27
return s;
28
}
29
30
return null;
31
}
32
33
//进行请求
34
this.Request = function(url, params, callback)
35
{
36
37
var s = this.CreateSession();
38
if(null == s)
39
alert("对不起,您的浏览器不支持某些特性。");
40
else
41
s.abort();
42
43
var isAsync = typeof(callback) == 'function';
44
var method = !params ? "GET" : "POST";
45
46
if(isAsync) s.onreadystatechange = function()
47
{
48
try
{
49
alert(s.status);
50
if ((4 == s.readyState) && (200 == s.status || 304 == s.status))
51
callback(this.Response(s));
52
else
53
alert("请求错误,错误原因:" + s.statusText);
54
}catch(e)
{}
55
}
56
57
s.open(method, url, isAsync);
58
s.setRequestHeader("Connection","Keep-Alive");
59
s.setRequestHeader("Content-Type","text/html; charset=gb2312");
60
//s.setRequestHeader("Content-Type","text/plain; charset=UTF-8");
61
62
if(method == "POST")
63
{
64
s.setRequestHeader("Content-Length",params.length)
65
s.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
66
67
}
68
69
alert(params);
70
s.send(params);
71
72
73
if(!isAsync)
74
return this.Response(s);
75
}
76
77
//返回应答信息
78
this.Response = function(s)
79
{
80
if(s.status == 200 || 304 == s.status)
81
{
82
if(s.responseXML != null && s.responseXML.xml != null && s.responseXML.xml != '')
83
return s.responseXML;
84
else
85
return s.responseText;
86
}
87
}
88
89
//对字符串进行编码
90
this.UncCoding = function(s)
91
{
92
var output = '';
93
for(var i = 0 ;i< s.length;i++)
{
94
output = output + '%' + s.charCodeAt(i);
95
}
96
97
return output;
98
}
99
100
//获取xml结构
101
this.GetDom = function(s)
{
102
var doc = new ActiveXObject('Microsoft.XMLDOM');
103
doc.async = false;
104
doc.loadXML(s) ;
105
return doc;
106
}
107
108
return this;
109
}
//QQ会话类
1
//会话类
2
if(typeof(QQSession) == 'undefined')
3
var QQSession = function()
{
4
this.UIN = 0;
5
this.Md5PasswordStr = "";
6
this.WebQQUrl = "http://tqq.tencent.com:8000/";
7
this.qs = null;
8
this.isLogin = false;
9
this.SeqIndex = null;
10
11
//用户登陆
12
this.Login = function(uin,passwd,vcode,qs)
{
13
var m5 = new MD5();
14
this.UIN = uin;
15
this.Md5PasswordStr = m5.calcMD5(passwd);
16
var CmdStr = "VER=1.0&CMD=1&SEQ=" + this.GetNewSEQ() + "&UIN=" + uin + "&PS=" + this.Md5PasswordStr + "&STATUS=10&VCODE=" + vcode + "&QQSESSION=" + qs ;
17
18
//if(!this.qs)
19
// this.qs = new AjaxSession();
20
window.frames["proxy"].request(this.WebQQUrl,CmdStr);
21
//this.qs.Request(this.WebQQUrl,CmdStr,this.ShowMsg);
22
23
//document.getElementById("ssl_login").callback = this.ShowMsg;
24
//document.getElementById("ssl_login").src = "https://webqq-proxy.qq.com/webqq/l?"+ CmdStr;
25
}
26
27
//用户信息
28
this.GetInfo = function()
{
29
var CmdStr = "VER=1.0&CMD=10&SEQ=" + this.GetNewSEQ() + "&UIN=" + this.UIN + "&FUIN=" + this.UIN;
30
this.qs.Request(this.WebQQUrl,CmdStr,this.ShowMsg);
31
//window.frames["proxy"].request(this.WebQQUrl,CmdStr);
32
}
33
34
//获取好友列表
35
this.GetList = function()
{
36
var CmdStr = "VER=1.0&CMD=2&SEQ=" + this.GetNewSEQ() + "&UIN=" + this.UIN + "&NPOS=0";
37
this.qs.Request(this.WebQQUrl,CmdStr,this.ShowMsg);
38
}
39
40
//获得新的SEQ
41
this.GetNewSEQ = function()
{
42
if(!this.SeqIndex)
{
43
var d = new Date();
44
this.SeqIndex = d.getTime()
45
}
46
47
this.SeqIndex ++;
48
return this.SeqIndex;
49
}
50
51
this.ShowMsg = function(s)
{
52
alert(s);
53
}
54
55
return this;
56
}
我在那用天真的眼神,盼望着能从这个地方掏出点东西来。可偏偏我这个比较倒霉的孩子,碰到了极其复杂的网络问题(家穷人丑,只好用手机上网,速度回到上世纪90年代),掏了半天啥也没弄到,返回的尽是12152错误。
去翻MSDN时,遇到几个头疼的单词(鄙人英语着实差劲,单词量屈指可数),很习惯的就去开金山词霸。等等,金山词霸能把别的窗口的信息给拽出来,为什么我就不能。于是我就抛弃了前面的工作,从QQ对话窗口下手。nndx,偶就不信了,偶还灭不了你。
说干就干,那就先勾吧,.net好象是干不了这事,但是winapi还是能干这活的。win32编程嘛,不就几个消息循环(—(—……*(—
WinApi调用
1
using System;
2
using System.Drawing;
3
using System.Runtime.InteropServices;
4
5
namespace TQQ
6
{
7
/**//// <summary>
8
/// WinApi调用
9
/// </summary>
10
public class WinApi
11
{
12
/**//// <summary>
13
/// 根据鼠标位置获取窗体
14
/// </summary>
15
/// <param name="lpPoint"></param>
16
/// <returns></returns>
17
[DllImport("user32.dll")]
18
public static extern IntPtr WindowFromPoint(Point lpPoint);
19
20
/**//// <summary>
21
/// 获取鼠标位置
22
/// </summary>
23
/// <param name="lpPoint"></param>
24
/// <returns></returns>
25
[DllImport("user32.dll")]
26
public static extern int GetCursorPos(out Point lpPoint);
27
28
/**//// <summary>
29
/// 获取鼠标位置下的窗体
30
/// </summary>
31
/// <returns></returns>
32
public static IntPtr GetLocalWindow()
33
{
34
Point point;
35
GetCursorPos(out point);
36
return WindowFromPoint(point);
37
}
38
39
/**//// <summary>
40
/// 申请内存空间
41
/// </summary>
42
/// <param name="hProcess"></param>
43
/// <param name="lpAddress"></param>
44
/// <param name="dwSize"></param>
45
/// <param name="flAllocationType"></param>
46
/// <param name="flProtect"></param>
47
/// <returns></returns>
48
[ DllImport( "Kernel32.dll" )]
49
public static extern Int32 VirtualAllocEx(IntPtr hProcess,Int32 lpAddress,Int32 dwSize,Int16 flAllocationType,Int16 flProtect);
50
51
/**//// <summary>
52
/// 读取内存空间
53
/// </summary>
54
/// <param name="hProcess"></param>
55
/// <param name="lpBaseAddress"></param>
56
/// <param name="lpBuffer"></param>
57
/// <param name="nSize"></param>
58
/// <param name="lpNumberOfBytesWritten"></param>
59
/// <returns></returns>
60
[ DllImport( "Kernel32.dll" )]
61
public static extern int ReadProcessMemory(IntPtr hProcess, Int32 lpBaseAddress,byte[] lpBuffer,long nSize,long lpNumberOfBytesWritten);
62
63
/**//// <summary>
64
/// 写内存空间
65
/// </summary>
66
/// <param name="hProcess"></param>
67
/// <param name="lpBaseAddress"></param>
68
/// <param name="lpBuffer"></param>
69
/// <param name="nSize"></param>
70
/// <param name="lpNumberOfBytesWritten"></param>
71
/// <returns></returns>
72
[ DllImport( "Kernel32.dll" )]
73
public static extern int WriteProcessMemory(IntPtr hProcess, Int32 lpBaseAddress,byte[] lpBuffer,long nSize,long lpNumberOfBytesWritten);
74
75
/**//// <summary>
76
/// 根据类/标题查找窗口
77
/// </summary>
78
/// <param name="lpClassName"></param>
79
/// <param name="lpWindowName"></param>
80
/// <returns></returns>
81
[DllImport("User32.dll",EntryPoint="FindWindow")]
82
public static extern IntPtr FindWindow(string lpClassName,string lpWindowName);
83
84
/**//// <summary>
85
/// 获取窗口子对象
86
/// </summary>
87
/// <param name="hwndParent"></param>
88
/// <param name="hwndChildAfter"></param>
89
/// <param name="lpszClass"></param>
90
/// <param name="lpszWindow"></param>
91
/// <returns></returns>
92
[DllImport("user32.dll",EntryPoint="FindWindowEx")]
93
public static extern IntPtr FindWindowEx(IntPtr hwndParent,IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
94
95
/**//// <summary>
96
/// 发送windows消息
97
/// </summary>
98
/// <param name="hWnd"></param>
99
/// <param name="Msg"></param>
100
/// <param name="wParam"></param>
101
/// <param name="lParam"></param>
102
/// <returns></returns>
103
[DllImport("User32.dll")]
104
public static extern IntPtr SendMessage(IntPtr hWnd,int Msg,IntPtr wParam,IntPtr lParam);
105
106
/**//// <summary>
107
/// 发送windows消息
108
/// </summary>
109
/// <param name="hWnd"></param>
110
/// <param name="Msg"></param>
111
/// <param name="wParam"></param>
112
/// <param name="lParam"></param>
113
/// <returns></returns>
114
[DllImport("User32.dll",EntryPoint="SendMessage")]
115
public static extern int SendMessage(IntPtr hWnd,int Msg, IntPtr wParam, string lParam);
116
117
/**//// <summary>
118
/// 发送windows消息
119
/// </summary>
120
/// <param name="hwnd"></param>
121
/// <param name="wMsg"></param>
122
/// <param name="wParam"></param>
123
/// <param name="lParam"></param>
124
/// <returns></returns>
125
[DllImport("user32.dll", CharSet = CharSet.Auto)]
126
public static extern int SendMessage( IntPtr hwnd, int wMsg, int wParam,string lParam);
127
128
/**//// <summary>
129
/// 发送windows消息
130
/// </summary>
131
/// <param name="hwnd"></param>
132
/// <param name="wMsg"></param>
133
/// <param name="wParam"></param>
134
/// <param name="lParam"></param>
135
/// <returns></returns>
136
[DllImport("user32.dll", CharSet = CharSet.Auto)]
137
public static extern int SendMessage( IntPtr hwnd, int wMsg, int wParam,int lParam);
138
139
/**//// <summary>
140
/// 发送windows消息
141
/// </summary>
142
/// <param name="hwnd"></param>
143
/// <param name="wMsg"></param>
144
/// <param name="wParam"></param>
145
/// <param name="lParam"></param>
146
/// <returns></returns>
147
[DllImport("user32.dll", CharSet = CharSet.Auto)]
148
public static extern int SendMessage( IntPtr hwnd, int wMsg, int wParam,System.Text.StringBuilder lParam);
149
150
public const int WM_GETTEXT = 0x000D;
151
public const int WM_GETTEXTLENGTH = 0x000E;
152
public const int WM_SETTEXT = 0x000C;
153
public const int WM_CLICK = 0x00F5;
154
public const int WM_CHAR = 0x0102;
155
public const int EM_SETSEL = 0x00B1;
156
public const int EM_REPLACESEL = 0x00C2;
157
158
}
159
}
QQ钩子
1
/**//// <summary>
2
/// QQ钩子
3
/// </summary>
4
public class QQHooks
5
{
6
/**//// <summary>
7
/// 发送消息
8
/// </summary>
9
/// <param name="windowName">窗口标题</param>
10
/// <param name="strMsg">消息内容</param>
11
public static void SendMsg(string windowName,string strMsg)
12
{
13
string lpszParentClass = "#32770"; //整个窗口的类名
14
string lpszParentWindow = windowName; //窗口标题
15
IntPtr ip = WinApi.FindWindow(lpszParentClass,lpszParentWindow);
16
IntPtr EdithParentWnd = WinApi.FindWindowEx(ip,new IntPtr(0),"#32770","");
17
IntPtr EdithWnd = WinApi.FindWindowEx(EdithParentWnd,new IntPtr(0),"AfxWnd42","");
18
19
string lpszClass_Text = "RICHEDIT"; //消息输入窗口
20
string lpszName_Text = ""; //消息输入窗口
21
IntPtr THandle = WinApi.FindWindowEx(EdithWnd,new IntPtr(0),lpszClass_Text,lpszName_Text);
22
23
StringBuilder sb = new StringBuilder(strMsg);
24
WinApi.SendMessage(THandle,WinApi.EM_SETSEL,-1,-1);//
25
WinApi.SendMessage(THandle,WinApi.EM_REPLACESEL,0,sb);
26
27
string lpszClass_Submit = "Button"; //需要查找的Button的类名
28
string lpszName_Submit = "发送(&S)"; //需要查找的Button的标题
29
IntPtr TButtonHandle = WinApi.FindWindowEx(EdithParentWnd,new IntPtr(0),lpszClass_Submit,lpszName_Submit);
30
WinApi.SendMessage(TButtonHandle,WinApi.WM_CLICK,new IntPtr(0),"");//发送消息到目标控件使它执行click事件
31
}
32
33
/**//// <summary>
34
/// 获取消息
35
/// </summary>
36
/// <param name="windowName">窗口标题</param>
37
/// <returns></returns>
38
public static string GetMsg(string windowName)
39
{
40
string lpszParentClass = "#32770"; //整个窗口的类名
41
string lpszParentWindow = windowName; //窗口标题
42
IntPtr ip = WinApi.FindWindow(lpszParentClass,lpszParentWindow);
43
IntPtr EdithWnd = WinApi.FindWindowEx(ip,new IntPtr(0),"#32770","");
44
45
string lpszClass_Text = "RichEdit20A"; //查找历史记录类
46
string lpszName_Text = ""; //查找历史记录类的标题
47
IntPtr THandle = WinApi.FindWindowEx(EdithWnd,new IntPtr(0),lpszClass_Text,lpszName_Text);
48
49
StringBuilder sb = new StringBuilder(300000);
50
WinApi.SendMessage(THandle,WinApi.WM_GETTEXT,255,sb);//发送消息到目标控件
51
WinApi.SendMessage(THandle,WinApi.WM_SETTEXT,0,"");
52
return sb.ToString();
53
}
54
}
东西到手了,传话筒的工作基本上算是完成了,接下来就让它显示出来:
1
/**//// <summary>
2
/// 时钟事件
3
/// </summary>
4
/// <param name="sender"></param>
5
/// <param name="e"></param>
6
private void tmGetMsg_Tick(object sender, System.EventArgs e)
7
{
8
//群1里的消息
9
string strMsg = QQHooks.GetMsg(txtGroupWinName1.Text);
10
string str = "";
11
12
if(!string.Empty.Equals(strMsg))
13
{
14
ArrayList msgList = ParseMsg.Parse(strMsg);
15
16
foreach(QQMsg msg in msgList)
17
{
18
if("253822559" == msg.Number.ToString())continue;
19
20
if(string.Empty.Equals(msg.Msg.Trim()))
21
str = string.Format("{0}在群1里做了个表情/r/n",msg.Name,msg.Msg);
22
else
23
str = string.Format("{0}在群1里说:/r/n{1}/r/n",msg.Name,msg.Msg);
24
25
lbGroupMsgList1.Items.Add(str);
26
//save msg
27
28
//发送消息
29
QQHooks.SendMsg(txtGroupWinName2.Text,str);
30
QQHooks.SendMsg(txtGroupWinName3.Text,str);
31
32
}
33
}
34
}
这里的txtGroupWinName1是让输入qq窗口标题。以前用asm32做程序的时候就觉的微软够BT的,要是每个窗口编译的时候就给限制个GUID多好—()—*)((—
至此大功算是告成了,完美交差。拿着这东东,改天狠狠的宰我师兄几顿.
(07-01-04)续:
要的人太多了,我还是主动把东西传上来吧,要不然有骗 email地址之嫌
源代码和相关资料下载:/Files/sukyboor/Q.rar
附,说明:先介绍一下http方法:
1,qq接口.txt
是我在网络上找的一篇“C#编写QQ接口软件--QQ协议篇” 里面有QQhttp协议访问的详细的介绍,协议标准是v1.1。但是经过我是没调通,好象是http://tqq.tencent.com:8000被封了,你有没有好的运气我就不知道了。tx的webqq用的端口是http://webqq-proxy.qq.com:8080/这个就是慢点,用还是能用的。
2,Maxthon_Appin 文件夹下面有2个文件QQTest.txt ,GetQQSession.txt。maxthon有个简易收集面板你可以动态的去调试脚本.用maxthon打开http://webqq.qq.com后装入qqtest.txt你会发现访问过程的一举一动都在你的监视之中。Log.txt就是这么来的。GetQQSession.txt操作同上,用于获取一个新的sessionid
3,log.txt是监视http://webqq.qq.com的访问过程后得来的.你可以参考qq接口.txt看。不过tx的webqq用的是v1.0的接口,但大体上是相似的,相信聪明的你是可以看懂的。
4,webqq文件夹下放着http://webqq.qq.com被我下到本地的页面。有兴趣的可以去看看里面的脚本,尤其是js/web_cmd.js虽然写的比我还烂,但还是值得一看。
5,WQQ文件夹下放着我写的测试页面。不过我家的破电脑调不通。如果你运气好的话,在这个基础上继续干吧。不过别忘记了,到时候把做好的东西发给我一份(sukyboor·163.com)。
好了,下面说说钩子方法
项目在TQQ文件夹下面,注释写的挺详细的,自己看吧。
就提醒4点,
1 是app.config里面的qqnum一定要配置成你的qq号,否则你就等着别人骂你sx吧。
2 主窗口上的几个输入框一定要配置成群聊窗口的标题,否则它啥也干不了
3 别告诉我你还用qq2005
4 消息被转发以后在窗口里是看不到的,得点聊天记录按纽以后才能看的见
license.txt
里面堆的是一堆套话,有空就瞅2眼.
Feedback
#1楼 [楼主] 回复 引用 查看
2007-01-03 11:28 by 笨小苏第一种办法不是不能用,可能是我网络的问题。
我这里收了很多资料,有兴趣的朋友可以下下去看
代码写的不是一般的烂,砖头的不要
#2楼 回复 引用 查看
2007-01-03 11:40 by CCC[匿名] [未注册用户]hj821111@gmail.com
谢谢..
#3楼 回复 引用 查看
2007-01-03 11:59 by Double [未注册用户]DoublePSD@sohu.com
谢谢
#4楼 回复 引用 查看
2007-01-03 12:24 by yoshow[匿名] [未注册用户]ruanyu83@gmail.com
3Q
#5楼 回复 引用 查看
2007-01-03 12:30 by wu [未注册用户]classweb #126.com,谢谢.
#6楼 回复 引用 查看
2007-01-03 12:30 by sunlife[匿名] [未注册用户]dohu1234@21cn.com
#7楼 回复 引用 查看
2007-01-03 12:51 by haaron[匿名] [未注册用户]haaron.john@gmail.com 谢谢
#8楼 回复 引用 查看
2007-01-03 12:56 by scotomascotoma@163.com
看上去不错也想要一份谢谢了....
#9楼 回复 引用 查看
2007-01-03 13:04 by j[匿名] [未注册用户]为什么有现成的不用。
PYTHON社区早有人写过QQ桥,以前我们就用他,几个群的消息共通。使用SVN下载。要PYTHON相关环境
Trac:http://trac.easiest.cn/cgi-bin/trac.cgi
svn:http://www.easiest.cn/svn/Python-QQ
缺省用户名和密码为Python-QQ
缺省用户名和密码只有读的权利,无写入权利。
引:
2006-12-19 公司三个站点整和到一起了,开通了论坛,大家可以到bbs.easiest.cn提出问题.
2006-7-22 修改数据包为2006,并修改了根登陆服务器地址。能正常login和list还有发送接收消息了.
2005-10-9 桥接了四个群,测试中。
2005-10-9 增加了对群消息的处理,将Python-QQ-bri做了两个群的桥接。
2005-09-26 将tea算法部分的中文注释提交上来了。
2005-09-10 能发送消息了,不过不稳定。
2005-09-09 增加了qqlib的部分注释。对qqlib的处理方法做了小调整。
2005-09-09 修改了GUI部分,能得到好友列表了,但是发送消息未完成。
2005-09-09 修改了GUI部分,能够正常登陆了。
2005-09-08 增加了对发送消息不成功的判断,但是未自动重发。
2005-08-11 增加了qq.login属性,为1时登陆成功。
2005-08-01 修改了消息处理方式,目前只处理了好友消息和陌生人消息。修正了改变当前状态的一处错误。
2005-07-30 按照limodou和其他朋友的提意,将编码改变为UTF-8,并通过os模块本程序自动在win和*uix下切换编码。将qqlib独立处理,分别进行控制台和图形界面的分工工作。hhgs.efhilt@gmail.com朋友提供了一个gui的程序,但是没有调试通过。将输入密码的地方使用了getpass模块。加上了登陆成功的提示。
2005-07-29 yxxyun@gmail.com朋友的提醒下,发现了一个命令定义错误。更改过来。
2005-07-28 因为朋友们反映在linux下不能使用,于是进行测试,发现2.3不支持某种方法的字典操作,更改update方法后,在FreeBSD 5.3下运行成功。
2005-07-27 释放出第一个版本,环境支持需要Python 2.4 以及twisted 2.01。目前实现的功能有:登陆、发送活动包、列好友、列在线好友、发送消息、接受好友消息、退出登陆。
相关文章推荐
- 一步一步打造自己的编译器http://www.cnblogs.com/sukyboor/archive/2007/01/11/617406.html
- http://www.cnblogs.com/wengyuli/archive/2010/06/29/silverlight-video-chat.html
- http://www.cnblogs.com/zjz008/archive/2010/04/19/1715663.html
- mysql的数据类型- 特别是表示日期/时间的数据类型: 参考: http://www.cnblogs.com/bukudekong/archive/2011/06/27/2091590.html
- Win32应用程序中进程间通信方法分析与比较[转http://www.cnblogs.com/erwin/archive/2007/04/16/715084.html]
- http://www.cnblogs.com/yungboy/archive/2009/03/11/1408283.html
- http://www.cnblogs.com/yungboy/archive/2010/05/25/1743991.html
- http://www.cnblogs.com/yungboy/archive/2010/06/08/1753401.html
- VS2010 测试 -普通单元测试 http://www.cnblogs.com/rhythmK/archive/2012/04/20/2458832.html
- android权限大全转http://www.cnblogs.com/classic/archive/2011/06/20/2085055.html
- Unity3D界面功能操作讲解【转http://www.cnblogs.com/fortomorrow/archive/2012/10/28/unity01.html】
- 我对架构师的理解(如何成为一个合格的架构师)http://www.cnblogs.com/daoxuebao/archive/2012/06/14/2549967.html
- 转载至http://www.cnblogs.com/huxi/archive/2010/07/04/1771073.html
- http://www.cnblogs.com/bingoidea/archive/2009/08/05/1539656.html
- C#正则表达式整理备忘 转载(http://www.cnblogs.com/KissKnife/archive/2008/03/23/1118423.html)
- Android学习笔记之AndroidManifest.xml文件解析【转载地址:http://www.cnblogs.com/pilang/archive/2011/04/20/2022932.html】
- 两个div,一个左右排列不换行(zz:http://www.cnblogs.com/circlesport/archive/2007/03/15/676261.html)
- http://www.cnblogs.com/henw/archive/2012/01/06/2314870.html
- Javascript 操作select控件大全(新增、修改、删除、选中、清空、判断存在等)转自:http://www.cnblogs.com/zyh-nhy/archive/2007/08/08/847876.html
- @Html.ActionLink (转载自http://www.cnblogs.com/shizhi57/archive/2011/07/20/2111484.html)