Qt/C++ 调用迅雷开放下载引擎(ThunderOpenSDK)下载数据资源

目录导读

    • 前言
    • [ThunderOpenSDK 简介](#ThunderOpenSDK 简介)
      • [参考 xiaomi_Thunder_Cloud 示例](#参考 xiaomi_Thunder_Cloud 示例)
      • [ThunderOpenSDK 下载问题](#ThunderOpenSDK 下载问题)

前言

在对以前老版本的exe执行程序进行研究学习的时候,发现以前的软件是使用的ThunderOpenSDK这个迅雷开放下载引擎进行的项目数据下载,于是在网上搜索一番找到了相关内容,但是不知道为什么了相关资料相当少,不过用是真的好用,于是仔细的研究了一下。


ThunderOpenSDK 简介

ThunderOpenSDK 是一个迅雷开放下载引擎的 SDK,允许开发者在自己的应用程序中集成迅雷的下载功能。该 SDK 提供了丰富的接口,支持多种下载任务的管理,包括任务的创建、启动、停止、删除等操作。此外,SDK 还支持设置下载速度限制、代理、用户代理等功能,以满足不同应用场景的需求。

出自:ThunderOpenSDK 使用教程

相关内容参考:

  1. 迅雷开放下载引擎(ThunderOpenSDK)使用指南

  2. ThunderOpenSDK 使用教程

  3. 配置云平台ip和端口 云平台接口

  4. GitHub: ThunderOpenSDK

ThunderOpenSDK 不需要再进行编译,直接附加到项目中就能直接使用,甚至示例程序都写好了,只管调用。

GitHub示例中有0.CurUseCommonLib360Jisu_Thunder_Cloudliebao_Thunder_Cloudxiaomi_Thunder_CloudXunleiDownload_Old 5个版本的示例,

可以根据需求任选一个

通过查看xldl.dll文件的属性信息和Github上的声明,

我都毫不怀疑这些库文件是不是是从某个软件上扒下来的。

参考 xiaomi_Thunder_Cloud 示例

xiaomi_Thunder_Cloud 迅雷云加速开发平台 版本示例;

打开xldl.h 文件可以发现xldl.dll的接口和数据结构都已经声明好还有注释,只管调用:

  • xldl.h:
cpp 复制代码
#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类 通过
LoadLibraryGetProcAddress 函数调用,使用MSCV2017编译器

并添加<Windows.h>引用,建议添加:

cpp 复制代码
#include <Windows.h>
#include <stdio.h>
#include <Shlwapi.h>
#pragma comment(lib,"Shlwapi")
  • 初始化函数示例:

只需要简单修改init方法,修改xldl.dll的加载路径,其他基本不变;

cpp 复制代码
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;方法,获取文件总大小,下载进度,下载有效字节数,即时速度,倒计时等信息,并通过信号槽控制下载的中断和退出。

cpp 复制代码
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库也完全够用了。

相关推荐
晓纪同学1 小时前
QT-简单视觉框架代码
开发语言·qt
威桑1 小时前
Qt SizePolicy详解:minimum 与 minimumExpanding 的区别
开发语言·qt·扩张策略
飞飞-躺着更舒服2 小时前
【QT】实现电子飞行显示器(简易版)
开发语言·qt
fyzy2 小时前
Qt获取本地计算的CPU温度
qt
cbdg37572 小时前
Qt 6 QML Settings location 不创建指定路径文件
qt
了一li2 小时前
Qt中的QProcess与Boost.Interprocess:实现多进程编程
服务器·数据库·qt
杨德杰2 小时前
QT网络(一):主机信息查询
网络·qt
黄金右肾2 小时前
Qt之串口设计-线程实现(十二)
qt·thread·serialport
别NULL3 小时前
机试题——疯长的草
数据结构·c++·算法
飞飞-躺着更舒服4 小时前
【QT】实现电子飞行显示器(改进版)
开发语言·qt