目录导读
- 前言
- ThunderOpenSDK 简介
- 参考 xiaomi_Thunder_Cloud 示例
- ThunderOpenSDK 下载问题
前言
在对以前老版本的exe执行程序进行研究学习的时候,发现以前的软件是使用的ThunderOpenSDK这个迅雷开放下载引擎进行的项目数据下载,于是在网上搜索一番找到了相关内容,但是不知道为什么了相关资料相当少,不过用是真的好用,于是仔细的研究了一下。
ThunderOpenSDK 简介
ThunderOpenSDK 是一个迅雷开放下载引擎的 SDK,允许开发者在自己的应用程序中集成迅雷的下载功能。该 SDK 提供了丰富的接口,支持多种下载任务的管理,包括任务的创建、启动、停止、删除等操作。此外,SDK 还支持设置下载速度限制、代理、用户代理等功能,以满足不同应用场景的需求。
出自:ThunderOpenSDK 使用教程
相关内容参考:
迅雷开放下载引擎(ThunderOpenSDK)使用指南
ThunderOpenSDK 使用教程
配置云平台ip和端口 云平台接口
GitHub: ThunderOpenSDK
ThunderOpenSDK 不需要再进行编译,直接附加到项目中就能直接使用,甚至示例程序都写好了,只管调用。
GitHub示例中有0.CurUseCommonLib,360Jisu_Thunder_Cloud,liebao_Thunder_Cloud,xiaomi_Thunder_Cloud,XunleiDownload_Old 5个版本的示例,
可以根据需求任选一个
通过查看xldl.dll文件的属性信息和Github上的声明,
我都毫不怀疑这些库文件是不是是从某个软件上扒下来的。
参考 xiaomi_Thunder_Cloud 示例
以xiaomi_Thunder_Cloud 迅雷云加速开发平台版本示例;
打开xldl.h文件可以发现xldl.dll的接口和数据结构都已经声明好还有注释,只管调用:
- xldl.h:
#pragma once
// 所有结构体定义按1字节对齐
#pragma pack(push, 1)
struct DownTaskParam
{
DownTaskParam()
{
memset(this, 0, sizeof(DownTaskParam));
nReserved1 = 5;
bReserved = FALSE;
DisableAutoRename = FALSE;
IsOnlyOriginal = FALSE;
IsResume = TRUE;
}
int nReserved;
wchar_t szTaskUrl[2084]; // 任务URL
wchar_t szRefUrl[2084]; // 引用页
wchar_t szCookies[4096]; // 浏览器cookie
wchar_t szFilename[MAX_PATH]; // 下载保存文件名.
wchar_t szReserved0[MAX_PATH];
wchar_t szSavePath[MAX_PATH]; // 文件保存目录
HWND hReserved;
BOOL bReserved;
wchar_t szReserved1[64];
wchar_t szReserved2[64];
BOOL IsOnlyOriginal; // 是否只从原始地址下载
UINT nReserved1;
BOOL DisableAutoRename; // 禁止智能命名
BOOL IsResume; // 是否用续传
DWORD reserved[2048];
};
enum DOWN_TASK_STATUS
{
NOITEM = 0,
TSC_ERROR,
TSC_PAUSE,
TSC_DOWNLOAD,
TSC_COMPLETE,
TSC_STARTPENDING,
TSC_STOPPENDING
};
enum TASK_ERROR_TYPE
{
TASK_ERROR_UNKNOWN = 0x00, // 未知错误
TASK_ERROR_DISK_CREATE = 0x01, // 创建文件失败
TASK_ERROR_DISK_WRITE = 0x02, // 写文件失败
TASK_ERROR_DISK_READ = 0x03, // 读文件失败
TASK_ERROR_DISK_RENAME = 0x04, // 重命名失败
TASK_ERROR_DISK_PIECEHASH = 0x05, // 文件片校验失败
TASK_ERROR_DISK_FILEHASH = 0x06, // 文件全文校验失败
TASK_ERROR_DISK_DELETE = 0x07, // 删除文件失败失败
TASK_ERROR_DOWN_INVALID = 0x10, // 无效的DOWN地址
TASK_ERROR_PROXY_AUTH_TYPE_UNKOWN = 0x20, // 代理类型未知
TASK_ERROR_PROXY_AUTH_TYPE_FAILED = 0x21, // 代理认证失败
TASK_ERROR_HTTPMGR_NOT_IP = 0x30, // http下载中无ip可用
TASK_ERROR_TIMEOUT = 0x40, // 任务超时
TASK_ERROR_CANCEL = 0x41, // 任务取消
TASK_ERROR_TP_CRASHED= 0x42, // MINITP崩溃
TASK_ERROR_ID_INVALID = 0x43, // TaskId 非法
};
struct DownTaskInfo
{
DownTaskInfo()
{
memset(this, 0, sizeof(DownTaskInfo));
stat = TSC_PAUSE;
fail_code = TASK_ERROR_UNKNOWN;
fPercent = 0;
bIsOriginUsable = false;
fHashPercent = 0;
}
DOWN_TASK_STATUS stat;
TASK_ERROR_TYPE fail_code;
wchar_t szFilename[MAX_PATH];
wchar_t szReserved0[MAX_PATH];
__int64 nTotalSize; // 该任务总大小(字节)
__int64 nTotalDownload; // 下载有效字节数(可能存在回退的情况)
float fPercent; // 下载进度
int nReserved0;
int nSrcTotal; // 总资源数
int nSrcUsing; // 可用资源数
int nReserved1;
int nReserved2;
int nReserved3;
int nReserved4;
__int64 nReserved5;
__int64 nDonationP2P; // p2p贡献字节数
__int64 nReserved6;
__int64 nDonationOrgin; // 原始资源共享字节数
__int64 nDonationP2S; // 镜像资源共享字节数
__int64 nReserved7;
__int64 nReserved8;
int nSpeed; // 即时速度(字节/秒)
int nSpeedP2S; // 即时速度(字节/秒)
int nSpeedP2P; // 即时速度(字节/秒)
bool bIsOriginUsable; // 原始资源是否有效
float fHashPercent; // 现不提供该值
int IsCreatingFile; // 是否正在创建文件
DWORD reserved[64];
};
enum DOWN_PROXY_TYPE
{
PROXY_TYPE_IE = 0,
PROXY_TYPE_HTTP = 1,
PROXY_TYPE_SOCK4 = 2,
PROXY_TYPE_SOCK5 = 3,
PROXY_TYPE_FTP = 4,
PROXY_TYPE_UNKOWN = 255,
};
enum DOWN_PROXY_AUTH_TYPE
{
PROXY_AUTH_NONE =0,
PROXY_AUTH_AUTO,
PROXY_AUTH_BASE64,
PROXY_AUTH_NTLM,
PROXY_AUTH_DEGEST,
PROXY_AUTH_UNKOWN,
};
struct DOWN_PROXY_INFO
{
BOOL bIEProxy;
BOOL bProxy;
DOWN_PROXY_TYPE stPType;
DOWN_PROXY_AUTH_TYPE stAType;
wchar_t szHost[2048];
INT32 nPort;
wchar_t szUser[50];
wchar_t szPwd[50];
wchar_t szDomain[2048];
};
struct WSAPROTOCOL_INFOW;
#pragma pack(pop)
namespace DownEngine
{
extern "C" __declspec(dllimport) BOOL XL_Init(void);
extern "C" __declspec(dllimport) BOOL XL_UnInit(void);
extern "C" __declspec(dllimport) HANDLE XL_CreateTask(DownTaskParam &stParam);
extern "C" __declspec(dllimport) BOOL XL_DeleteTask(HANDLE hTask);
extern "C" __declspec(dllimport) BOOL XL_StartTask(HANDLE hTask);
extern "C" __declspec(dllimport) BOOL XL_StopTask(HANDLE hTask);
extern "C" __declspec(dllimport) BOOL XL_ForceStopTask(HANDLE hTask);
extern "C" __declspec(dllimport) BOOL XL_QueryTaskInfo(HANDLE hTask, DownTaskInfo & stTaskInfo); //旧版接口,使用Ex接口替换
extern "C" __declspec(dllimport) BOOL XL_QueryTaskInfoEx(HANDLE hTask, DownTaskInfo & stTaskInfo);
extern "C" __declspec(dllimport) BOOL XL_DelTempFile(DownTaskParam &stParam);
extern "C" __declspec(dllimport) void XL_SetSpeedLimit(INT32 nKBps);
extern "C" __declspec(dllimport) void XL_SetUploadSpeedLimit(INT32 nTcpKBps,INT32 nOtherKBps);
extern "C" __declspec(dllimport) BOOL XL_SetProxy(DOWN_PROXY_INFO &stProxyInfo);
extern "C" __declspec(dllimport) void XL_SetUserAgent(const wchar_t *pszUserAgent);
extern "C" __declspec(dllimport) BOOL XL_ParseThunderPrivateUrl(const wchar_t *pszThunderUrl, wchar_t *normalUrlBuffer, INT32 bufferLen);
extern "C" __declspec(dllimport) BOOL XL_GetFileSizeWithUrl(const wchar_t * lpURL, INT64& iFileSize);
extern "C" __declspec(dllimport) BOOL XL_SetFileIdAndSize(HANDLE hTask, char szFileId[40], unsigned __int64 nFileSize);
extern "C" __declspec(dllimport) BOOL XL_SetAdditionInfo( HANDLE task_id, WSAPROTOCOL_INFOW *sock_info, CHAR *http_resp_buf, LONG buf_len );
extern "C" __declspec(dllimport) HANDLE XL_CreateTaskByURL(const wchar_t *url, const wchar_t *path, const wchar_t *fileName, BOOL IsResume);
extern "C" __declspec(dllimport) LONG XL_CreateTaskByThunder(wchar_t *pszUrl, wchar_t *pszFileName, wchar_t *pszReferUrl, wchar_t *pszCharSet, wchar_t *pszCookie);
extern "C" __declspec(dllimport) LONG XL_CreateBTTaskByThunder(const wchar_t *pszPath);
};
相关函数的具体说明,可以参考Github上的文档
这一版本没有调用的示例,但是没关系,liebao_Thunder_Cloud这一版本有调用示例;
参考thunderWrapper.h文件中的thunderWrapper类通过
LoadLibrary和GetProcAddress函数调用,使用MSCV2017编译器
并添加<Windows.h>
引用,建议添加:
#include <Windows.h>
#include <stdio.h>
#include <Shlwapi.h>
#pragma comment(lib,"Shlwapi")
- 初始化函数示例:
只需要简单修改init方法,修改xldl.dll的加载路径,其他基本不变;
bool init(PCWSTR pDllPath = L"xldl.dll")
{
assert(!m_hModule);
WCHAR szModulePath[MAX_PATH] = { 0 };
GetModuleFileNameW(NULL, szModulePath, MAX_PATH);
PathRemoveFileSpecW(szModulePath); // 拆分路径 新版使用PathCchRemoveFileSpec
qDebug()<<"[szModulePath] "<<QString::fromWCharArray(szModulePath);
WCHAR szDllpath[MAX_PATH] = { 0 };
PathCombineW(szDllpath, szModulePath, L"xldl.dll"); // 连接路径, 新版建议使用 PathCchCombine
qDebug()<<"[szDllpath] "<<QString::fromWCharArray(szDllpath);
m_hModule = LoadLibraryW(szDllpath);
assert(m_hModule);
if (m_hModule == NULL)
{
qDebug()<<"can not load xldl.dll -->";
throw L"can not load xldl.dll";
}
_Init = (fn_Init) GetProcAddress(m_hModule, "XL_Init");
_UnInit = (fn_UnInit) GetProcAddress(m_hModule, "XL_UnInit");
_TaskCreate = (fn_TaskCreate) GetProcAddress(m_hModule, "XL_CreateTask");
_TaskDelete = (fn_TaskDelete) GetProcAddress(m_hModule, "XL_DeleteTask");
_TaskStart = (fn_TaskStart) GetProcAddress(m_hModule, "XL_StartTask");
_TaskPause = (fn_StopTask) GetProcAddress(m_hModule, "XL_StopTask");
_TaskForcePause = (fn_StopTask) GetProcAddress(m_hModule, "XL_ForceStopTask");
_TaskQuery = (fn_TaskQuery) GetProcAddress(m_hModule, "XL_QueryTaskInfo");
_TaskQueryEx = (fn_TaskQueryEx) GetProcAddress(m_hModule, "XL_QueryTaskInfoEx");
_LimitSpeed = (fn_LimitSpeed) GetProcAddress(m_hModule, "XL_SetSpeedLimit");
_LimitUploadSpeed = (fn_LimitUploadSpeed) GetProcAddress(m_hModule, "XL_SetUploadSpeedLimit");
_DelTempFile = (fn_DelTempFile) GetProcAddress(m_hModule, "XL_DelTempFile");
_SetProxy = (fn_SetProxy) GetProcAddress(m_hModule, "XL_SetProxy");
_SetUserAgent = (fn_SetUserAgent) GetProcAddress(m_hModule, "XL_SetUserAgent");
_GetFileSizeWithUrl = (fn_GetFileSizeWithUrl) GetProcAddress(m_hModule, "XL_GetFileSizeWithUrl");
_ParseThunderPrivateUrl = (fn_ParseThunderPrivateUrl) GetProcAddress(m_hModule, "XL_ParseThunderPrivateUrl");
_SetAdditionInfo = (fn_SetAdditionInfo) GetProcAddress(m_hModule, "XL_SetAdditionInfo");
_SetFileIdAndSize = (fn_SetFileIdAndSize) GetProcAddress(m_hModule, "XL_SetFileIdAndSize");
_CreateTaskByURL = (fn_CreateTaskByURL) GetProcAddress(m_hModule, "XL_CreateTaskByURL");
_CreateTaskByThunder = (fn_CreateTaskByThunder) GetProcAddress(m_hModule, "XL_CreateTaskByThunder");
_CreateBTTaskByThunder = (fn_CreateBTTaskByThunder) GetProcAddress(m_hModule, "XL_CreateBTTaskByThunder");
CHECKFUNC(_Init, false);
return _Init() == TRUE;
}
需要注意的是在不同版本中,所包含的方法函数也不一样,例如liebao_Thunder_Cloud 版就没有XL_CreateTaskByURL函数方法,
- 实际线程调用:
继承QThread类,重写void run() override;
方法,获取文件总大小,下载进度,下载有效字节数,即时速度,倒计时等信息,并通过信号槽控制下载的中断和退出。
void QThread_ThunderWrapper::run()
{
emit IsStart(true);
bool ISuccessed=false;
IsQuit=false;
QString Error="";
try {
qDebug()<<"QThread_ThunderWrapper Start!";
thunderWrapper=new Lib_ThunderWrapper();
bool ISuccessed=thunderWrapper->init();
if(!ISuccessed)
throw QString("Lib_ThunderWrapper 初始化失败!");
else
qDebug()<<"thunderWrapper->init : Successed!";
wchar_t * url=utf8_to_wchar(Urlpath.toStdString().c_str());
wchar_t * path=utf8_to_wchar(Filepath.toStdString().c_str());
wchar_t * fileName=utf8_to_wchar(Filename.toStdString().c_str());
if(!thunderWrapper->CreateTaskByURL(url,path,fileName,TRUE))
{
thunderWrapper->unInit();
throw QString("taskCreate 失败!");
}
else
qDebug()<<"thunderWrapper->taskCreate : Successed!";
if(!thunderWrapper->taskStart())
{
thunderWrapper->taskDelete();
thunderWrapper->unInit();
throw QString("taskStart 失败!");
}
else
qDebug()<<"thunderWrapper->taskStart : Successed!";
//! 1秒查询一次
msleep(1000);
DownTaskInfo stTaskInfo;
while (!IsQuit) {
if(thunderWrapper->taskQueryEx(stTaskInfo))
{
if(stTaskInfo.stat==TSC_ERROR)
{
emit Current_status("下载失败!",TSC_ERROR);
throw QString("TSC_ERROR: fail_code:%1").arg(stTaskInfo.fail_code);
}
else if(stTaskInfo.stat==TSC_PAUSE)
{
emit Current_status("下载暂停!",TSC_PAUSE);
}
else if(stTaskInfo.stat==TSC_DOWNLOAD)
{
emit Current_status("正在下载...",TSC_PAUSE);
emit Down_Speed(stTaskInfo.nSpeed);
emit ProgressBar((int)stTaskInfo.fPercent*100);
emit SendDownsize(stTaskInfo.nTotalDownload,stTaskInfo.nTotalSize);
if(stTaskInfo.nSpeed>0)
emit Time_Remaining((stTaskInfo.nTotalSize-stTaskInfo.nTotalDownload)/stTaskInfo.nSpeed);
}
else if(stTaskInfo.stat==TSC_COMPLETE)
{
ISuccessed=true;
IsQuit=true;
emit Current_status("下载完成",TSC_COMPLETE);
emit Down_Speed(stTaskInfo.nSpeed);
emit ProgressBar((int)stTaskInfo.fPercent*100);
emit SendDownsize(stTaskInfo.nTotalDownload,stTaskInfo.nTotalSize);
emit Time_Remaining(0);
break;
}
else if(stTaskInfo.stat==TSC_STARTPENDING)
{
emit Current_status("等待下载!",TSC_STARTPENDING);
}
else if(stTaskInfo.stat==TSC_STOPPENDING)
{
emit Current_status("停止等待!",TSC_STARTPENDING);
}
// qDebug().noquote()<<QString("\n state : %1 "
// "\n fail_code : %2"
// "\n nTotalSize : %3"
// "\n nTotalDownload : %4"
// "\n fPercent : %5"
// "\n nSrcTotal : %6"
// "\n nSrcUsing : %7"
// "\n nSpeed : %8"
// "\n szFilename : %9"
// "\n szSavePath : %10"
// "\n IsCreatingFile : %11"
// "\n bIsOriginUsable : %12 \n\n")
// .arg(stateStr)
// .arg(stTaskInfo.fail_code)
// .arg(QString::number(stTaskInfo.nTotalSize,10))
// .arg(QString::number(stTaskInfo.nTotalDownload,10))
// .arg(QString::number(stTaskInfo.fPercent))
// .arg(stTaskInfo.nSrcTotal)
// .arg(stTaskInfo.nSrcUsing)
// .arg(stTaskInfo.nSpeed)
// .arg(QString::fromWCharArray(stTaskInfo.szFilename))
// .arg(QString::fromWCharArray(stTaskInfo.szReserved0))
// .arg(stTaskInfo.IsCreatingFile?"TRUE":"FALSE")
// .arg(stTaskInfo.bIsOriginUsable?"TRUE":"FALSE")
// ;
//! 1秒查询一次
}
msleep(1000);
}
}
catch (QString error) {
ISuccessed=false;
Error="异常信息 :"+error;
}
catch (...) {}
qDebug()<<"thunderWrapper unInit-->";
thunderWrapper->unInit();
//! 清除连接
delete thunderWrapper;
thunderWrapper=nullptr;
emit IsStart(true);
}
如图所示:
下载在网上找到系统镜像文件时,ThunderOpenSDK下载速度更快, 能稳定到9mb/s左右,而通过原生的QNetworkReply下载最高在5Mb/s左右。
ThunderOpenSDK 下载问题
ThunderOpenSDK 无法下载包含重定向跳转的下载链接,
正当我打算整体改用ThunderOpenSDK下载时,我突然发现ThunderOpenSDK 无法下载项目中的资源文件,换成其他网上找的资源文件又能正常下载,
测试多次发现ThunderOpenSDK只能下载直接指向下载资源的链接,
包含重定向跳转的下载链接下载不了!
无解,果断放弃,还是改用调用Aria2下载!
不过一般的下载ThunderOpenSDK库也完全够用了。