关键部分代码如下:

    1. #include "curl.h"
    2. #pragma comment(lib, "libcurl.lib")
    3. size_t CROS_DownloadDlg::getContentLengthFunc(void * ptr, size_t size, size_t nmemb, void * stream)
    4. {
    5. LONGLONG len = 0;
    6. int r = sscanf((const char *)ptr, "Content-Length:%I64d\n",&len);
    7. if(r)
    8. *((LONGLONG *) stream) = len;
    9. return size * nmemb;
    10. }
    11. //根据URL获取下载文件大小
    12. LONGLONG CROS_DownloadDlg::getDownloadFileSize(const char* url)
    13. {
    14. double lensize = 0.0;
    15. for(int iTry = 0 ; iTry < 3 ; iTry ++)//由于curl_easy_perform可能会有偶发性的 CURLE_WRITE_ERROR错误,所以添加重试机制
    16. {
    17. CURL *handle = curl_easy_init();
    18. curl_easy_setopt(handle, CURLOPT_URL, url);
    19. curl_easy_setopt(handle, CURLOPT_HEADER, 1);
    20. curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1);
    21. curl_easy_setopt(handle, CURLOPT_NOBODY, 1);
    22. CURLcode res = curl_easy_perform(handle), resGetInfo = CURLE_OK;
    23. if (res == CURLE_OK) {
    24. resGetInfo = curl_easy_getinfo(handle, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &lensize);
    25. if(CURLE_OK == resGetInfo){
    26. curl_easy_cleanup(handle);
    27. return (LONGLONG)lensize;
    28. }
    29. }
    30. curl_easy_cleanup(handle);
    31. Sleep(200);
    32. }
    33. return 0;
    34. }
    35. size_t CROS_DownloadDlg::downLoadPackage(void *ptr, size_t size, size_t nmemb, void *userdata)
    36. {
    37. if(!ptr || !userdata)
    38. return 0;
    39. return fwrite(ptr, size, nmemb, (FILE *)userdata);
    40. }
    41. int CROS_DownloadDlg::assetsManagerProgressFunc(void *ptr, double totalToDownload, double nowDownloaded, double totalToUpLoad, double nowUpLoaded)
    42. {
    43. if(m_bStop)
    44. return -1;
    45. if(totalToDownload > 0.0)
    46. {
    47. CROS_DownloadDlg* pDlg = (CROS_DownloadDlg*)ptr;
    48. pDlg->m_lProcessSize = (LONGLONG)nowDownloaded;
    49. pDlg->SendMessage(WM_DOWNLOADPROC_MSG, 1, 0);
    50. }
    51. return 0;
    52. }
    53. /*
    54. 0 设置总大小
    55. 1 设置当前下载
    56. 2 下载完成
    57. 3 用户停止下载,其他异常终止下载
    58. 4 网络问题引发的下载异常
    59. 5 设备断开连接
    60. 6 磁盘剩余空间不足
    61. */
    62. UINT CROS_DownloadDlg::DownloadProc(LPVOID lpParam)
    63. {
    64. //////////////////////////////////////////////////////////////////////////使用CURL实现下载
    65. string sURL = CStringConverter::Unicode2Ansi(strURL.GetString()), sSavePath = CStringConverter::Unicode2Ansi(strSavePath.GetString());
    66. LONGLONG local_file_len = GetFileSize(strSavePath);
    67. pDlg->m_lLocalFileCurSize = local_file_len;
    68. curl_global_init(CURL_GLOBAL_DEFAULT);
    69. LONGLONG remote_file_len = getDownloadFileSize(sURL.c_str());
    70. if(!remote_file_len)
    71. {
    72. pDlg->SendMessage(WM_DOWNLOADPROC_MSG, 4, 0);//网络问题获取失败
    73. return 0;
    74. }
    75. pDlg->m_lTotalSize = remote_file_len;
    76. pDlg->SendMessage(WM_DOWNLOADPROC_MSG, 0, 0);
    77. if(local_file_len == remote_file_len)
    78. {
    79. pDlg->SendMessage(WM_DOWNLOADPROC_MSG, 2, 0);
    80. return 0;
    81. }
    82. //得到准确大小后应判断strSavePath空间是否足够先
    83. if(remote_file_len >= (pDlg->m_ulDiskSpaceMax))
    84. {
    85. pDlg->SendMessage(WM_DOWNLOADPROC_MSG, 6, 0);
    86. return 0;
    87. }
    88. FILE *fp = fopen(sSavePath.c_str(), "ab+");
    89. if(!fp)
    90. {
    91. pDlg->SendMessage(WM_DOWNLOADPROC_MSG, 3, 0);
    92. return 0;
    93. }
    94. LONGLONG filesize = 0;
    95. m_pCurl = curl_easy_init();//curl初始化
    96. CURLcode res;
    97. curl_easy_setopt(m_pCurl, CURLOPT_URL, sURL.c_str());//设定curl的链接
    98. curl_easy_setopt(m_pCurl, CURLOPT_CONNECTTIMEOUT,5);//设置连接超时,单位秒
    99. curl_easy_setopt(m_pCurl, CURLOPT_HEADERFUNCTION,getContentLengthFunc);
    100. curl_easy_setopt(m_pCurl, CURLOPT_HEADERDATA, &filesize);
    101. curl_easy_setopt(m_pCurl, CURLOPT_RESUME_FROM_LARGE, local_file_len);//断点下载设置
    102. curl_easy_setopt(m_pCurl, CURLOPT_WRITEFUNCTION, downLoadPackage);
    103. curl_easy_setopt(m_pCurl, CURLOPT_WRITEDATA, fp);//设置将data写入到文件流fp中
    104. curl_easy_setopt(m_pCurl, CURLOPT_FOLLOWLOCATION, 1L);//设置重定位URL,使用自动跳转,返回的头部中有Location(一般直接请求的url没找到),则继续请求Location对应的数据
    105. curl_easy_setopt(m_pCurl, CURLOPT_MAXREDIRS,5);//查找次数,防止查找太深
    106. curl_easy_setopt(m_pCurl, CURLOPT_NOPROGRESS, false);//设为false 下面才能设置进度响应函数
    107. curl_easy_setopt(m_pCurl, CURLOPT_PROGRESSFUNCTION, assetsManagerProgressFunc);//进度响应函数
    108. curl_easy_setopt(m_pCurl, CURLOPT_PROGRESSDATA, pDlg);//数据传输的对象
    109. curl_easy_setopt(m_pCurl, CURLOPT_VERBOSE,1L);
    110. res = curl_easy_perform(m_pCurl);
    111. curl_easy_cleanup(m_pCurl);
    112. curl_global_cleanup();
    113. m_pCurl = NULL;
    114. if (res != CURLE_OK)
    115. {
    116. fclose(fp);
    117. if(res == CURLE_ABORTED_BY_CALLBACK)//点击停止下载
    118. pDlg->SendMessage(WM_DOWNLOADPROC_MSG, 3, 0);
    119. else if(res == CURLE_RECV_ERROR)//断网 /* 56 - failure in receiving network data */
    120. pDlg->SendMessage(WM_DOWNLOADPROC_MSG, 4, 0);
    121. else
    122. pDlg->SendMessage(WM_DOWNLOADPROC_MSG, 3, 0);
    123. return 0;
    124. }
    125. fclose(fp);
    126. pDlg->SendMessage(WM_DOWNLOADPROC_MSG, 2, 0);
    127. return 0;
    128. }
    129. void CROS_DownloadDlg::OnClickBtnStop()
    130. {
    131. if(m_pCurl){
    132. curl_easy_pause(m_pCurl, CURLPAUSE_RECV);
    133. if(IDYES == ShowMessage(IDS_DEF_ROS_SURE_TO_STOP, CiPhoneUtil::GetApplicationName(), SM_ICON_QUESTION|SM_YES_AND_NO)){
    134. m_btnStop.EnableWindow(FALSE);
    135. m_bStop = true;
    136. return;
    137. }
    138. curl_easy_pause(m_pCurl, CURLPAUSE_RECV_CONT);
    139. }
    140. }


    image.jpeg