作者:magictong
日期:2018/04/09
资源下载
https://download.csdn.net/download/magictong/10370195
主要目的
1、下载文件到内存。
2、下载分片Range文件(譬如下载某个资源文件的第100字节到第150字节的内容)。
3、不需要回调线程是UI线程(有消息循环)。
适用场景
1、小文件全量下载(注:暂未支持断点续传)。
2、分片文件下载(注:下载某个文件中的一段内容)。
3、支持https协议(仅支持只需要验证服务器端的情况)。
适用系统
受限于WinHttp的支持,本库需要Windows XP SP1以上或者Windows 2000 SP3以上才能使用。
头文件介绍
1、QMTINYDL::IQMTinyDLSink接口
使用类需要从QMTINYDL::IQMTinyDLSink接口进行继承,实现它的三个虚函数(OnTinyDLComplete,OnTinyDLProgress,OnTinyDLError),OnTinyDLComplete必须实现,其它两个可以按需要实现,这个接口主要用于下载完成,下载失败,下载出错,下载进度的回调,使用者只有通过此接口的回调感知下载库的工作进度。回调函数参数说明参考下面的注释。
//-------------------------------------------------------------------------
// 类名 : IQMTinyDLSink
// 功能 : QMTinyDL下载回调接口
// 附注 :使用IQMTinyDLMgr接口进行下载的类需要继承本接口
// -------------------------------------------------------------------------
class IQMTinyDLSink
{
public:
virtual ~IQMTinyDLSink() {}
//-------------------------------------------------------------------------
// 函数 :OnTinyDLComplete
// 功能 :下载结束回调(dwErr==0表示下载成功)
// 返回值 : virtualvoid
// 参数 : LONGlTaskID任务id
// 参数 : void*pBuffer如果是下载到内存需求,则指向该内存,如果是下载到文件,则指向(wchar*)文件路径
// 参数 : DWORDdwSize下载总长度
// 参数 : DWORDdwErr错误码
// 参数 : PVOIDpContext上下文参数
// 附注 :必须实现
//-------------------------------------------------------------------------
virtual void OnTinyDLComplete(LONG lTaskID, void* pBuffer, DWORD dwSize,DWORD dwErr, PVOID pContext) = 0;
//-------------------------------------------------------------------------
// 函数 :OnTinyDLProgress
// 功能 :下载进度回调
// 返回值 : virtualvoid
// 参数 : LONGlTaskID任务id
// 参数 : DWORDdwLen当前下载长度
// 参数 : DWORDdwTotalLen需要下载总长度
// 参数 : PVOIDpContext上下文参数
// 附注 :可选实现
//-------------------------------------------------------------------------
virtual void OnTinyDLProgress(LONG lTaskID, DWORD dwLen, DWORDdwTotalLen, PVOID pContext) {}
//-------------------------------------------------------------------------
// 函数 :OnTinyDLError
// 功能 :下载中途错误回调
// 返回值 : virtualvoid
// 参数 : LONGlTaskID任务id
// 参数 : DWORDdwErr错误码
// 参数 : PVOIDpContext上下文参数
// 附注 :可选实现
//-------------------------------------------------------------------------
virtual void OnTinyDLError(LONG lTaskID, DWORD dwErr, PVOID pContext) {}
};
//-------------------------------------------------------------------------
// 枚举名 : ERRORCODE
// 功能 :下载失败错误码
// 附注 :通过DWORD dwErr参数传递
//-------------------------------------------------------------------------
enum
{
ERRORCODE_NULL=0, //SUCCESS
ERRORCODE_NOMODIFIED = 1, // Nomodified . so no update
ERRORCODE_NETWORKFAILED = 2,
ERRORCODE_OPEN_HTTP = 3,
ERRORCODE_FILE_ERROR = 4,
ERRORCODE_USER_ABORT = 5,
ERRORCODE_FAILED = 6,
//
// 创建下载实例失败,申请buffer失败等
// add by magictong 2016/12/16 11:33:33
//
ERRORCODE_CREATE_HTTPDOWNLOAD_FAILED = 7,
ERRORCODE_NEWBUF_FAILED = 8,
ERRORCODE_STOP_HANDLE_NULL = 9,
ERRORCODE_NOT_SUPPORT_WINHTTP = 10,
};
2、QMTINYDL:: IQMTinyDLMgr
使用类进行下载请求前,需要先获得QMTINYDL:: IQMTinyDLMgr接口,该接口由4个启动方法,1个反注册接口,2个停止方法和1个代理设置接口组成。详细参数信息参考下面的对应注释。
//-------------------------------------------------------------------------
// 类名 : IQMTinyDLMgr
// 功能 : QMTinyDL外部使用接口
// 附注 :
// -------------------------------------------------------------------------
class IQMTinyDLMgr
{
public:
~IQMTinyDLMgr() {}
//-------------------------------------------------------------------------
// 函数 :CHTTPDownloadEx::StartTaskToBuf
// 功能 :下载到内存,需要设置大小
// 返回值 : DWORD任务id(当前进程唯一)
// 参数 :IQMTinyDLSink* pCallbackObj回调接口
// 参数 :LPCWSTR pUrl下载链接
// 参数 :DWORD64 dw64Size下载大小
// 参数 : PVOIDpContext上下文参数
// 附注 :注意:需要设置大小,内部需要提前分配内存
//-------------------------------------------------------------------------
virtual DWORD StartTaskToBuf(
IQMTinyDLSink* pCallbackObj,
LPCWSTR pUrl,
DWORD64 dw64Size,
PVOID pContext = NULL) = 0;
//-------------------------------------------------------------------------
// 函数 :CHTTPDownloadEx::StartRangeTaskToBuf
// 功能 :下载到内存,分片下载
// 返回值 : DWORD任务id(当前进程唯一)
// 参数 :IQMTinyDLSink* pCallbackObj回调接口
// 参数 :LPCWSTR pUrl下载链接
// 参数 :DWORD64 dw64Offset下载偏移(0开始)
// 参数 :DWORD64 dw64Size下载分片大小
// 参数 : PVOIDpContext上下文参数
// 附注 :如果启动失败,则返回0,否则返回任务ID
//-------------------------------------------------------------------------
virtual DWORD StartRangeTaskToBuf(
IQMTinyDLSink* pCallbackObj,
LPCWSTR pUrl,
DWORD64 dw64Offset,
DWORD64 dw64Size,
PVOID pContext = NULL) = 0;
//-------------------------------------------------------------------------
// 函数 :CHTTPDownloadEx::StartTaskRange
// 功能 :进行下载,下载到文件
// 返回值 : DWORD任务id(当前进程唯一)
// 参数 :IQMTinyDLSink* pCallbackObj回调接口
// 参数 :LPCWSTR pUrl下载链接
// 参数 :LPCWSTR lpFilePath下载到目标文件全路径
// 参数 : PVOIDpContext上下文参数
// 附注 :如果启动失败,则返回0,否则返回任务ID
//-------------------------------------------------------------------------
virtual DWORD StartTask(
IQMTinyDLSink* pCallbackObj,
LPCWSTR pUrl,
LPCWSTR lpFilePath,
PVOID pContext = NULL) = 0;
//-------------------------------------------------------------------------
// 函数 :CHTTPDownloadEx::StartRangeTask
// 功能 :进行分片下载
// 返回值 : DWORD任务id(当前进程唯一)
// 参数 :IQMTinyDLSink* pCallbackObj回调接口
// 参数 :LPCWSTR pUrl下载链接
// 参数 :LPCWSTR lpFilePath下载到目标文件全路径
// 参数 :DWORD64 dw64Offset下载偏移(0开始)
// 参数 :DWORD64 dw64Size下载分片大小
// 参数 : PVOIDpContext上下文参数
// 附注 :如果启动失败,则返回0,否则返回任务ID
//-------------------------------------------------------------------------
virtual DWORD StartRangeTask(
IQMTinyDLSink* pCallbackObj,
LPCWSTR pUrl,
LPCWSTR lpFilePath,
DWORD64 dw64Offset,
DWORD64 dw64Size,
PVOID pContext = NULL) = 0;
//-------------------------------------------------------------------------
// 函数 :StopTask
// 功能 :停止id为lTaskID的下载任务
// 返回值 : void
// 参数 : LONGlTaskID
// 附注 :
// -------------------------------------------------------------------------
virtual void StopTask(LONG lTaskID) = 0;
//-------------------------------------------------------------------------
// 函数 :StopAllTask
// 功能 :停掉所有的下载任务
// 返回值 : void
// 附注 :
//-------------------------------------------------------------------------
virtual void StopAllTask() = 0;
//-------------------------------------------------------------------------
// 函数 :SetProxy
// 功能 :设置代理信息
// 返回值 : virtualvoid
// 参数 :QMTINYDL::QMDLPROXYTYPE proxyType,
// 参数 : PCWSTRlpszAddress
// 参数 : USHORTusPort
// 参数 :LPCWSTR lpszUserName = NULL
// 参数 :LPCWSTR lpszPassword = NULL
// 参数 :LPCWSTR lpszDomain = NULL
// 附注 :如果不调用SetProxy,组件内部会自动处理管家代理
//-------------------------------------------------------------------------
virtual void SetProxy(
QMTINYDL::QMDLPROXYTYPE proxyType,
LPCWSTR lpszAddress,
USHORT usPort,
LPCWSTR lpszUserName = NULL,
LPCWSTR lpszPassword = NULL,
LPCWSTR lpszDomain = NULL) = 0;
//-------------------------------------------------------------------------
// 函数 :UnregisterCallback
// 功能 :反注册回调
// 返回值 : virtualBOOL
// 参数 :IQMTinyDLSink* pCallbackObj
// 附注 :
//-------------------------------------------------------------------------
virtual BOOL UnregisterCallback(IQMTinyDLSink* pCallbackObj) = 0;
};
3、头文件里面QMDLProxyInfo和QMDLPROXYTYPE定义是代理相关内容,按需使用即可,另外库内部初始化时会自动处理IE设置的代理,如果外部调用SetProxy方法手动设置代理,则使用手动设置的代理。
使用方法
1、实现QMTINYDL::IQMTinyDLSink接口,相关调用者自己按需实现即可。
2、获得QMTINYDL:: IQMTinyDLMgr接口,获取该接口有两个方法:
(1) 一种是直接使用QMTinyDL.dll(MD编译)的导出函数获取:
//
// Export原型如下
//
extern "C" IQMTinyDLMgr*__stdcall CreateQMTinyDLMgr();
extern "C" int __stdcallDestroyQMTinyDLMgr(IQMTinyDLMgr* p);
extern "C" unsigned int__stdcall GetQMTinyDLVer();
先使用CreateQMTinyDLMgr获得IQMTinyDLMgr接口,使用完之后调用DestroyQMTinyDLMgr释放。
(2) 另外一种方法是使用QMTINYDL库的辅助lib(QMTinyDLLib.lib:MD编译)来获取,节省寻找加载QMTinyDL.dll的操作。
使用该lib只需要引入IQMTinyDL.h头文件,使用里面的两个函数CreateQMTinyDLMgr和DestroyQMTinyDLMgr即可。
//-------------------------------------------------------------------------
// 函数 : CreateQMTinyDLMgr
// 功能 :创建IQMTinyDLMgr接口
// 返回值 : IQMTinyDLMgr*
// 附注 :
//-------------------------------------------------------------------------
extern "C" IQMTinyDLMgr*__stdcall CreateQMTinyDLMgr();
// -------------------------------------------------------------------------
// 函数 : DestroyQMTinyDLMgr
// 功能 :释放IQMTinyDLMgr接口
// 返回值 : int
// 参数 : IQMTinyDLMgr* p
// 附注 :
//-------------------------------------------------------------------------
extern "C" int __stdcall DestroyQMTinyDLMgr(IQMTinyDLMgr*p);
注意:在使用QMTINYDL:: IQMTinyDLMgr接口的Start*系列方法(譬如:StartRangeTask)时,传入了一个QMTINYDL::IQMTinyDLSink接口,在调用DestroyQMTinyDLMgr之前需要把该接口从库里面反注册,务必调用QMTINYDL:: IQMTinyDLMgr接口的UnregisterCallback方法将其反注册,否则如果实现QMTINYDL::IQMTinyDLSink接口的外部对象提前销毁,极易导致下载库Crash,这里没有使用引用计数来管理各个对象主要是基于简单轻便的考虑。
使用举例
1、头文件。
class CDeltaDlder
:public QMTINYDL::IQMTinyDLSink
,public DeltaTaskBase
{
public:
CDeltaDlder(void);
~CDeltaDlder(void);
……
// -------------------------------------------------------------------------
// IQMTinyDLSink
//
virtual void OnTinyDLComplete(LONG lTaskid, void* pBuffer, DWORD dwSize,DWORD dwErr, PVOID pContext);
virtual void OnTinyDLProgress(LONG lTaskID, DWORD dwLen, DWORDdwTotalLen, PVOID pContext) {}
virtual void OnTinyDLError(LONG lTaskID,DWORD dwErr, PVOID pContext) {}
……
private:
QMTINYDL::IQMTinyDLMgr* m_pHttpDlder;
……
};
2、实现文件
BOOL CDeltaDlder::Init()
{
……
BOOLbRet = FALSE;
if(!m_pHttpDlder)
{
m_pHttpDlder = QMTINYDL::CreateQMTinyDLMgr();
}
if(!m_pHttpDlder)
{
LOG_ERROR_PRINTF(_T("[%s]QMTINYDL::CreateQMTinyDLMgr Error"), __FUNCTIONW__);
bRet= FALSE;
}
else
{
bRet= TRUE;
}
returnbRet;
}
VOID CDeltaDlder::UnInit()
{
if (m_pHttpDlder)
{
LOG_COMMON_PRINTF(L"[%s] UnInit()", __FUNCTIONW__);
m_pHttpDlder->UnregisterCallback(this);
QMTINYDL::DestroyQMTinyDLMgr(m_pHttpDlder);
m_pHttpDlder = NULL;
}
}
void CDeltaDlder::OnTinyDLComplete(LONGlTaskid, void* pBuffer, DWORD dwSize, DWORD dwErr, PVOID pContext)
{
utils::CCriticalSection::Ownero(m_csDL);
BOOL bDoTry = FALSE;
if(QMTINYDL::ERRORCODE_NULL != dwErr && lTaskid) //
{
……
}
……
}
……
DWORD dwTaskId = m_pHttpDlder->StartRangeTask(this, m_strDldUrl,itr->strDldFileName, itr->dw64DldOffset, itr->dw64DldLength);
……