有时候做程序,喜欢把程序的注册与用户QQ号码绑定,程序仅允许登录成功了指定QQ账号时才可使用,
为了实现这个目的,有人用API取QQ窗口、QQ托盘图标上的QQ账号,
但是这个方法写起来比较麻烦,如果用户有意玩玩的话,也可以自己在你软件获取之前先用API修改你要获取的目标信息!
还有一种方法就是内存读取,当然要找到一个QQ登录成功后存放QQ号码的地址,基址肯定是不存在的,再加之QQ更新频繁,
所以内存读取的办法也不太好,
为了实现这个目的,还有一种办法那就是利用QQ网页自身的功能,这种方法既方便又准确,下面就来说下原理:
打开: http://xui.ptlogin2.qq.com/cgi-bin/qlogin
我们会发现这也页面会自动获取我们的已登录的QQ信息,并可以实现快速登录,分析之:
关键的东西:
<script src="http://imgcache.qq.com/ptlogin/ac/v5/js/xui.js?v=1.2"></script>
通过分析这个js,我们找到如下2个重要的函数:
function ptui_qInit() 这个函数的作用是初始化SSOAxCtrlForPTLogin.SSOForPTLogin2对象,创建一个ActiveXObject对象
hummer_loaduin() 这个函数就是真正的通过 SSOAxCtrlForPTLogin这个COM来获取已登录QQ信息的,
到此,我们试着自己用程序来调用 SSOAxCtrlForPTLogin的com对象,但是发现失败,原因下面说,
既然不能自己调用 SSOAxCtrlForPTLogin对象,那先试试将页面保存为本地在打开看看什么情况,结果如下:
“快速登录失败,请您返回重试或切换到普通登录模式。”
很明显, SSOAxCtrlForPTLogin对象是要判断当前url的,如果url不是来自以下域名的都不能初始化成功:
var site=["qq.com","paipai.com","tencent.com","soso.com","taotao.com","tenpay.com","foxmail.com","wenwen.com","3366.com","imqq.com"];
好了,既然不能自己用本地页面,也不能自己写程序调用它的COM,那我们就直接来访问它获取它页面上已经获取好的信息吧:
同时附上已经格式好了的 xui.js代码,有兴趣的可以看看
xui.js
STR_QLOGIN
=
1
;STR_QLOGIN_OTHER_ERR
=
2
;STR_QLOGIN_SELECT_TIP
=
3
;STR_QLOGIN_NO_UIN
=
4
;STR_QLOGIN_SELECT_OFFLINE
=
5
;STR_QLOGINING
=
6
;
function
ptui_mapStr(B){
for
(i
=
0
;i
<
B.length;i
++
)
{
var
A
=
document.getElementById(B[i][
1
]);
if
(A
!=
null
)
{
if
(
"
A
"
==
A.nodeName
||
"
U
"
==
A.nodeName
||
"
OPTION
"
==
A.nodeName
||
"
LABEL
"
==
A.nodeName
||
"
P
"
==
A.nodeName)
{
if
(A.innerHTML
==
""
)
{
A.innerHTML
=
ptui_str(B[i][
0
])
}
}
else
{
if
(
"
INPUT
"
==
A.nodeName)
{
if
(A.value
==
""
)
{
A.value
=
ptui_str(B[i][
0
])
}
}
else
{
if
(
"
IMG
"
==
A.nodeName)
{
A.alt
=
ptui_str(B[i][
0
])
}
}
}
}
}
}
function
ptui_str(A){
A
-=
1
;
if
(A
>=
0
&&
A
<
g_strArray.length)
{
return
g_strArray[A]}
return
""
}
var
g_labelMap
=
new
Array([STR_QLOGIN,
"
loginbtn
"
],[STR_QLOGIN_SELECT_TIP,
"
qlogin_select_tip
"
]);
ptui_mapStr(g_labelMap);
function
getArgs(){
var
B
=
new
Object();
var
F
=
location.href.substring(location.href.indexOf(
"
/qlogin?
"
)
+
8
);
var
E
=
F.split(
"
&
"
);
for
(
var
C
=
0
;C
<
E.length;C
++
)
{
var
G
=
E[C].indexOf(
"
=
"
);
if
(G
==-
1
)
{
continue
}
var
A
=
E[C].substring(
0
,G);
var
D
=
E[C].substring(G
+
1
);
D
=
decodeURIComponent(D);
B[A]
=
D
}
return
B
}
var
params
=
getArgs();
var
g_qtarget
=
params.qtarget;
var
g_domain
=
params.domain;
var
g_jumpname
=
params.jumpname;
var
g_param
=
params.param;
var
site
=
[
"
qq.com
"
,
"
paipai.com
"
,
"
tencent.com
"
,
"
soso.com
"
,
"
taotao.com
"
,
"
tenpay.com
"
,
"
foxmail.com
"
,
"
wenwen.com
"
,
"
3366.com
"
,
"
imqq.com
"
];
var
flag
=
false
;
for
(
var
i
=
0
;i
<
site.length;i
++
)
{
if
(site[i]
==
g_domain)
{flag
=
true
}
}
if
(
!
flag)
{
g_domain
=
"
qq.com
"
}
var
q_bInit
=
false
;
var
q_hummerQtrl
=
null
;
var
g_vOptData
=
null
;
var
q_aUinList
=
new
Array();
function
ptui_qInit(){
if
(q_bInit)
{
return
}
q_bInit
=
true
;
if
(
!
window.ActiveXObject)
{
return
}
try
{
q_hummerQtrl
=
new
ActiveXObject(
"
SSOAxCtrlForPTLogin.SSOForPTLogin2
"
);
var
A
=
q_hummerQtrl.CreateTXSSOData();
q_hummerQtrl.InitSSOFPTCtrl(
0
,A);
g_vOptData
=
q_hummerQtrl.CreateTXSSOData();
hummer_loaduin();
if
(q_aUinList.length
<=
0
)
{
msg(ptui_str(STR_QLOGIN_NO_UIN));
return
false
}
else
{
if
(ptui_buildUinList)
{ptui_buildUinList(q_aUinList)}
}
document.cookie
=
"
ptui_qstatus=2;domain=ptlogin2.
"
+
g_domain
}
catch
(B)
{
q_hummerQtrl
=
null
;
document.cookie
=
"
ptui_qstatus=3;domain=ptlogin2.
"
+
g_domain;
msg(ptui_str(STR_QLOGIN_OTHER_ERR));
ptui_reportAttr(
89217
,
true
)
}
}
function
list(){
q_bInit
=
false
;
ptui_qInit();
xui_report()
}
function
ptui_buildUinList(){
var
G
=
""
;
var
E
=
document.getElementById(
"
list_uin
"
);
if
(
null
==
E)
{
return
}
var
A
=
q_aUinList.length
>
5
?
5
:q_aUinList.length;
for
(
var
C
=
0
;C
<
A;C
++
)
{
var
F
=
q_aUinList[C];
var
B
=
""
;
var
D
=
""
;
if
(q_aUinList.length
==
1
)
{D
=
'
style="display:none;"
'
}
if
(C
==
0
)
{B
=
"
checked='checked'
"
}
G
+=
"
<li><input type='radio' name='q_uin' id='uin_
"
+
F.uin
+
"
'
"
+
B
+
D
+
"
/><span>
"
+
F.nick.replace(
/
&
/
g,
"
&
"
).replace(
/
<
/
g,
"
<
"
).replace(
/
>
/
g,
"
>
"
)
+
"
(
"
+
F.name
+
"
)</span></li>
"
}
E.innerHTML
=
G
}
function
onQloginSelect(){
for
(
var
C
=
0
;C
<
q_aUinList.length;C
++
)
{
var
D
=
q_aUinList[C];
var
B
=
document.getElementById(
"
uin_
"
+
D.uin);
if
(B
!=
null
)
{
if
(B.checked)
{
hummer_loaduin();
var
A
=
hummer_getUinObj(D.uin);
if
(A
==
null
)
{
msg(ptui_str(STR_QLOGIN_SELECT_OFFLINE),
true
);
return
}
document.getElementById(
"
qlogin_loading
"
).innerHTML
=
'
<img src="http://imgcache.qq.com/ptlogin/v4/style/0/images/load.gif" align="absmiddle" />
'
+
ptui_str(STR_QLOGINING);
document.getElementById(
"
loginbtn
"
).className
=
"
btn_gray
"
;
document.getElementById(
"
loginbtn
"
).style.color
=
"
gray
"
;
hummer_login(A,g_domain,g_jumpname,g_param)
}
}
}
}
function
hummer_loaduin(){
q_aUinList.length
=
0
;
var
P
=
q_hummerQtrl.DoOperation(
1
,g_vOptData);
if
(
null
==
P)
{
return
}
try
{
var
M
=
P.GetArray(
"
PTALIST
"
);
var
T
=
M.GetSize();
var
O
=
""
;
var
F
=
document.getElementById(
"
list_uin
"
);
for
(
var
U
=
0
;U
<
T;U
++
)
{
var
C
=
M.GetData(U);
var
R
=
C.GetDWord(
"
dwSSO_Account_dwAccountUin
"
);
var
G
=
""
;
var
J
=
C.GetByte(
"
cSSO_Account_cAccountType
"
);
var
S
=
R;
if
(J
==
1
)
{
try
{
G
=
C.GetArray(
"
SSO_Account_AccountValueList
"
);
S
=
G.GetStr(
0
)
}
catch
(Q)
{}
}
var
K
=
0
;
try
{
K
=
C.GetWord(
"
wSSO_Account_wFaceIndex
"
)
}
catch
(Q)
{K
=
0
}
var
L
=
""
;
try
{
L
=
C.GetStr(
"
strSSO_Account_strNickName
"
)
}
catch
(Q)
{L
=
""
}
var
D
=
C.GetBuf(
"
bufGTKey_PTLOGIN
"
);
var
E
=
C.GetBuf(
"
bufST_PTLOGIN
"
);
var
I
=
""
;
var
A
=
E.GetSize();
for
(
var
N
=
0
;N
<
A;N
++
)
{
var
B
=
E.GetAt(N).toString(
"
16
"
);
if
(B.length
==
1
)
{B
=
"
0
"
+
B}
I
+=
B
}
var
H
=
{uin:R,name:S,type:J,face:K,nick:L,key:I};
q_aUinList[U]
=
H
}
switch
(q_aUinList.length)
{
case
0
:ptui_reportAttr(
77430
,
false
);
break
;
case
1
:ptui_reportAttr(
77431
,
false
);
break
;
default
:ptui_reportAttr(
77432
,
false
)
}
}
catch
(Q){}
}
function
hummer_getUinObj(B){
for
(
var
A
=
0
;A
<
q_aUinList.length;A
++
)
{
var
C
=
q_aUinList[A];
if
(C.uin
==
B)
{
return
C}
}
return
null
}
function
unloadpage(){
document.domain
=
g_domain;
try
{
parent.document.body.onbeforeunload
=
function
(){};
parent.document.body.onunload
=
function
(){};
for
(
var
A
=
0
;A
<
parent.parent.frames.length;A
++
)
{
parent.parent.frames[A].onunload
=
function
(){};
parent.parent.frames[A].onbeforeunload
=
function
(){}
}
if
(parent.parent
!=
top)
{
for
(
var
A
=
0
;A
<
parent.parent.parent.frames.length;A
++
)
{
parent.parent.parent.frames[A].onunload
=
function
(){};
parent.parent.parent.frames[A].onbeforeunload
=
function
(){}
}
}
}
catch
(B){}
}
function
hummer_login(E,D,A,F){
if
(A
==
""
)
{A
=
"
jump
"
}
var
C
=
"
http://ptlogin2.
"
+
D
+
"
/
"
+
A
+
"
?clientuin=
"
+
E.uin
+
"
&clientkey=
"
+
E.key
+
"
&keyindex=9
"
;
if
(F
!=
null
&&
F
!=
""
)
{
var
B
=
decodeURIComponent(F);
if
(B.indexOf(
"
#
"
)
>-
1
)
{
B
=
B.replace(
/
#
/
g,
"
%23
"
)
}
C
+=
(
"
&
"
+
B)
}
switch
(parseInt(g_qtarget))
{
case
0
:unloadpage();parent.location.href
=
C;
break
;
case
1
:top.location.href
=
C;
break
;
case
2
:unloadpage();parent.parent.location.href
=
C;
break
;
default
:top.location.href
=
C
}
}
function
msg(A){
try
{
var
C
=
document.getElementById(
"
qlogin_loading
"
);
if
((C.style.display
!=
"
none
"
)
&&
(document.getElementById(
"
qlogin
"
).style.display
!=
"
none
"
))
{
C.innerHTML
=
'
<span style="color:#cc0000;">
'
+
A
+
"
</span>
"
;C.style.display
=
""
}
}
catch
(B){}
}
function
xui_report(B){
if
(Math.random()
>
0.001
)
{
return
}
var
A
=
new
Date();
var
C
=
location.hash.substr(
1
,location.hash.length);
url
=
"
http://isdspeed.qq.com/cgi-bin/r.cgi?flag1=6000&flag2=1&flag3=2&1=
"
+
(A
-
C)
+
"
&2=
"
+
(A
-
time1);
imgTime
=
new
Image();
imgTime.src
=
url
}
function
ptui_reportAttr(C,B){
if
((B
==
false
)
&&
(Math.random()
>
0.001
))
{
return
}
url
=
"
http://ui.ptlogin2.
"
+
g_domain
+
"
/cgi-bin/report?id=
"
+
C;
var
A
=
new
Image();
A.src
=
url
}
list();
/*
|xGv00|0d5165981e8a571e21b5c15cc81a9130
*/
接着我们来直接实现程序吧,代码如下:
CheckLoginedQQ
using
System;
using
System.Windows.Forms;
namespace
CheckLoginedQQ
{
public
class
Checker
{
public
Checker()
{
}
private
HtmlDocument Document;
///
<summary>
///
初始化
///
</summary>
///
<returns></returns>
public
bool
Initialize()
{
WebBrowser browser
=
new
WebBrowser();
browser.Url
=
new
Uri(
"
http://xui.ptlogin2.qq.com/cgi-bin/qlogin
"
);
while
(browser.ReadyState
!=
WebBrowserReadyState.Complete)
{
Application.DoEvents();
}
if
(browser.Document.Url.AbsoluteUri
==
"
http://xui.ptlogin2.qq.com/cgi-bin/qlogin
"
)
{
Document
=
browser.Document;
return
true
;
}
return
false
;
}
///
<summary>
///
检测登陆账号
///
</summary>
///
<param name="uin"></param>
///
<returns></returns>
public
bool
QQisLogined(
string
uin)
{
HtmlElementCollection elements
=
Document.GetElementsByTagName(
"
input
"
);
foreach
(HtmlElement element
in
elements)
{
string
type
=
element.GetAttribute(
"
type
"
);
if
(type
!=
"
radio
"
)
continue
;
string
name
=
element.GetAttribute(
"
name
"
);
if
(name
!=
"
q_uin
"
)
continue
;
string
id
=
element.GetAttribute(
"
id
"
);
if
(id
==
"
uin_
"
+
uin)
{
return
true
;
}
}
return
false
;
}
}
}
首先用Webbrowser控件访问,http://xui.ptlogin2.qq.com/cgi-bin/qlogin
通过ReadState属性判断页面是否加载完成
通过Document.url判断加载时候为http://xui.ptlogin2.qq.com/cgi-bin/qlogin页面
然后返回真或假
Initialize() == true 之后通过Webbrowser.Document来获取页面上的QQ信息,具体实现看代码!
好了,基本就是这样了,不过要注意的一点是Webbrowser是不能跨线程实例化的,因为他是一个基于COM的控件,所以必须使用 [STAThread] 管理线程
使用示例如下:
[STAThread]
static void Main(string[] args)
{
CheckLoginedQQ.Checker checker = new CheckLoginedQQ.Checker();
if (checker.Initialize())
{
if(checker.QQisLogined("110001"));
Console.Write("Logined");
else
Console.Write("Not Logined");
}
else
{
Console.Write("un Initialize");
}
}