|
|

分享源码
| 界面截图: |
- |
| 是否带模块: |
调用了模块 |
| 备注说明: |
- |
本帖最后由 是永乐哟 于 2026-6-9 19:01 编辑
我不是原创,这个记得是之前看到别人写的,然后我封装C++给我程序调用的
但是今天看到有人要易语言取qq的,又把C++转成易语言的了
注:调用了精易模块,我之前中过别人发的精易模块有病毒,所以我不分享模块
| 窗口程序集名 | 保 留 | 保 留 | 备 注 | | 窗口程序集_启动窗口 | | | |
| 变量名 | 类 型 | 静态 | 数组 | 备 注 | | 账号数组 | QQ账号信息 | | 0 | | 数量 | 整数型 | | | | i | 整数型 | | |
数量 = 取本地QQ账号 (账号数组 ) 计次循环首 (数量, i ) 输出调试文本 (“QQ:” + 账号数组 [i ].uin + “ 昵称:” + 账号数组 [i ].昵称 ) 计次循环尾 ()| 变量名 | 类 型 | 静态 | 数组 | 备 注 | | 随机数 | 整数型 | | | | 随机数文本 | 文本型 | | | | 请求URL | 文本型 | | | | 协议头 | 文本型 | | | | 响应文本 | 文本型 | | | | 起始位置 | 整数型 | | | | 结束位置 | 整数型 | | | | 标志文本 | 文本型 | | | | JSON文本 | 文本型 | | | | json | 类_json | | | | 成员总数 | 整数型 | | | | i | 整数型 | | | | 临时账号 | QQ账号信息 | | | | uin类型 | 整数型 | | | | uin文本 | 文本型 | | | | tmp | 文本型 | | | 置随机数种子 ()随机数 = 取随机数 (1000000000, 2000000000 )随机数文本 = 到文本 (随机数 ) 请求URL = “https://localhost.ptlogin2.qq.com:4301/pt_get_uins?callback=ptui_getuins_CB&pt_local_tk=-” + 随机数文本 协议头 = “Referer: https://ui.ptlogin2.qq.com/” + #换行符 + “Cookie: pt_local_token=-” + 随机数文本 响应文本 = 到文本 (网页_访问_对象 (请求URL, 0, , , , 协议头, , , , , , , , , , , , , )) 如果真 (响应文本 = “”) 输出调试文本 (“请求失败,请确认QQ已运行并登录!”) 返回 (0 ) 标志文本 = “var var_sso_uin_list=”起始位置 = 寻找文本 (响应文本, 标志文本, , 假) 如果真 (起始位置 = -1 ) 标志文本 = “var var_sso_uin_list =” 起始位置 = 寻找文本 (响应文本, 标志文本, , 假) 如果真 (起始位置 = -1 ) 输出调试文本 (“未找到 var_sso_uin_list,接口可能已变更”) 返回 (0 ) 起始位置 = 起始位置 + 取文本长度 (标志文本 )结束位置 = 寻找文本 (响应文本, “;”, 起始位置, 假) 如果真 (结束位置 = -1 ) 输出调试文本 (“JSON结束符未找到”) 返回 (0 )JSON文本 = 取文本中间 (响应文本, 起始位置, 结束位置 - 起始位置) 如果真 (json. 解析 (JSON文本, , ) = 假) 返回 (0 ) 成员总数 = json. 成员数 ()重定义数组 (账号列表, 假, 0 ) 计次循环首 (成员总数, i )  uin类型 = json. 取类型 (“[” + 到文本 (i - 1 ) + “].uin”)  判断 (uin类型 = 2 )   uin文本 = json. 取通用属性 (“[” + 到文本 (i - 1 ) + “].uin”, ) 判断 (uin类型 = 6 )   tmp = json. 取通用属性 (“[” + 到文本 (i - 1 ) + “].uin”, )   如果真 (取文本长度 (tmp ) ≥ 2 )     uin文本 = 取文本中间 (tmp, 2, 取文本长度 (tmp ) - 2 )     uin文本 = “”   如果真 (uin文本 ≠ “”)  临时账号.uin = uin文本   临时账号.昵称 = json. 取通用属性 (“[” + 到文本 (i - 1 ) + “].nickname”, 真)    临时账号.昵称 = 文本_替换 (临时账号.昵称, , , , #引号, “”, , , , , , , , )  加入成员 (账号列表, 临时账号 )  计次循环尾 ()返回 (取数组成员数 (账号列表 )) 以下是C++版本的
[C++] 纯文本查看 复制代码 // qq.hpp - 获取本机已登录 QQ 账号(WinHTTP 版)
// 功能:通过本地 QQ 的 ptlogin 接口(localhost:4301)获取当前已登录的 QQ 账号信息。
// 依赖:需要 nlohmann/json 库(json.hpp)
// 编译:链接 winhttp.lib
#pragma once
#include <windows.h>
#include <winhttp.h>
#include <string>
#include <vector>
#include <random>
#include <stdexcept>
#pragma comment(lib, "winhttp.lib")
namespace qq_local {
/**
* @brief QQ 账号信息结构体
*/
struct QQInfo {
std::string uin; ///< QQ 号(字符串形式)
std::string nickname; ///< 昵称(可能为空)
};
/**
* @brief 忽略 SSL 证书错误(因为本地 4301 端口使用的是自签名证书)
* @param hRequest WinHTTP 请求句柄
*/
inline void IgnoreSslErrors(HINTERNET hRequest) {
DWORD flags = SECURITY_FLAG_IGNORE_UNKNOWN_CA |
SECURITY_FLAG_IGNORE_CERT_CN_INVALID |
SECURITY_FLAG_IGNORE_CERT_DATE_INVALID;
WinHttpSetOption(hRequest, WINHTTP_OPTION_SECURITY_FLAGS,
&flags, sizeof(flags));
}
/**
* @brief 获取本机当前已登录的所有 QQ 账号
*
* 该函数向本地 QQ 服务(localhost.ptlogin2.qq.com:4301)发送请求,
* 获取已登录账号的 JSON 列表并解析。
*
* @return std::vector<QQInfo> 包含所有已登录账号的 vector,若无登录账号则为空。
*
* @throws std::runtime_error 当网络请求失败、响应解析失败或接口不可用时抛出异常。
*
* @note 使用前必须确保 QQ 客户端正在运行且已登录至少一个账号。
* @note 该函数会忽略本地 SSL 证书错误,仅用于本地调试。
* @note 需要 nlohmann/json 库支持。
*/
inline std::vector<QQInfo> GetLocalQQ() {
// 1. 生成随机数作为 pt_local_tk(防缓存)
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<long long> dist(1000000000LL, 2000000000LL);
long long randNum = dist(gen);
std::string randStr = std::to_string(randNum);
std::wstring randWstr(randStr.begin(), randStr.end());
std::wstring path = L"/pt_get_uins?callback=ptui_getuins_CB&pt_local_tk=-" + randWstr;
// 2. 初始化 WinHTTP 会话
HINTERNET hSession = WinHttpOpen(L"Mozilla/5.0",
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
WINHTTP_NO_PROXY_NAME,
WINHTTP_NO_PROXY_BYPASS, 0);
if (!hSession) {
throw std::runtime_error("WinHttpOpen 失败");
}
// 3. 连接到本地 QQ 服务(端口 4301)
HINTERNET hConnect = WinHttpConnect(hSession, L"localhost.ptlogin2.qq.com", 4301, 0);
if (!hConnect) {
WinHttpCloseHandle(hSession);
throw std::runtime_error("WinHttpConnect 失败,请确认 QQ 已启动");
}
// 4. 创建请求(HTTPS)
HINTERNET hRequest = WinHttpOpenRequest(hConnect, L"GET", path.c_str(),
nullptr, WINHTTP_NO_REFERER,
WINHTTP_DEFAULT_ACCEPT_TYPES,
WINHTTP_FLAG_SECURE);
if (!hRequest) {
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
throw std::runtime_error("WinHttpOpenRequest 失败");
}
IgnoreSslErrors(hRequest);
// 5. 添加请求头(Referer 和 Cookie)
std::wstring headers = L"Referer: https://ui.ptlogin2.qq.com/\r\n";
headers += L"Cookie: pt_local_token=-" + randWstr;
if (!WinHttpAddRequestHeaders(hRequest, headers.c_str(), (DWORD)-1,
WINHTTP_ADDREQ_FLAG_ADD)) {
WinHttpCloseHandle(hRequest);
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
throw std::runtime_error("WinHttpAddRequestHeaders 失败");
}
// 6. 发送请求
if (!WinHttpSendRequest(hRequest, nullptr, 0, nullptr, 0, 0, 0)) {
WinHttpCloseHandle(hRequest);
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
throw std::runtime_error("请求发送失败,请确认 QQ 已登录且本地服务正常");
}
// 7. 接收响应
if (!WinHttpReceiveResponse(hRequest, nullptr)) {
WinHttpCloseHandle(hRequest);
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
throw std::runtime_error("接收响应失败");
}
// 8. 读取响应数据
std::string response;
DWORD bytesRead = 0;
char buffer[4096];
while (WinHttpReadData(hRequest, buffer, sizeof(buffer), &bytesRead) && bytesRead > 0) {
response.append(buffer, bytesRead);
}
WinHttpCloseHandle(hRequest);
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
// 9. 从响应中提取 JSON 字符串(包裹在 JavaScript 回调中)
std::string marker = "var var_sso_uin_list=";
size_t start = response.find(marker);
if (start == std::string::npos) {
marker = "var var_sso_uin_list =";
start = response.find(marker);
if (start == std::string::npos) {
throw std::runtime_error("响应中未找到 var_sso_uin_list,QQ 可能未登录或接口已变更");
}
}
start += marker.length();
size_t end = response.find(";", start);
if (end == std::string::npos) {
throw std::runtime_error("JSON 结束符 ';' 未找到");
}
std::string jsonStr = response.substr(start, end - start);
// 10. 解析 JSON(需要 nlohmann/json.hpp)
nlohmann::json qqList;
try {
qqList = nlohmann::json::parse(jsonStr);
}
catch (const nlohmann::json::parse_error& e) {
throw std::runtime_error("JSON 解析失败: " + std::string(e.what()));
}
if (!qqList.is_array()) {
return {};
}
// 11. 转换为 QQInfo 结构体
std::vector<QQInfo> result;
for (const auto& item : qqList) {
QQInfo info;
if (item.contains("uin")) {
if (item["uin"].is_string()) {
info.uin = item["uin"].get<std::string>();
}
else if (item["uin"].is_number()) {
uint64_t uin_num = item["uin"].get<uint64_t>();
info.uin = std::to_string(uin_num);
}
}
if (item.contains("nickname") && item["nickname"].is_string()) {
info.nickname = item["nickname"].get<std::string>();
}
if (!info.uin.empty()) {
result.push_back(info);
}
}
return result;
}
} // namespace qq_local
|
|