不少微信QQ机器人大多通过分析通讯包,模拟包方式实现消息的发送,该方式会随着QQ 微信的升级儿很容易失效需要不断升级。通过模拟界面操作方式虽然也存在界面改变失效的问题,但该方式相对协议方式失效的周期应该更长一点。闲来无事儿,实现一个简单QQ消息投送,原理主要通过Go实现web接口便于外部通过浏览器或http或websocket接口给指定的QQ发送消息,web服务接收到消息后,通过回调函数通知VC实现对指定QQ窗口操作完成消息的发送
VC主要通过查找指定QQ号主窗口,查找要发送QQ消息的QQ号,模拟点击,模拟键盘输入,实现消息的投送
Go编写dll由VC调用
主要代码实现如下
Go部分
//Go导出函数便于VC调用
/*
#cgo CFLAGS: -I .
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef void (*callback)(int,void *,int,void *,int);
extern void c_callback (int,void *,int,void *,int);
extern callback _cb;
*/
import "C"
import "unsafe"
/*以下两行标识导出特别重要*/
//InitHttpWebSocket :
//export InitHttpWebSocket
//初始Web服务和websocket服务,node为websocket接口调用名,nPort为web服务接口,pClass为VC的类指针,p为回调函数
func InitHttpWebSocket(node string, nPort int, pClass int, p C.callback) (bool, string) {
//myConfig := new(Config.Config)
//sInitFile := Share.GetCurrentDirectory() + "/web/conf/appi"
//myConfig.InitConfig(sInitFile)
m_AddrMap = make(map[string]OneWSLink)
if p != nil {
C._cb = p
//WebSocketCallBack(0, "call OK", 4)
pSaveClass = pClass
}
t1 := time.Now()
go InitHTTP(t1, nPort, node)
str := "正在初始化"
WebSocketCallBack(pSaveClass, "", 0, str)
return true, "正在初始化"
}
//数据处理函数
func ActionAPI(res http.ResponseWriter, req *http.Request, ModeName, FName string, m_VarHH map[string]interface{}) {
fmt.Println(ModeName, FName)
var m_ReturnJson ReturnJson
switch ModeName {
case "CORESYS.SYS":
switch FName {
case "API":
//获得参数核实参数合法性
ok, _ := GetParameValues(m_VarHH, "appid", "sign", "action")
if !ok {
m_ReturnJson.BOK = false
m_ReturnJson.sg = "缺少必要参数"
NETReturnData(res, req, m_ReturnJson)
return
}
var keyArray = [...]string{}
keyArrayT := keyArray[:]
for k, _ := range m_VarHH {
if k != "sign" {
keyArrayT = append(keyArrayT, k)
}
}
sort.Strings(keyArrayT)
fmt.Println(keyArrayT)
_, appid := GetParameValue(m_VarHH, "appid")
_, sign := GetParameValue(m_VarHH, "sign")
appkeyString := ""
if isDBSave {
fmt.Println("采用数据库存储")
ok, m_Rows := m_baseDB.XNGetRecord(false, "select appkey from sys_apps where appid=?", appid)
if ok {
if len(m_Rows) == 0 {
m_ReturnJson.BOK = false
m_ReturnJson.sg = "未能查询到appid:" + appid
NETReturnData(res, req, m_ReturnJson)
return
}
appkey, ok := m_Rows[0]["appkey"]
if ok {
appkeyString = appkey.(string)
} else {
m_ReturnJson.BOK = false
m_ReturnJson.sg = "查询appid:" + appid + "的appkey失败"
NETReturnData(res, req, m_ReturnJson)
}
} else {
m_ReturnJson.BOK = false
m_ReturnJson.sg = "查询appid:" + appid + "失败"
NETReturnData(res, req, m_ReturnJson)
return
}
} else {
fmt.Println("采用INI存储")
m_oneApp, ok := m_AppIDMAP[appid]
if ok {
appkeyString = m_oneApp.AppKey
} else {
m_ReturnJson.BOK = false
m_ReturnJson.sg = "查询appid:" + appid + "失败"
NETReturnData(res, req, m_ReturnJson)
return
}
}
ok, m_PArray := GetParameValues(m_VarHH, keyArrayT...)
str := ""
for i := 0; i < len(m_PArray); i++ {
str += m_PArray[i]
}
str += appkeyString
fmt.Println("原始计算:" + str)
str = Share.GetMd5String(str)
fmt.Println("计算结果:" + str)
if str == sign {
bArray, _ := json.Marshal(m_VarHH)
jsonString := string(bArray)
//调用VC回调函数
WebSocketCallBack(pSaveClass, req.RemoteAddr, 1, jsonString)
m_ReturnJson.BOK = true
m_ReturnJson.sg = "执行正常"
NETReturnData(res, req, m_ReturnJson)
return
} else {
m_ReturnJson.BOK = false
m_ReturnJson.sg = "sign验证失败"
fmt.Println("sign验证失败")
}
NETReturnData(res, req, m_ReturnJson)
default:
m_ReturnJson.BOK = false
m_ReturnJson.sg = "未实现的函数:" + FName
NETReturnData(res, req, m_ReturnJson)
}
default:
m_ReturnJson.BOK = false
m_ReturnJson.sg = "未实现应用:" + ModeName + ",函数:" + FName
NETReturnData(res, req, m_ReturnJson)
}
}
//页面处理函数
func HomePage(res http.ResponseWriter, req *http.Request) {
fmt.Println("dom:", req.Host)
fmt.Println("url:", req.RequestURI)
url := req.RequestURI
nPos := strings.Index(url, "?")
if nPos != -1 {
url = Share.Substr(url, 0, nPos)
}
DefaultModeName := "CORESYS.SYS"
DefaultFuncName := "INDEX"
var MName, FName string
var urlArray []string = strings.Split(strings.ToUpper(url), "/")
nn := len(urlArray)
if nn >= 1 {
if nn == 1 {
MName = urlArray[0]
FName = DefaultFuncName
} else {
MName = urlArray[nn-2]
FName = urlArray[nn-1]
}
} else {
MName = DefaultModeName
FName = DefaultFuncName
}
if MName == "" {
MName = DefaultModeName
}
if FName == "" {
FName = DefaultFuncName
}
if FName == "FICON.ICO" {
b, err := ioutil.ReadFile(Share.GetCurrentDirectory() + "/web/favicon.ico")
if err != nil {
fmt.Print(err)
return
}
res.Header().Set("Content-Type", "image/x-icon")
res.Header().Set("Content-Length", strconv.Itoa(len(b)))
res.Write(b)
b = nil
return
}
ReturnType := 0
nIndex := strings.Index(FName, ".")
strLength := len([]byte(FName))
if nIndex != -1 {
DotName := Share.Substr(FName, nIndex+1, strLength-nIndex-1)
FName = Share.Substr(FName, 0, nIndex)
nIndex = strings.Index(FName, "_RAWJSON")
if nIndex != -1 {
ReturnType = 2
} else {
fmt.Println("DotName", DotName)
if DotName == "AJAX" {
ReturnType = 1
}
}
} else {
nIndex := strings.Index(FName, "_RAWJSON")
if nIndex != -1 {
ReturnType = 2
}
}
fmt.Println("ReturnType:", ReturnType)
if ReturnType == 1 {
var m_ReturnJson ReturnJson
fmt.Println("获得数据")
m_VarHH := GetRequestParameHH(req)
isQQ := true
var m_PArray []string
var ok bool
ok, m_PArray = GetParameValues(m_VarHH, "appid", "msg", "qq", "sign", "qqnickname")
if ok {
} else {
ok, m_PArray = GetParameValues(m_VarHH, "appid", "msg", "weixin", "sign", "weixinnickname")
if !ok {
//处理数据
ActionAPI(res, req, MName, FName, m_VarHH)
return
}
isQQ = false
}
//bArray, _ := json.Marshal(m_Vars)
//fmt.Println(string(bArray))
if ok {
//fmt.Println("appid:" + m_PArray[0])
//fmt.Println("msg:" + m_PArray[1])
//fmt.Println("qq:" + m_PArray[2])
//fmt.Println("sign:" + m_PArray[3])
appid := m_PArray[0]
msg := m_PArray[1]
qq := m_PArray[2]
sign := m_PArray[3]
nickname := m_PArray[4]
appkeyString := ""
if isDBSave {
fmt.Println("采用数据库存储")
ok, m_Rows := m_baseDB.XNGetRecord(false, "select appkey from sys_apps where appid=?", appid)
if ok {
if len(m_Rows) == 0 {
m_ReturnJson.BOK = false
m_ReturnJson.sg = "未能查询到appid:" + appid
NETReturnData(res, req, m_ReturnJson)
return
}
appkey, ok := m_Rows[0]["appkey"]
if ok {
appkeyString = appkey.(string)
} else {
m_ReturnJson.BOK = false
m_ReturnJson.sg = "查询appid:" + appid + "的appkey失败"
NETReturnData(res, req, m_ReturnJson)
}
} else {
m_ReturnJson.BOK = false
m_ReturnJson.sg = "查询appid:" + appid + "失败"
NETReturnData(res, req, m_ReturnJson)
return
}
} else {
fmt.Println("采用INI存储")
m_oneApp, ok := m_AppIDMAP[appid]
if ok {
appkeyString = m_oneApp.AppKey
} else {
m_ReturnJson.BOK = false
m_ReturnJson.sg = "查询appid:" + appid + "失败"
NETReturnData(res, req, m_ReturnJson)
return
}
}
str := ""
if isQQ {
str = "appid=" + m_PArray[0] + "&msg=" + msg + "&qq=" + qq + "&qqnickname=" + nickname + appkeyString
} else {
str = "appid=" + m_PArray[0] + "&msg=" + msg + "&weixin=" + qq + "&weixinnickname=" + nickname + appkeyString
}
fmt.Println("原始计算:" + str)
str = Share.GetMd5String(str)
fmt.Println("计算结果:" + str)
if str == sign {
m_ReturnJson.BOK = true
m_ReturnJson.sg = "OK"
fmt.Println("sign验证成功")
jsonString := ""
word := PickupHTML(msg)
/*
doc, err := goquery.NewDocument(msg)
if err != nil {
//log.Fatal(err)
}
doc.Find("img").Each(func(i int, s *goquery.Selection) {
src, _ := s.Attr("src")
fmt.Printf("img:%s\n", src)
})
*/
imgs := PickupImages(msg)
if len(word) > 50 {
word = Share.Substr(word, 0, 50)
}
onClickURL := ""
FString := "onclick=\"javascript:window.location.href='"
nPos := Share.StringIndex(msg, FString)
if nPos != -1 {
rightString := Share.Substr(msg, nPos+len(FString), -1)
fmt.Println("rightString:" + rightString)
FString = "';"
nPos = Share.StringIndex(rightString, FString)
if nPos != -1 {
onClickURL = Share.Substr(rightString, 0, nPos)
}
}
fmt.Println("onClickURL:" + onClickURL)
m_Data := make(map[string]interface{})
if isQQ {
m_Data["qq"] = qq
m_Data["datatype"] = "qq"
m_Data["nickname"] = nickname
} else {
m_Data["weixin"] = qq
m_Data["datatype"] = "weixin"
m_Data["nickname"] = nickname
}
m_Data["word"] = word
if imgs != nil {
m_Data["imgs"] = imgs
}
if onClickURL != "" {
m_Data["link"] = onClickURL
}
m_Data["rawtext"] = msg
m_Data["action"] = "sendmsg"
bArray, _ := json.Marshal(m_Data)
jsonString = string(bArray)
//回调通知VC处理
WebSocketCallBack(pSaveClass, req.RemoteAddr, 1, jsonString)
return
} else {
m_ReturnJson.BOK = false
m_ReturnJson.sg = "sign验证失败"
fmt.Println("sign验证失败")
}
NETReturnData(res, req, m_ReturnJson)
}
}
t, err := template.ParseFiles("web/index.html")
if err != nil {
fmt.Println(err)
return
}
err = WriteTemplateToHttpResponse(res, t)
if err != nil {
fmt.Println(err)
return
}
}
VC部分主要代码
//初始化函数部分
void CWebRobotDlg::OnButton1()
{
// TODO: Add your control notification handler code here
m_RobotEngine.InitEngine();
char m_Data[500];
int nDataL=500;
GoString m_GoString=GoStringClass::CString2GoString("ws",(char *)m_Data,nDataL);
InitHttpWebSocket_return m_InitHttpWebSocket_return=InitHttpWebSocket(m_GoString, 12000, (DWORD)this,WSCallBack);
if((BOOL)m_InitHttpWebSocket_return.r0)
{
m_BT.EnableWindow(false);
}
}
其中m_RoboteEngine为实际操作QQ操作的类,主要代码将在下面提供
VC的回调函数
void WSCallBack(int pClass,void *WSAddress,int NetEvent,void *pData,int nDataL)
{
CWebRobotDlg *pCWebRobotDlg=(CWebRobotDlg *)pClass;
printf("NetEvent:%d\r\n",NetEvent);
CString sText="";
if(nDataL>0)
{
char *pText=CChineseCodeLib::UTF_8ToGB2312((char *)pData, nDataL);
pCWebRobotDlg->AddMsg(pText);
sText.Format("%s",pText);
//printf("sText:\r\n%s\r\n",pText);
delete[]pText;
}
switch(NetEvent)
{
case 1:
{
HANDLE hJson=TextToJson((char *)(const char *)sText);
if(hJson!=NULL)
{
//真正处理消息函数
pCWebRobotDlg->ActionJson(hJson);
CloseJson(hJson);
}
//pCWebRobotDlg->ActionQQ();
}
break;
}
}
//处理函数
void CWebRobotDlg::ActionJson(HANDLE hJson)
{
CString sAction;
CString sName="datatype",sValue,sType,sDataType="";
CString NO,Word,Link,RawText,NickName;
CStringArray m_PICArray;
sName="action";
if(GetMFCJsonVar(hJson, sName,sAction,sType))
{
if(sAction=="sendmsg")
{
sName="datatype";
if(GetMFCJsonVar(hJson, sName,sValue,sType))
{
if(sValue=="qq")
{
sDataType=sValue;
GetMFCJsonVar(hJson, "qq",NO,sType);
}
else
{
if(sValue=="weixin")
{
sDataType="weixin";
GetMFCJsonVar(hJson, "weixin",NO,sType);
}
}
GetMFCJsonVar(hJson, "word",Word,sType);
GetMFCJsonVar(hJson, "rawtext",RawText,sType);
GetMFCJsonVar(hJson, "link",Link,sType);
CString FString="title=";
int nPos=Link.Find(FString);
if(nPos!=-1)
{
CString LString=Link.Mid(0,nPos);
CString RString=Link.Mid(nPos);
Link=LString+"&"+RString;
FString="linkto=";
nPos=Link.Find(FString);
if(nPos!=-1)
{
LString=Link.Mid(0,nPos);
RString=Link.Mid(nPos);
Link=LString+"&"+RString;
}
}
GetMFCJsonVar(hJson, "nickname",NickName,sType);
int nSize=GetJsonArraySize(hJson,"imgs");
CString PICString="";
for(int i=0;i<nSize;i++)
{
sName.Format("imgs[%d]",i);
GetMFCJsonVar(hJson, sName,sValue,sType);
m_PICArray.Add(sValue);
if(PICString!="")
{
PICString+=",";
}
PICString+=sValue;
}
CString TStr;
TStr.Format("DataType:%s,NO:%s,NickName:%s,Word:%s,Link:%s,ImgSize:%d,imgs:%s",(char *)(const char *)sDataType,(char *)(const char *)NO,(char *)(const char *)NickName,(char *)(const char *)Word,(char *)(const char *)Link,nSize,(char *)(const char *)PICString);
AddMsg((char *)(const char *)TStr);
if(sDataType=="qq" || sDataType=="weixin")
{
OneMsg *pOneMsg=new OneMsg();
pOneMsg->m_msgType=sDataType;
pOneMsg->m_textArray.Add(Word);
pOneMsg->m_textArray.Add(Link);
pOneMsg->m_linkUrl=Link;
for(int i=0;i<m_PICArray.GetSize();i++)
{
pOneMsg->m_imageArray.Add(m_PICArray.GetAt(i));
}
if(sDataType=="qq")
{
sprintf(pOneMsg->m_Robot.m_OneQQ.QQ,"%s",(char *)(const char *)NO);
sprintf(pOneMsg->m_Robot.m_OneQQ.QQName,"%s",(char *)(const char *)NickName);
}
else
{
if(sDataType=="weixin")
{
sprintf(pOneMsg->m_Robot.m_OneWX.WX,"%s",(char *)(const char *)NO);
sprintf(pOneMsg->m_Robot.m_OneWX.WXName,"%s",(char *)(const char *)NickName);
}
else
{
delete pOneMsg;
return;
}
}
//要处理的消息投递给RobotEngine处理,RobotEngine的代码后面提供
m_RobotEngine.AddOneMsg(pOneMsg);
}
}
}
else
{
printf("未实现的动作:%s\r\n",(char *)(const char *)MFCJsonToText(hJson));
}
}
}
RobotEngine操作QQ发送消息核心代码如下
RobotEngine::RobotEngine()
{
bInit=false;
}
RobotEngine::~RobotEngine()
{
if(bInit)
{
::DeleteCriticalSection(&m_SendWorkCS);
::DeleteCriticalSection(&m_RobotCS);
::DeleteCriticalSection(&m_GetMessageCS);
}
}
void RobotEngine::InitEngine()
{
if(bInit)
return;
bInit=true;
::InitializeCriticalSection(&m_SendWorkCS);
::InitializeCriticalSection(&m_RobotCS);
::InitializeCriticalSection(&m_GetMessageCS);
hSendStartEvent=::CreateEvent(NULL,true,false,NULL);
hGetMessageStartEvent=::CreateEvent(NULL,true,false,NULL);
hExitEvent=::CreateEvent(NULL,true,false,NULL);
CWinThread *pThread=AfxBeginThread(PostMessageThread,this);
pThread->m_bAutoDelete=true;
pThread=AfxBeginThread(GetMessageThread,this);
pThread->m_bAutoDelete=true;
LoadQQGroup();
}
UINT RobotEngine::PostMessageThread(LPVOID p)
{
RobotEngine *pRobotEngine=(RobotEngine*)p;
pRobotEngine->ActionPostMessage();
return 0;
}
UINT RobotEngine::GetMessageThread(LPVOID p)
{
RobotEngine *pRobotEngine=(RobotEngine*)p;
pRobotEngine->ActionGetMessage();
return 0;
}
void RobotEngine::ActionPostMessage()
{
HANDLE m_Events[2];
m_Events[0]=hSendStartEvent;
m_Events[1]=hExitEvent;
while(true)
{
DWORD nWait=WaitForMultipleObjects(2,m_Events,false,INFINITE);
switch(nWait)
{
case WAIT_OBJECT_0:
{
ActionOneMsg();
}
break;
case WAIT_OBJECT_0+1:
{
ClearPostWork();
return;
}
break;
default:
{
}
break;
}
}
}
void RobotEngine::ActionGetMessage()
{
HANDLE m_Events[2];
m_Events[0]=hGetMessageStartEvent;
m_Events[1]=hExitEvent;
while(true)
{
DWORD nWait=WaitForMultipleObjects(2,m_Events,false,INFINITE);
switch(nWait)
{
case WAIT_OBJECT_0:
{
ActionGetMsg();
}
break;
case WAIT_OBJECT_0+1:
{
ClearAllGetMsg();
return;
}
break;
default:
{
}
break;
}
}
}
//添加任务
void RobotEngine::AddOneMsg(OneMsg *pOneMsg)
{
::EnterCriticalSection(&m_SendWorkCS);
m_SendWorkPtr.AddTail(pOneMsg);
if(m_SendWorkPtr.GetCount()==1)
{
::SetEvent(hSendStartEvent);
}
::LeaveCriticalSection(&m_SendWorkCS);
}
void RobotEngine::ClearPostWork()
{
::EnterCriticalSection(&m_SendWorkCS);
for(int i=0;i<m_SendWorkPtr.GetCount();i++)
{
OneMsg *pOneMsg=(OneMsg *)m_SendWorkPtr.GetAt(m_SendWorkPtr.FindIndex(i));
delete pOneMsg;
}
m_SendWorkPtr.RemoveAll();
::LeaveCriticalSection(&m_SendWorkCS);
}
void RobotEngine::ActionOneMsg()
{
OneMsg *pOneMsg=NULL;
::EnterCriticalSection(&m_SendWorkCS);
if(m_SendWorkPtr.GetCount()>0)
{
pOneMsg=(OneMsg *)m_SendWorkPtr.GetHead();
m_SendWorkPtr.RemoveHead();
if(m_SendWorkPtr.GetCount()==0)
{
::ResetEvent(hSendStartEvent);
}
}
::LeaveCriticalSection(&m_SendWorkCS);
if(pOneMsg!=NULL)
{
::EnterCriticalSection(&m_RobotCS);
if(pOneMsg->m_msgType=="qq")
{
QQRobot::PostQQRichMessage((char *)pOneMsg->m_Robot.m_OneQQ.QQ,(char *)pOneMsg->m_Robot.m_OneQQ.QQName,pOneMsg->m_imageArray,pOneMsg->m_textArray);
}
else
{
if(pOneMsg->m_msgType=="weixin")
{
WXRobot::PostWXRichMessage((char *)pOneMsg->m_Robot.m_OneWX.WXName,pOneMsg->m_imageArray,pOneMsg->m_textArray);
}
else
{
if(pOneMsg->m_msgType=="qqgroupmember")
{
QQRobot::PostGoupMember(pOneMsg->m_Robot.m_OneGroupMember.GroupQQ,pOneMsg->m_Robot.m_OneGroupMember.GroupName,pOneMsg->m_Robot.m_OneGroupMember.ToQQ,pOneMsg->m_Robot.m_OneGroupMember.ToQQName,pOneMsg->m_imageArray,pOneMsg->m_textArray);
}
}
}
::LeaveCriticalSection(&m_RobotCS);
delete pOneMsg;
}
Sleep(2000);
}
//具体执行一个消息
void RobotEngine::ActionOneGetMsg(OneGetMsg *pOneGetMsg)
{
::EnterCriticalSection(&m_RobotCS);
QQRobot::ActionQQGroupMessage(pOneGetMsg);
::LeaveCriticalSection(&m_RobotCS);
}
CString RobotEngine::GetDBString()
{
//Provider=SQLOLEDB.1;Connect Timeout=10;Persist Security Info=true;Initial Catalog=Ticket;Data Source=127.0.0.1;User ID=sa;Password=;
CString TStr,Path;
CString IP,DBName,UserName,PWD;
char tt[200];
GetModuleFileName(NULL,tt,200);
TStr.Format("%s",tt);
int nWei=TStr.ReverseFind('\\');
TStr=TStr.Mid(0,nWei+1);
Path=TStr+"web\\conf\\appi";
char Xiang[40];
sprintf(Xiang,"连接IP");
GetPrivateProfileString("WEB服务配置",Xiang,"",tt,200,Path);
IP.Format("%s",tt);
sprintf(Xiang,"库名");
GetPrivateProfileString("WEB服务配置",Xiang,"",tt,200,Path);
DBName.Format("%s",tt);
sprintf(Xiang,"库用户名");
GetPrivateProfileString("WEB服务配置",Xiang,"",tt,200,Path);
UserName.Format("%s",tt);
sprintf(Xiang,"库密码");
GetPrivateProfileString("WEB服务配置",Xiang,"",tt,200,Path);
PWD.Format("%s",tt);
CString DBString="";
DBString.Format("Provider=SQLOLEDB.1;Connect Timeout=10;Persist Security Info=true;Initial Catalog=%s;Data Source=%s;User ID=%s;Password=%s",(char *)(const char *)DBName,(char *)(const char *)IP,(char *)(const char *)UserName,(char *)(const char *)PWD);
return DBString;
}
void RobotEngine::SetOneQQWord(CString GroupName, oneQQWord &m_oneQQWord)
{
oneQQWord m_oneQQWordT;
if(m_QQGroupWordMAP.Lookup(GroupName,m_oneQQWordT))
{
}
else
{
m_QQGroupWordMAP.SetAt(GroupName,m_oneQQWord);
}
}
BOOL RobotEngine::GetOneQQWord(CString GroupName, oneQQWord &m_oneQQWord)
{
return m_QQGroupWordMAP.Lookup(GroupName,m_oneQQWord);
}
void RobotEngine::AddOneGetMsg(OneGetMsg *pOneGetMsg)
{
::EnterCriticalSection(&m_GetMessageCS);
OneGetMsg *pTOneGetMsg=new OneGetMsg();
pTOneGetMsg->GroupName=pOneGetMsg->GroupName;
pTOneGetMsg->GroupQQ=pOneGetMsg->GroupQQ;
pTOneGetMsg->GroupMainKey=pOneGetMsg->GroupMainKey;
pTOneGetMsg->m_oneQQWordLast.QQName=pOneGetMsg->m_oneQQWordLast.QQName;
pTOneGetMsg->m_oneQQWordLast.Time=pOneGetMsg->m_oneQQWordLast.Time;
pTOneGetMsg->m_oneQQWordLast.Word=pOneGetMsg->m_oneQQWordLast.Word;
int i;
for(i=0;i<pOneGetMsg->QQArray.GetSize();i++)
{
pTOneGetMsg->QQArray.Add(pOneGetMsg->QQArray.GetAt(i));
}
for(i=0;i<pOneGetMsg->QQNameArray.GetSize();i++)
{
pTOneGetMsg->QQNameArray.Add(pOneGetMsg->QQNameArray.GetAt(i));
}
for(i=0;i<pOneGetMsg->NotifyUrlArray.GetSize();i++)
{
pTOneGetMsg->NotifyUrlArray.Add(pOneGetMsg->NotifyUrlArray.GetAt(i));
}
for(i=0;i<pOneGetMsg->AppIDArray.GetSize();i++)
{
pTOneGetMsg->AppIDArray.Add(pOneGetMsg->AppIDArray.GetAt(i));
}
for(i=0;i<pOneGetMsg->AppKeyArray.GetSize();i++)
{
pTOneGetMsg->AppKeyArray.Add(pOneGetMsg->AppKeyArray.GetAt(i));
}
m_GetMessagePtr.AddTail(pTOneGetMsg);
::SetEvent(hGetMessageStartEvent);
::LeaveCriticalSection(&m_GetMessageCS);
}
void RobotEngine::ClearAllGetMsg()
{
::EnterCriticalSection(&m_GetMessageCS);
for(int i=0;i<m_GetMessagePtr.GetCount();i++)
{
OneGetMsg *pOneGetMsg=(OneGetMsg *)m_GetMessagePtr.GetAt(m_GetMessagePtr.FindIndex(i));
delete pOneGetMsg;
}
m_GetMessagePtr.RemoveAll();
::LeaveCriticalSection(&m_GetMessageCS);
}
void RobotEngine::ActionGetMsg()
{
::EnterCriticalSection(&m_GetMessageCS);
for(int i=0;i<m_GetMessagePtr.GetCount();i++)
{
OneGetMsg *pOneGetMsg=(OneGetMsg *)m_GetMessagePtr.GetAt(m_GetMessagePtr.FindIndex(i));
ActionOneGetMsg(pOneGetMsg);
}
::LeaveCriticalSection(&m_GetMessageCS);
Sleep(10000);
}
void RobotEngine::LoadQQGroup()
{
CString TStr,Path;
CString IP,DBName,UserName,PWD;
char tt[200];
GetModuleFileName(NULL,tt,200);
TStr.Format("%s",tt);
int nWei=TStr.ReverseFind('\\');
TStr=TStr.Mid(0,nWei+1);
Path=TStr+"WebRoboti";
char Xiang[40],MainKey[40];
sprintf(Xiang,"group数量");
GetPrivateProfileString("群配置",Xiang,"",tt,200,Path);
TStr.Format("%s",tt);
int n=atoi(TStr);
CString GroupName,GroupQQ;
for(int i=0;i<n;i++)
{
sprintf(MainKey,"group_%d",i);
GetPrivateProfileString(MainKey,"groupname","",tt,200,Path);
GroupName.Format("%s",tt);
GetPrivateProfileString(MainKey,"groupqq","",tt,200,Path);
GroupQQ.Format("%s",tt);
GetPrivateProfileString(MainKey,"kfcnt","",tt,200,Path);
int kfcnt=atoi(tt);
if(GroupName!="" && GroupQQ!="" && kfcnt>0)
{
OneGetMsg m_OneGetMsg;
m_OneGetMsg.GroupMainKey.Format("%s",MainKey);
m_OneGetMsg.GroupName=GroupName;
m_OneGetMsg.GroupQQ=GroupQQ;
GetPrivateProfileString(MainKey,"lastqqname","",tt,200,Path);
m_OneGetMsg.m_oneQQWordLast.QQName.Format("%s",tt);
GetPrivateProfileString(MainKey,"lasttime","",tt,200,Path);
m_OneGetMsg.m_oneQQWordLast.Time.Format("%s",tt);
m_OneGetMsg.m_oneQQWordLast.Word="";
for(int j=0;j<kfcnt;j++)
{
CString QQ,QQName,NotifyUrl,AppID,AppKey;
sprintf(Xiang,"kfqq_%d",j);
GetPrivateProfileString(MainKey,Xiang,"",tt,200,Path);
QQ.Format("%s",tt);
sprintf(Xiang,"kfqqname_%d",j);
GetPrivateProfileString(MainKey,Xiang,"",tt,200,Path);
QQName.Format("%s",tt);
sprintf(Xiang,"kfnotifyurl_%d",j);
GetPrivateProfileString(MainKey,Xiang,"",tt,200,Path);
NotifyUrl.Format("%s",tt);
sprintf(Xiang,"kfappid_%d",j);
GetPrivateProfileString(MainKey,Xiang,"",tt,200,Path);
AppID.Format("%s",tt);
sprintf(Xiang,"kfappkey_%d",j);
GetPrivateProfileString(MainKey,Xiang,"",tt,200,Path);
AppKey.Format("%s",tt);
if(QQ!="" && QQName!="")
{
m_OneGetMsg.QQArray.Add(QQ);
m_OneGetMsg.QQNameArray.Add(QQName);
m_OneGetMsg.NotifyUrlArray.Add(NotifyUrl);
m_OneGetMsg.AppIDArray.Add(AppID);
m_OneGetMsg.AppKeyArray.Add(AppKey);
}
}
AddOneGetMsg(&m_OneGetMsg);
}
}
}
关于该应用使用文件
文件结构
conf下的配置文件appi
[WS服务配置]
端口=6100
节点名=node
HTTPS站点=false
HTTPS证书名=122
[WEB服务配置]
数据存储方式=INI
库类型=MSSQL
连接IP=127.0.0.1
库名=robot
库端口=5432
库用户名=hello
库密码=123
app数量=1
[app_0]
appid=appid
appname=QQ
appkey=appkey
notifyurl=
其中主要配置一般采用数据存储采用INI方式以免安装数据库
接口app的数量也就是调用该接口的app的数量,及接口配置参数在[app]节点
在调用QQ消息发送时候需要
Post的JSON参数
{
"appid":"",
"msg":"消息内容",
"qq":"接收消息QQ号",
"sign":"签名",
"qqnickname":"QQ昵称"
}
sign签名为键排序后键名+键值各键之间用&拼接成串再加上appkey做MD5
PostJson地址为:http://服务地址:端口/qq.ajax
解决远程桌面解决断开后UI交互问题
远程登录服务器后,启动主程序
执行以下命令
query session
查询远程连接编号一般为 #0
然后执行
tscon rdp-tcp#0 /dest:console
给机器人分配一个远程账户,登录进去后执行连接到本地
日常维护的用另一个远程账户
不少人通过聊天已经抽取到幸运字符了,而现在大家就是想要快点点亮字母了,这样我们的字符表示才会更加明显。而qq幸运字符字母如何快速点亮呢?下文教大家方法。
qq幸运字符字母如何快速点亮
首先通过和好友的互动发消息之后,我们会获得一个幸运字符进行领取的。
领取以后,我们需要进行抽卡的,运气好的话,就可以抽到字符卡了。
抽到字符卡以后,我们就需要点亮字符上面的字母的,上面显示的有互动消息的数量,我们就需要继续和好友进行聊天发消息了。
互动的消息数量每达到100次的话,就可以点亮一个字母,达到200点亮第二个字母。
点亮的字母我们和好友的聊天界面的最上面互动标识可以看到的,是有颜色的,就是点亮的。
幸运字符每天最多点亮几个字母
但是每天不是说一直都可以点亮所有的,上面提示的就有,每天最多2个字母,因此到了2个以后,就需要等待第二天继续点亮了。
来源:腾牛网