DownloadMTR.cpp
上传用户:oadesign
上传日期:2013-12-25
资源大小:265k
文件大小:26k
源码类别:

进程与线程

开发平台:

Visual C++

  1. // DownloadMTR.cpp: implementation of the CDownloadMTR class.
  2. //
  3. //////////////////////////////////////////////////////////////////////
  4. #include "stdafx.h"
  5. #include "NetDownMTR.h"
  6. #include "DownloadMTR.h"
  7. #include <io.h>
  8. #ifdef _DEBUG
  9. #undef THIS_FILE
  10. static char THIS_FILE[]=__FILE__;
  11. #define new DEBUG_NEW
  12. #endif
  13. void DownloadNotify ( int nIndex, UINT nNotityType, LPVOID lpNotifyData, LPVOID pDownloadMTR );
  14. //////////////////////////////////////////////////////////////////////
  15. // Construction/Destruction
  16. //////////////////////////////////////////////////////////////////////
  17. CDownloadMTR::CDownloadMTR()
  18. : m_nThreadCount ( DEFAULT_THREAD_COUNT )
  19. , m_pDownloadPub_MTR ( NULL )
  20. , m_pDownloadPub_Info ( NULL )
  21. , m_pDownloadCellInfo ( NULL )
  22. , m_hThread ( NULL )
  23. , m_bForceDownload ( FALSE )
  24. , m_nTotalDownloadedSize_ThisTimes ( 0 )
  25. {
  26. memset ( &m_BaseDownInfo, 0, sizeof(t_BaseDownInfo) );
  27. m_hEvtEndModule = ::CreateEvent ( NULL, TRUE, FALSE, NULL );
  28. m_dwDownloadStartTime = GetTickCount();
  29. }
  30. CDownloadMTR::~CDownloadMTR()
  31. {
  32. StopDownload ();
  33. }
  34. //
  35. // 设置下载的线程数
  36. //
  37. BOOL CDownloadMTR::SetThreadCount(int nThreadCount)
  38. {
  39. if ( nThreadCount <= 0 || nThreadCount > MAX_DOWNLOAD_THREAD_COUNT )
  40. {
  41. Log ( L_WARNING, "Thread count %d is invalid. Rang [%d-%d]", nThreadCount, 1, MAX_DOWNLOAD_THREAD_COUNT );
  42. return FALSE;
  43. }
  44. if ( nThreadCount == m_nThreadCount )
  45. return TRUE;
  46. m_nThreadCount = nThreadCount;
  47. return TRUE;
  48. }
  49. //
  50. // 下载任务的线程函数
  51. //
  52. DWORD WINAPI ThreadProc_DownloadMTR(
  53.   LPVOID lpParameter   // thread data
  54. )
  55. {
  56. CDownloadMTR *pDownloadMTR = (CDownloadMTR*)lpParameter;
  57. ASSERT ( pDownloadMTR );
  58. pDownloadMTR->ThreadProc_DownloadMTR ();
  59. TRACE ( "下载任务的线程函数 执行完毕n" );
  60. return TRUE;
  61. }
  62. BOOL CDownloadMTR::ThreadProc_DownloadMTR()
  63. {
  64. // 启动多线程下载任务
  65. int nRet = StartMTRDownload ();
  66. if ( nRet == 2 ) return HandleDownloadFinished(ENUM_DOWNLOAD_RESULT_SUCCESS);
  67. if ( nRet == 0 ) return HandleDownloadFinished(ENUM_DOWNLOAD_RESULT_FAILED);
  68. // 等待所有线程下载完成
  69. ENUM_DOWNLOAD_RESULT eDownloadResult = WaitForDownloadFinished ();
  70. if ( eDownloadResult == ENUM_DOWNLOAD_RESULT_SUCCESS && !GetDownloadResult () )
  71. {
  72. eDownloadResult = ENUM_DOWNLOAD_RESULT_FAILED;
  73. }
  74. return HandleDownloadFinished ( eDownloadResult );
  75. }
  76. //
  77. // 多线程断点续传下载一个文件
  78. //
  79. BOOL CDownloadMTR::Download (
  80. LPCTSTR lpszDownloadURL,
  81. LPCTSTR lpszSavePath,
  82. LPCTSTR lpszSaveOnlyFileName,
  83. LPCTSTR lpszUsername/*=NULL*/,
  84. LPCTSTR lpszPassword/*=NULL*/,
  85. BOOL bForceDownload/*=FALSE*/ // 如果为 TRUE 表示强制性重新下载,以下载的部分将会被删除,FALSE 表示断点续传
  86. )
  87. {
  88. if ( !HANDLE_IS_VALID(m_hEvtEndModule) )
  89. return FALSE;
  90. if ( !lpszSavePath || strlen(lpszSavePath) < 1 )
  91. return FALSE;
  92. m_csSavePath = lpszSavePath;
  93. m_csSaveOnlyFileName = GET_SAFE_STRING(lpszSaveOnlyFileName);
  94. m_bForceDownload = bForceDownload;
  95. CString csServer, csObject;
  96. USHORT nPort = 0;
  97. if ( !ParseURL ( lpszDownloadURL, csServer, csObject, nPort, m_csProtocolType ) )
  98. {
  99. Log ( L_ERROR, "Download URL [%s] invalid", lpszDownloadURL );
  100. return FALSE;
  101. }
  102. m_csDownloadURL = lpszDownloadURL;
  103. // 创建取站点信息对象
  104. if ( !( m_pDownloadPub_Info = CreateDownloadObject () ) )
  105. {
  106. Log ( L_ERROR, "Create download object failed" );
  107. return HandleDownloadFinished(ENUM_DOWNLOAD_RESULT_FAILED);
  108. }
  109. // 设置取站点信息对象的参数
  110. m_pDownloadPub_Info->SetAuthorization ( lpszUsername, lpszPassword );
  111. m_pDownloadPub_Info->m_pDownloadMTR = this;
  112. m_pDownloadPub_Info->SetDownloadUrl ( lpszDownloadURL );
  113. // 创建一个下载线程
  114. DWORD dwThreadId = 0;
  115. m_hThread = CreateThread ( NULL, 0, ::ThreadProc_DownloadMTR, LPVOID(this), 0, &dwThreadId );
  116. if ( !HANDLE_IS_VALID(m_hThread) )
  117. {
  118. Log ( L_WARNING, "Create download thread failed" );
  119. return FALSE;
  120. }
  121. return TRUE;
  122. }
  123. //
  124. // 创建下载对象
  125. //
  126. CDownloadPub* CDownloadMTR::CreateDownloadObject ( int nCount/*=1*/ )
  127. {
  128. if ( nCount < 1 ) return NULL;
  129. CDownloadPub *pDownloadPub = NULL;
  130. if ( m_csProtocolType.CompareNoCase ( "http" ) == 0 )
  131. {
  132. pDownloadPub = (CDownloadPub*)new CDownloadHttp[nCount];
  133. }
  134. else if ( m_csProtocolType.CompareNoCase ( "ftp" ) == 0 )
  135. {
  136. pDownloadPub = (CDownloadPub*)new CDownloadFtp[nCount];
  137. }
  138. else return NULL;
  139. return pDownloadPub;
  140. }
  141. //
  142. // 删除下载对象
  143. //
  144. void CDownloadMTR::DeleteDownloadObject ( CDownloadPub *pDownloadPub )
  145. {
  146. if ( m_csProtocolType.CompareNoCase ( "http" ) == 0 )
  147. {
  148. delete[] ( (CDownloadHttp*)pDownloadPub );
  149. }
  150. else if ( m_csProtocolType.CompareNoCase ( "ftp" ) == 0 )
  151. {
  152. delete[] ( (CDownloadFtp*)pDownloadPub );
  153. }
  154. else delete[] pDownloadPub;
  155. }
  156. void Callback_SaveDownloadInfo ( int nIndex, int nDownloadedSize, int nSimpleSaveSize, WPARAM wParam )
  157. {
  158. CDownloadMTR *pDownloadMTR = (CDownloadMTR*)wParam;
  159. ASSERT ( pDownloadMTR );
  160. pDownloadMTR->Callback_SaveDownloadInfo ( nIndex, nDownloadedSize, nSimpleSaveSize );
  161. }
  162. void CDownloadMTR::Callback_SaveDownloadInfo ( int nIndex, int nDownloadedSize, int nSimpleSaveSize )
  163. {
  164. if ( nIndex >= 0 && nIndex < m_nThreadCount )
  165. {
  166. m_pDownloadCellInfo[nIndex].nDownloadedSize = nDownloadedSize;
  167. if ( nDownloadedSize > 0 )
  168. {
  169. m_CSFor_DownloadedData.Lock();
  170. m_BaseDownInfo.nTotalDownloadedSize += nSimpleSaveSize;
  171. m_nTotalDownloadedSize_ThisTimes += nSimpleSaveSize;
  172. m_CSFor_DownloadedData.Unlock ();
  173. }
  174. }
  175. }
  176. //
  177. // 创建多线程下载使用的对象和数据缓冲
  178. //
  179. BOOL CDownloadMTR::CreateDownloadObjectAndDataMTR ()
  180. {
  181. DeleteDownloadObjectAndDataMTR ();
  182. ASSERT ( !m_pDownloadPub_MTR && m_pDownloadPub_Info );
  183. m_pDownloadPub_MTR = CreateDownloadObject ( m_nThreadCount );
  184. // 设置多线程下载使用的对象的参数
  185. if ( m_pDownloadPub_MTR )
  186. {
  187. for ( int nIndex=0; nIndex<m_nThreadCount; nIndex++ )
  188. {
  189. m_pDownloadPub_MTR[nIndex].m_nIndex = nIndex;
  190. m_pDownloadPub_MTR[nIndex].m_pDownloadMTR = this;
  191. m_pDownloadPub_MTR[nIndex].Set_SaveDownloadInfo_Callback ( ::Callback_SaveDownloadInfo, WPARAM(this) );
  192. m_pDownloadPub_MTR[nIndex].SetAuthorization ( m_pDownloadPub_Info->Get_UserName(), m_pDownloadPub_Info->Get_GetPassword() );
  193. m_pDownloadPub_MTR[nIndex].SetDownloadUrl ( m_pDownloadPub_Info->Get_DownloadUrl () );
  194. if ( !m_pDownloadPub_MTR[nIndex].SetSaveFileName ( GetTempFilePath() ) )
  195. return FALSE;
  196. }
  197. }
  198. // 创建多线程下载使用的数据缓冲
  199. ASSERT ( !m_pDownloadCellInfo );
  200. m_pDownloadCellInfo = new t_DownloadCellInfo[m_nThreadCount];
  201. if ( m_pDownloadCellInfo )
  202. memset ( m_pDownloadCellInfo, 0, m_nThreadCount*sizeof(t_DownloadCellInfo) );
  203. if ( m_pDownloadPub_MTR != NULL && m_pDownloadCellInfo != NULL )
  204. return TRUE;
  205. Log ( L_WARNING, "Create MTR download object or buffer failed" );
  206. return FALSE;
  207. }
  208. //
  209. // 删除多线程下载使用的对象和数据缓冲
  210. //
  211. void CDownloadMTR::DeleteDownloadObjectAndDataMTR()
  212. {
  213. if ( m_pDownloadPub_MTR )
  214. {
  215. DeleteDownloadObject ( m_pDownloadPub_MTR );
  216. m_pDownloadPub_MTR = NULL;
  217. }
  218. if ( m_pDownloadCellInfo )
  219. {
  220. delete[] m_pDownloadCellInfo;
  221. m_pDownloadCellInfo = NULL;
  222. }
  223. }
  224. //
  225. // 删除取站点信息的下载对象
  226. //
  227. void CDownloadMTR::DeleteDownloadObject_Info()
  228. {
  229. if ( m_pDownloadPub_Info )
  230. {
  231. DeleteDownloadObject ( m_pDownloadPub_Info );
  232. m_pDownloadPub_Info = NULL;
  233. }
  234. }
  235. //
  236. // 启动多线程下载,返回 0 表示失败,1表示成功,2表示不用下载了,因为该文件已经下载过了
  237. //
  238. int CDownloadMTR::StartMTRDownload ()
  239. {
  240. m_dwDownloadStartTime = GetTickCount();
  241. DownloadNotify ( -1, NOTIFY_TYPE_START_DOWNLOAD, (LPVOID)NULL, this );
  242. // 先获取站点信息
  243. ASSERT ( m_pDownloadPub_Info );
  244. if ( !m_pDownloadPub_Info->GetRemoteSiteInfo () )
  245. return 0;
  246. DbgLog ( "要下载的文件大小是:%d 字节n", m_pDownloadPub_Info->Get_FileTotalSize () );
  247. StandardSaveFileName ();
  248. // 要保存的文件是否已经存在,且大小和创建时间一致,如果不是强制性下载,则不需要再下载了。
  249. CFileStatus fileStatus;
  250. if ( CFile::GetStatus(m_csSavePathFileName,fileStatus) )
  251. {
  252. if (
  253. (
  254. fileStatus.m_mtime.GetTime() - m_pDownloadPub_Info->Get_TimeLastModified() <=2 &&
  255. m_pDownloadPub_Info->Get_TimeLastModified()-fileStatus.m_mtime.GetTime() <=2
  256. )
  257. &&
  258. fileStatus.m_size == m_pDownloadPub_Info->Get_FileTotalSize ()
  259. &&
  260. !m_bForceDownload
  261. )
  262. {
  263. return 2;
  264. }
  265. // 需要重新下载
  266. ::DeleteFile ( m_csSavePathFileName );
  267. ::DeleteFile ( GetTempFilePath() );
  268. }
  269. BOOL bMustCreateNullFile = TRUE;
  270. // 读取下载信息,如果能读到说明上次下载尚未完成
  271. if ( m_pDownloadPub_Info->Is_SupportResume() )
  272. {
  273. if ( CFile::GetStatus(GetTempFilePath(),fileStatus) &&
  274. fileStatus.m_size == m_pDownloadPub_Info->Get_FileTotalSize()+GetDownloadInfoWholeSize() )
  275. {
  276. if ( ReadDownloadInfo () )
  277. bMustCreateNullFile = FALSE;
  278. }
  279. }
  280. if ( bMustCreateNullFile )
  281. {
  282. int nFileSize = m_pDownloadPub_Info->Get_FileTotalSize();
  283. int nTempFileSize = nFileSize+GetDownloadInfoWholeSize();
  284. if ( nFileSize < 0 || !m_pDownloadPub_Info->Is_SupportResume() )
  285. nTempFileSize = 0;
  286. // 创建一个用来保存下载数据的空文件
  287. if ( !CreateNullFile ( GetTempFilePath(), nTempFileSize ) )
  288. return FALSE;
  289. }
  290. // 分配下载任务
  291. if ( !AssignDownloadTask () )
  292. {
  293. Log ( L_WARNING, "Assign task failed" );
  294. return 0;
  295. }
  296. m_dwDownloadStartTime = GetTickCount();
  297. return 1;
  298. }
  299. //
  300. // 得到临时数据保存的路径文件名
  301. //
  302. CString CDownloadMTR::GetTempFilePath ()
  303. {
  304. ASSERT ( !m_csSavePathFileName.IsEmpty () );
  305. CString csTempFileName;
  306. csTempFileName.Format ( "%s.~xhw~", m_csSavePathFileName );
  307. ::SetFileAttributes ( csTempFileName, FILE_ATTRIBUTE_HIDDEN );
  308. return csTempFileName;
  309. }
  310. //
  311. // 分配下载任务
  312. //
  313. BOOL CDownloadMTR::AssignDownloadTask()
  314. {
  315. ASSERT ( m_pDownloadPub_Info );
  316. if ( !m_pDownloadPub_Info->Is_SupportResume() )
  317. {
  318. DeleteDownloadObjectAndDataMTR ();
  319. Log ( L_WARNING, "Site [%s] not support resume download", m_pDownloadPub_Info->Get_ServerName() );
  320. }
  321. // 文件大小未知,采用单线程
  322. if ( m_pDownloadPub_Info->Get_FileTotalSize () <= 0 || !m_pDownloadPub_Info->Is_SupportResume() )
  323. {
  324. if ( m_nThreadCount != 1 )
  325. {
  326. DeleteDownloadObjectAndDataMTR ();
  327. SetThreadCount ( 1 );
  328. }
  329. }
  330. if ( !DownloadInfoIsValid() || !m_pDownloadPub_MTR || !m_pDownloadCellInfo )
  331. {
  332. if ( !CreateDownloadObjectAndDataMTR () )
  333. return FALSE;
  334. }
  335. ASSERT ( m_pDownloadPub_MTR && m_pDownloadCellInfo );
  336. // 下载任务尚未分配
  337. if ( !DownloadInfoIsValid() )
  338. {
  339. int nWillDownloadSize = -1, nWillDownloadStartPos = 0, nNoAssignSize = 0;
  340. if ( m_pDownloadPub_Info->Get_FileTotalSize () > 0 )
  341. {
  342. nWillDownloadSize = m_pDownloadPub_Info->Get_FileTotalSize () / m_nThreadCount;
  343. // 均分后剩下的部分,让第一个线程来承担下载
  344. nNoAssignSize = m_pDownloadPub_Info->Get_FileTotalSize () % m_nThreadCount;
  345. }
  346. DbgLog ( "任务分配如下:--------------------n" );
  347. for ( int nIndex=0; nIndex<m_nThreadCount; nIndex++ )
  348. {
  349. m_pDownloadCellInfo[nIndex].nWillDownloadStartPos = nWillDownloadStartPos;
  350. m_pDownloadCellInfo[nIndex].nWillDownloadSize = nWillDownloadSize;
  351. if ( nIndex == 0 && m_pDownloadPub_Info->Get_FileTotalSize () > 0 )
  352. {
  353. m_pDownloadCellInfo[nIndex].nWillDownloadSize += nNoAssignSize;
  354. }
  355. DbgLog ( "线程.%d 从 %d(0x%08x) 下载到 %d(0x%08x) 共 %d(0x%08x) 字节n", nIndex, 
  356. m_pDownloadCellInfo[nIndex].nWillDownloadStartPos, m_pDownloadCellInfo[nIndex].nWillDownloadStartPos,
  357. m_pDownloadCellInfo[nIndex].nWillDownloadStartPos+m_pDownloadCellInfo[nIndex].nWillDownloadSize,
  358. m_pDownloadCellInfo[nIndex].nWillDownloadStartPos+m_pDownloadCellInfo[nIndex].nWillDownloadSize,
  359. m_pDownloadCellInfo[nIndex].nWillDownloadSize, m_pDownloadCellInfo[nIndex].nWillDownloadSize );
  360. nWillDownloadStartPos += m_pDownloadCellInfo[nIndex].nWillDownloadSize;
  361. }
  362. }
  363. // 启动下载任务
  364. for ( int nIndex=0; nIndex<m_nThreadCount; nIndex++ )
  365. {
  366. if ( !m_pDownloadPub_MTR[nIndex].Download ( m_pDownloadCellInfo[nIndex].nWillDownloadStartPos,
  367. m_pDownloadCellInfo[nIndex].nWillDownloadSize, m_pDownloadCellInfo[nIndex].nDownloadedSize ) )
  368. return FALSE;
  369. }
  370. m_BaseDownInfo.dwThreadCount = m_nThreadCount;
  371. return TRUE;
  372. }
  373. //
  374. // 从下载信息文件中读取下载信息
  375. //
  376. BOOL CDownloadMTR::ReadDownloadInfo()
  377. {
  378. CString csTempFileName = GetTempFilePath ();
  379. BOOL bRet = FALSE;
  380. CFile file;
  381. TRY
  382. {
  383. if ( file.Open ( csTempFileName, CFile::modeCreate|CFile::modeNoTruncate|CFile::modeReadWrite|CFile::typeBinary|CFile::shareDenyNone ) )
  384. {
  385. if ( file.Seek ( -(int)sizeof(t_BaseDownInfo), CFile::end ) == (int)(file.GetLength() - sizeof(t_BaseDownInfo)) )
  386. {
  387. if ( (UINT)file.Read ( &m_BaseDownInfo, sizeof(t_BaseDownInfo) ) == sizeof(t_BaseDownInfo) )
  388. {
  389. if ( (m_BaseDownInfo.dwThreadCount > 0 && m_BaseDownInfo.dwThreadCount <= MAX_DOWNLOAD_THREAD_COUNT)&&
  390. SetThreadCount ( m_BaseDownInfo.dwThreadCount ) )
  391. {
  392. if ( CreateDownloadObjectAndDataMTR () )
  393. {
  394. if ( file.Seek ( -GetDownloadInfoWholeSize(), CFile::end ) == int(file.GetLength() - GetDownloadInfoWholeSize()) )
  395. {
  396. if ( file.Read ( m_pDownloadCellInfo, sizeof(t_DownloadCellInfo)*m_nThreadCount ) == sizeof(t_DownloadCellInfo)*m_nThreadCount )
  397. {
  398. bRet = TRUE;
  399. }
  400. else
  401. {
  402. memset ( m_pDownloadCellInfo, 0, sizeof(t_DownloadCellInfo)*m_nThreadCount );
  403. }
  404. }
  405. }
  406. }
  407. }
  408. }
  409. }
  410. }
  411. CATCH( CFileException, e )
  412. {
  413. e->Delete ();
  414. bRet = FALSE;
  415. }
  416. END_CATCH
  417. if ( HANDLE_IS_VALID(file.m_hFile) )
  418. file.Close ();
  419. return bRet;
  420. }
  421. BOOL CDownloadMTR::SaveDownloadInfo ()
  422. {
  423. if ( !m_pDownloadPub_Info->Is_SupportResume() )
  424. return TRUE;
  425. CString csTempFileName = GetTempFilePath ();
  426. BOOL bRet = FALSE;
  427. CFile file;
  428. TRY
  429. {
  430. if ( file.Open ( csTempFileName, CFile::modeCreate|CFile::modeNoTruncate|CFile::modeReadWrite|CFile::typeBinary|CFile::shareDenyNone ) )
  431. {
  432. if ( file.Seek ( -(int)sizeof(t_BaseDownInfo), CFile::end ) == (int)(file.GetLength() - sizeof(t_BaseDownInfo)) )
  433. {
  434. file.Write ( &m_BaseDownInfo, sizeof(t_BaseDownInfo) );
  435. if ( file.Seek ( -GetDownloadInfoWholeSize(), CFile::end ) == int(file.GetLength() - GetDownloadInfoWholeSize()) )
  436. {
  437. file.Write ( m_pDownloadCellInfo, m_nThreadCount*sizeof(t_DownloadCellInfo) );
  438. bRet = TRUE;
  439. }
  440. }
  441. }
  442. }
  443. CATCH( CFileException, e )
  444. {
  445. e->Delete ();
  446. bRet = FALSE;
  447. }
  448. END_CATCH
  449. if ( HANDLE_IS_VALID ( file.m_hFile ) )
  450. file.Close ();
  451. if ( !bRet ) Log ( L_WARNING, "Save download info failed. %s", hwFormatMessage ( GetLastError() ) );
  452. return bRet;
  453. }
  454. BOOL CDownloadMTR::HandleDownloadFinished(ENUM_DOWNLOAD_RESULT eDownloadResult)
  455. {
  456. CString csTempFileName;
  457. CFileStatus fileStatus;
  458. BOOL bRet = FALSE;
  459. CFile file;
  460. if ( eDownloadResult != ENUM_DOWNLOAD_RESULT_SUCCESS )
  461. {
  462. SaveDownloadInfo ();
  463. goto Finished;
  464. }
  465. csTempFileName = GetTempFilePath ();
  466. // 设置文件大小
  467. if ( m_pDownloadPub_Info->Is_SupportResume() && m_pDownloadPub_Info->Get_FileTotalSize() > 0 )
  468. {
  469. TRY
  470. {
  471. file.Open ( csTempFileName, CFile::modeCreate|CFile::modeNoTruncate|CFile::modeReadWrite|CFile::typeBinary|CFile::shareDenyNone );
  472. file.SetLength(m_pDownloadPub_Info->Get_FileTotalSize ());
  473. bRet = TRUE;
  474. }
  475. CATCH( CFileException, e )
  476. {
  477. e->Delete ();
  478. bRet = FALSE;
  479. }
  480. END_CATCH
  481. if ( HANDLE_IS_VALID(file.m_hFile) )
  482. file.Close ();
  483. if ( !bRet )
  484. {
  485. Log ( L_WARNING, "Set [%s] length failed", csTempFileName );
  486. eDownloadResult = ENUM_DOWNLOAD_RESULT_FAILED;
  487. goto Finished;
  488. }
  489. }
  490. if ( _access(csTempFileName,04) == 0 )
  491. {
  492. // 将文件改名
  493. bRet = FALSE;
  494. DeleteFile ( m_csSavePathFileName );
  495. TRY
  496. {
  497. CFile::Rename ( csTempFileName, m_csSavePathFileName );
  498. bRet = TRUE;
  499. }
  500. CATCH( CFileException, e )
  501. {
  502. e->Delete ();
  503. bRet = FALSE;
  504. }
  505. END_CATCH
  506. if ( !bRet )
  507. {
  508. Log ( L_WARNING, "Rename [%s] failed. %s", csTempFileName, hwFormatMessage(GetLastError()) );
  509. eDownloadResult = ENUM_DOWNLOAD_RESULT_FAILED;
  510. goto Finished;
  511. }
  512. // 设置文件属性,时间设置和服务器一致
  513. bRet = FALSE;
  514. if ( CFile::GetStatus(m_csSavePathFileName,fileStatus) )
  515. {
  516. fileStatus.m_mtime = m_pDownloadPub_Info->Get_TimeLastModified();
  517. fileStatus.m_attribute = CFile::normal;
  518. CFile::SetStatus ( m_csSavePathFileName, fileStatus );
  519. bRet = TRUE;
  520. }
  521. if ( !bRet )
  522. {
  523. Log ( L_WARNING, "Set file [%s] status failed. %s", csTempFileName, hwFormatMessage(GetLastError()) );
  524. eDownloadResult = ENUM_DOWNLOAD_RESULT_FAILED;
  525. goto Finished;
  526. }
  527. }
  528. Finished:
  529. DownloadNotify ( -1, NOTIFY_TYPE_END_DOWNLOAD, (LPVOID)eDownloadResult, this );
  530. return bRet;
  531. }
  532. BOOL CDownloadMTR::GetDownloadResult()
  533. {
  534. for ( int nIndex=0; nIndex<m_nThreadCount; nIndex++ )
  535. {
  536. if ( !m_pDownloadPub_MTR[nIndex].Is_DownloadSuccess() )
  537. return FALSE;
  538. }
  539. return TRUE;
  540. }
  541. //
  542. // 下载信息是否有效
  543. //
  544. BOOL CDownloadMTR::DownloadInfoIsValid()
  545. {
  546. BOOL bValid = FALSE;
  547. int nIndex = 0;
  548. if ( !m_pDownloadCellInfo ) goto Invalid;
  549. if ( m_BaseDownInfo.dwThreadCount < 1 || m_BaseDownInfo.dwThreadCount > MAX_DOWNLOAD_THREAD_COUNT )
  550. goto Invalid;
  551. for ( nIndex=0; nIndex<m_nThreadCount; nIndex++ )
  552. {
  553. if ( m_pDownloadCellInfo[nIndex].nWillDownloadSize > 0 )
  554. {
  555. bValid = TRUE;
  556. break;
  557. }
  558. }
  559. if ( !bValid ) goto Invalid;
  560. return TRUE;
  561. Invalid:
  562. if ( m_pDownloadCellInfo )
  563. memset ( m_pDownloadCellInfo, 0, m_nThreadCount*sizeof(t_DownloadCellInfo) );
  564. memset ( &m_BaseDownInfo, 0, sizeof(t_BaseDownInfo) );
  565. return FALSE;
  566. }
  567. //
  568. // 找到剩余未下载的数量最大的那个对象编号
  569. //
  570. int CDownloadMTR::GetUndownloadMaxBytes( int &nUndownloadBytes )
  571. {
  572. nUndownloadBytes = 0;
  573. int nMaxIndex = -1;
  574. for ( int nIndex=0; nIndex<m_nThreadCount; nIndex++ )
  575. {
  576. int nTempBytes = m_pDownloadPub_MTR[nIndex].GetUndownloadBytes ();
  577. if ( nUndownloadBytes < nTempBytes )
  578. {
  579. nUndownloadBytes = nTempBytes;
  580. nMaxIndex = nIndex;
  581. }
  582. }
  583. return nMaxIndex;
  584. }
  585. //
  586. // 编号为 nIndex 的对象调度任务,为下载任务最繁重的对象减轻负担
  587. //
  588. BOOL CDownloadMTR::AttemperDownloadTask(int nIndex)
  589. {
  590. ASSERT ( m_pDownloadPub_MTR && m_pDownloadCellInfo );
  591. if ( m_nThreadCount <= 1 || m_pDownloadCellInfo[nIndex].nWillDownloadSize == -1 )
  592. return FALSE;
  593. int nUndownloadBytes = 0;
  594. int nIndex_Heavy = GetUndownloadMaxBytes ( nUndownloadBytes );
  595. if ( nIndex_Heavy == -1 || nIndex_Heavy == nIndex || nUndownloadBytes < 10*1024 )
  596. return FALSE;
  597. ASSERT ( nIndex_Heavy >= 0 && nIndex_Heavy < m_nThreadCount );
  598. ASSERT ( m_pDownloadPub_MTR[nIndex_Heavy].Get_WillDownloadStartPos() == m_pDownloadCellInfo[nIndex_Heavy].nWillDownloadStartPos );
  599. DbgLog ( "下载对象.%d 帮 %d 减轻负担n", nIndex, nIndex_Heavy );
  600. // 给空闲下载对象分配新任务
  601. m_pDownloadCellInfo[nIndex].nWillDownloadSize = nUndownloadBytes / 2;
  602. m_pDownloadCellInfo[nIndex].nWillDownloadStartPos = m_pDownloadPub_MTR[nIndex_Heavy].Get_WillDownloadStartPos() +
  603. m_pDownloadPub_MTR[nIndex_Heavy].Get_WillDownloadSize() - m_pDownloadCellInfo[nIndex].nWillDownloadSize;
  604. m_pDownloadCellInfo[nIndex].nDownloadedSize = 0;
  605. DbgLog ( "空闲下载对象.%d 分配新任务: %d(0x%08x) - %d(0x%08x) 共 %d(0x%08x)n", nIndex, m_pDownloadCellInfo[nIndex].nWillDownloadStartPos, m_pDownloadCellInfo[nIndex].nWillDownloadStartPos,
  606. m_pDownloadCellInfo[nIndex].nWillDownloadStartPos + m_pDownloadCellInfo[nIndex].nWillDownloadSize, m_pDownloadCellInfo[nIndex].nWillDownloadStartPos + m_pDownloadCellInfo[nIndex].nWillDownloadSize,
  607. m_pDownloadCellInfo[nIndex].nWillDownloadSize, m_pDownloadCellInfo[nIndex].nWillDownloadSize );
  608. // 减轻繁忙下载对象的任务
  609. m_pDownloadCellInfo[nIndex_Heavy].nWillDownloadSize -= m_pDownloadCellInfo[nIndex].nWillDownloadSize;
  610. m_pDownloadPub_MTR[nIndex_Heavy].Set_WillDownloadSize ( m_pDownloadCellInfo[nIndex_Heavy].nWillDownloadSize );
  611. DbgLog ( "繁忙下载对象.%d 下载了 %d(0x%08x) 未完 %d(0x%08x) 字节,调整任务为: %d(0x%08x) - %d(0x%08x) 共 %d(0x%08x)n",
  612. nIndex_Heavy, m_pDownloadPub_MTR[nIndex_Heavy].Get_DownloadedSize(), m_pDownloadPub_MTR[nIndex_Heavy].Get_DownloadedSize(),
  613. nUndownloadBytes, nUndownloadBytes,
  614. m_pDownloadCellInfo[nIndex_Heavy].nWillDownloadStartPos, m_pDownloadCellInfo[nIndex_Heavy].nWillDownloadStartPos,
  615. m_pDownloadCellInfo[nIndex_Heavy].nWillDownloadStartPos + m_pDownloadCellInfo[nIndex_Heavy].nWillDownloadSize, m_pDownloadCellInfo[nIndex_Heavy].nWillDownloadStartPos + m_pDownloadCellInfo[nIndex_Heavy].nWillDownloadSize,
  616. m_pDownloadCellInfo[nIndex_Heavy].nWillDownloadSize, m_pDownloadCellInfo[nIndex_Heavy].nWillDownloadSize );
  617. // 启动空闲下载对象的下载任务
  618. m_pDownloadPub_MTR[nIndex].ResetVar ();
  619. if ( !m_pDownloadPub_MTR[nIndex].Download ( m_pDownloadCellInfo[nIndex].nWillDownloadStartPos,
  620. m_pDownloadCellInfo[nIndex].nWillDownloadSize, m_pDownloadCellInfo[nIndex].nDownloadedSize ) )
  621. return FALSE;
  622. return TRUE;
  623. }
  624. //
  625. // 等待下载结束
  626. //
  627. ENUM_DOWNLOAD_RESULT CDownloadMTR::WaitForDownloadFinished()
  628. {
  629. ASSERT ( HANDLE_IS_VALID(m_hEvtEndModule) );
  630. int nCount = m_nThreadCount + 1;
  631. ENUM_DOWNLOAD_RESULT eDownloadResult = ENUM_DOWNLOAD_RESULT_FAILED;
  632. HANDLE *lpHandles = new HANDLE[nCount];
  633. if ( !lpHandles ) goto End;
  634. while ( TRUE )
  635. {
  636. nCount = 0;
  637. for ( int nIndex=0; nIndex<m_nThreadCount; nIndex++ )
  638. {
  639. HANDLE hThread = m_pDownloadPub_MTR[nIndex].Get_Thread_Handle ();
  640. if ( HANDLE_IS_VALID(hThread) )
  641. lpHandles[nCount++] = hThread;
  642. }
  643. lpHandles[nCount++] = m_hEvtEndModule;
  644. if ( nCount == 1 )
  645. {
  646. if ( m_BaseDownInfo.nTotalDownloadedSize >= m_pDownloadPub_Info->Get_FileTotalSize() )
  647. eDownloadResult = ENUM_DOWNLOAD_RESULT_SUCCESS;
  648. else
  649. eDownloadResult = ENUM_DOWNLOAD_RESULT_FAILED;
  650. goto End;
  651. }
  652. int nRet = (int)WaitForMultipleObjects ( nCount, lpHandles, FALSE, INFINITE ) - WAIT_OBJECT_0;
  653. // 某下载对象完成任务了
  654. if ( nRet >= 0 && nRet < nCount-1 )
  655. {
  656. nIndex = FindIndexByThreadHandle ( lpHandles[nRet] );
  657. if ( ( nIndex >= 0 && nIndex < m_nThreadCount ) )
  658. {
  659. if ( !m_pDownloadPub_MTR[nIndex].Is_DownloadSuccess() ||
  660. !AttemperDownloadTask ( nIndex ) )
  661. {
  662. m_pDownloadPub_MTR[nIndex].Clear_Thread_Handle ();
  663. }
  664. }
  665. else
  666. {
  667. eDownloadResult = ENUM_DOWNLOAD_RESULT_CANCEL;
  668. goto End;
  669. }
  670. }
  671. // 模块结束
  672. else
  673. {
  674. eDownloadResult = ENUM_DOWNLOAD_RESULT_CANCEL;
  675. goto End;
  676. }
  677. }
  678. End:
  679. // 等待所有下载线程结束
  680. if ( eDownloadResult != ENUM_DOWNLOAD_RESULT_SUCCESS )
  681. {
  682. nCount = 0;
  683. for ( int nIndex=0; nIndex<m_nThreadCount; nIndex++ )
  684. {
  685. HANDLE hThread = m_pDownloadPub_MTR[nIndex].Get_Thread_Handle ();
  686. if ( HANDLE_IS_VALID(hThread) )
  687. lpHandles[nCount++] = hThread;
  688. }
  689. WaitForMultipleObjects ( nCount, lpHandles, TRUE, 500*1000 );
  690. }
  691. if ( lpHandles ) delete[] lpHandles;
  692. return eDownloadResult;
  693. }
  694. int CDownloadMTR::FindIndexByThreadHandle(HANDLE hThread)
  695. {
  696. for ( int nIndex=0; nIndex<m_nThreadCount; nIndex++ )
  697. {
  698. HANDLE hThread_Temp = m_pDownloadPub_MTR[nIndex].Get_Thread_Handle ();
  699. if ( HANDLE_IS_VALID(hThread_Temp) && hThread_Temp == hThread )
  700. return nIndex;
  701. }
  702. return -1;
  703. }
  704. int CDownloadMTR::GetDownloadInfoWholeSize()
  705. {
  706. return ( sizeof(t_DownloadCellInfo)*m_nThreadCount + sizeof(t_BaseDownInfo) );
  707. }
  708. //
  709. // 获取下载所消耗的时间(毫秒),可用来计算下载速度和推算剩余时间
  710. //
  711. DWORD CDownloadMTR::GetDownloadElapsedTime()
  712. {
  713. return (GetTickCount() - m_dwDownloadStartTime);
  714. }
  715. //
  716. // 停止下载。将所有下载线程关闭,将下载对象删除,文件关闭
  717. //
  718. void CDownloadMTR::StopDownload()
  719. {
  720. if ( HANDLE_IS_VALID(m_hEvtEndModule) )
  721. {
  722. ::SetEvent ( m_hEvtEndModule );
  723. }
  724. // 设置多线程下载使用的对象的参数
  725. if ( m_pDownloadPub_MTR )
  726. {
  727. for ( int nIndex=0; nIndex<m_nThreadCount; nIndex++ )
  728. {
  729. m_pDownloadPub_MTR[nIndex].StopDownload ();
  730. }
  731. }
  732. if ( HANDLE_IS_VALID(m_hThread) )
  733. {
  734. WaitForThreadEnd ( m_hThread,30*1000 );
  735. CLOSE_HANDLE ( m_hThread )
  736. }
  737. DeleteDownloadObjectAndDataMTR ();
  738. DeleteDownloadObject_Info ();
  739. CLOSE_HANDLE ( m_hEvtEndModule );
  740. }
  741. void CDownloadMTR::StandardSaveFileName ()
  742. {
  743. ASSERT ( m_csSavePath.GetLength() > 0 );
  744. StandardizationPathBuffer ( m_csSavePath.GetBuffer(MAX_PATH), MAX_PATH );
  745. m_csSavePath.ReleaseBuffer ();
  746. MakeSureDirectory ( m_csSavePath );
  747. char szOnlyFileName_NoExt_User[MAX_PATH] = {0};
  748. char szExtensionName_User[MAX_PATH] = {0};
  749. // 如果用户指定了新的保存文件名,就用新的。
  750. if ( m_csSaveOnlyFileName.GetLength() > 0 )
  751. {
  752. CString csFileNameByURL = GetLocalFileNameByURL ( m_csDownloadURL );
  753. if ( csFileNameByURL.CompareNoCase(m_csSaveOnlyFileName) != 0 )
  754. {
  755. PartFileAndExtensionName ( m_csSaveOnlyFileName, szOnlyFileName_NoExt_User, MAX_PATH, szExtensionName_User, MAX_PATH );
  756. }
  757. }
  758. CString csExtensionName_Remote;
  759. CString csFileName_Remote = m_pDownloadPub_Info->GetDownloadObjectFileName ( &csExtensionName_Remote );
  760. if ( strlen(szOnlyFileName_NoExt_User) > 0 )
  761. {
  762. if ( strlen(szExtensionName_User) < 1 )
  763. STRNCPY_CS ( szExtensionName_User, csExtensionName_Remote );
  764. m_csSavePathFileName.Format ( "%s%s.%s", StandardizationFileForPathName(m_csSavePath,FALSE),
  765. StandardizationFileForPathName(szOnlyFileName_NoExt_User,TRUE), StandardizationFileForPathName(szExtensionName_User,TRUE) );
  766. }
  767. else
  768. {
  769. m_csSavePathFileName.Format ( "%s%s", StandardizationFileForPathName(m_csSavePath,FALSE), StandardizationFileForPathName(csFileName_Remote,TRUE) );
  770. }
  771. }
  772. //
  773. // 根据 URL 来获取本地保存的文件名
  774. //
  775. CString CDownloadMTR::GetLocalFileNameByURL ( LPCTSTR lpszDownloadURL )
  776. {
  777. if ( !lpszDownloadURL || strlen(lpszDownloadURL) < 1 )
  778. return "";
  779. char szOnlyPath[MAX_PATH] = {0};
  780. char szOnlyFileName[MAX_PATH] = {0};
  781. if ( !PartFileAndPathByFullPath ( lpszDownloadURL, szOnlyFileName, MAX_PATH, szOnlyPath, MAX_PATH ) )
  782. return "";
  783. return szOnlyFileName;
  784. }
  785. //
  786. // 获取文件大小
  787. //
  788. int CDownloadMTR::Get_FileTotaleSize()
  789. {
  790. if ( !m_pDownloadPub_Info ) return -1;
  791. return m_pDownloadPub_Info->Get_FileTotalSize ();
  792. }
  793. //
  794. // 获取已下载的字节数
  795. //
  796. int CDownloadMTR::Get_TotalDownloadedSize()
  797. {
  798. m_CSFor_DownloadedData.Lock ();
  799. int nTotalDownloadedSize = m_BaseDownInfo.nTotalDownloadedSize;
  800. m_CSFor_DownloadedData.Unlock ();
  801. return nTotalDownloadedSize;
  802. }