FileCopy.cpp 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
  1. // FileCopy.cpp: implementation of the CFileCopy class.
  2. //
  3. //////////////////////////////////////////////////////////////////////
  4. #include "stdafx.h"
  5. #include "FileCopyDemo.h"
  6. #include "FileCopy.h"
  7. #ifdef _DEBUG
  8. #undef THIS_FILE
  9. static char THIS_FILE[]=__FILE__;
  10. #define new DEBUG_NEW
  11. #endif
  12. #include <Windows.h>
  13. #include <strsafe.h>
  14. #include <process.h>
  15. //////////////////////////////////////////////////////////////////////
  16. // Construction/Destruction
  17. //////////////////////////////////////////////////////////////////////
  18. class CAutoLock
  19. {
  20. private:
  21. LPCRITICAL_SECTION m_pcsLcok;
  22. public:
  23. CAutoLock(LPCRITICAL_SECTION pcsLcok)
  24. {
  25. m_pcsLcok = pcsLcok;
  26. if (m_pcsLcok)
  27. {
  28. EnterCriticalSection(m_pcsLcok);
  29. }
  30. }
  31. ~CAutoLock()
  32. {
  33. if (m_pcsLcok)
  34. {
  35. LeaveCriticalSection(m_pcsLcok);
  36. m_pcsLcok = NULL;
  37. }
  38. }
  39. };
  40. class CStopwatch
  41. {
  42. public:
  43. CStopwatch()
  44. {
  45. QueryPerformanceFrequency(&m_liPerfFreq);
  46. Start();
  47. }
  48. void Start()
  49. {
  50. QueryPerformanceCounter(&m_liPerfStart);
  51. }
  52. __int64 Now() const
  53. {
  54. LARGE_INTEGER liPerfNow;
  55. QueryPerformanceCounter(&liPerfNow);
  56. return (liPerfNow.QuadPart - m_liPerfStart.QuadPart) * 1000 / m_liPerfFreq.QuadPart;
  57. }
  58. __int64 NowInMicro() const
  59. {
  60. LARGE_INTEGER liPerfNow;
  61. QueryPerformanceCounter(&liPerfNow);
  62. return (liPerfNow.QuadPart - m_liPerfStart.QuadPart) * 1000000 / m_liPerfFreq.QuadPart;
  63. }
  64. private:
  65. LARGE_INTEGER m_liPerfFreq; //counter per second
  66. LARGE_INTEGER m_liPerfStart; //starting count
  67. };
  68. CFileCopy::CFileCopy()
  69. {
  70. m_bCancel = FALSE;
  71. m_dw64TotalFileSize = 0;
  72. m_dw64TotalBytesTransferred = 0;
  73. m_bIsCoping = FALSE;
  74. m_hPauseEvent = NULL;
  75. m_hFeedbackExitEvent = NULL;
  76. m_hAsyncCopyThreadHandle = NULL;
  77. m_hFeedbackProgressThreadHandle = NULL;
  78. m_pUserData = NULL;
  79. m_pAsyncCopyResultCB = NULL;
  80. m_pCopingProgressCB = NULL;
  81. m_dwProgressFeedbackTime = 0;
  82. InitializeCriticalSection(&m_csLock);
  83. }
  84. CFileCopy::~CFileCopy()
  85. {
  86. Cancel();
  87. DeleteCriticalSection(&m_csLock);
  88. }
  89. BOOL CFileCopy::CopyFile(IN LPCTSTR lpSrcFileName,
  90. IN LPCTSTR lpDesFileName,
  91. IN const BOOL bSynchronousCopy,
  92. IN const DWORD dwProgressFeedbackTime,
  93. OUT DOUBLE &dbSpeed,
  94. OUT tstring &strErrorMsg)
  95. {
  96. {
  97. CAutoLock autolock(&m_csLock);
  98. if (m_bIsCoping)
  99. {
  100. strErrorMsg = _T("In coping.");
  101. return FALSE;
  102. }
  103. m_bIsCoping = TRUE;
  104. }
  105. // 同步复制
  106. if (bSynchronousCopy)
  107. {
  108. m_dwProgressFeedbackTime = dwProgressFeedbackTime;
  109. BOOL bRet = SynchronousCopyFile(
  110. lpSrcFileName,
  111. lpDesFileName,
  112. dwProgressFeedbackTime,
  113. dbSpeed,
  114. strErrorMsg
  115. );
  116. m_bIsCoping = FALSE;
  117. return bRet;
  118. }
  119. // 异步复制
  120. m_strSrcFile = lpSrcFileName;
  121. m_strDesFile = lpDesFileName;
  122. m_dwProgressFeedbackTime = dwProgressFeedbackTime;
  123. unsigned threadID = 0;
  124. m_hAsyncCopyThreadHandle =
  125. (HANDLE)_beginthreadex(NULL, 0, &AsyncCopyThreadFunc, this, 0, &threadID);
  126. if (NULL == m_hAsyncCopyThreadHandle)
  127. {
  128. strErrorMsg = GetLastErrorMsg(_T("_beginthreadex"), GetLastError());
  129. return FALSE;
  130. }
  131. return TRUE;
  132. }
  133. BOOL CFileCopy::SynchronousCopyFile(LPCTSTR lpSrcFileName,
  134. LPCTSTR lpDesFileName,
  135. const DWORD dwProgressFeedbackTime,
  136. DOUBLE &dbSpeed,
  137. tstring &strErrorMsg)
  138. {
  139. m_bCancel = FALSE;
  140. m_dw64TotalFileSize = 0;
  141. m_dw64TotalBytesTransferred = 0;
  142. if (NULL == (m_hPauseEvent = CreateEvent(NULL, TRUE, TRUE, NULL)))
  143. {
  144. strErrorMsg = GetLastErrorMsg(_T("CreateEvent"), GetLastError());
  145. return FALSE;
  146. }
  147. if (0 != dwProgressFeedbackTime)
  148. {
  149. if (NULL == (m_hFeedbackExitEvent = CreateEvent(NULL, TRUE, FALSE, NULL)))
  150. {
  151. strErrorMsg = GetLastErrorMsg(_T("CreateEvent"), GetLastError());
  152. CloseAllHandles();
  153. return FALSE;
  154. }
  155. unsigned threadID = 0;
  156. m_hFeedbackProgressThreadHandle =
  157. (HANDLE)_beginthreadex(NULL, 0, &FeedbackProgressThreadFunc, this, 0, &threadID);
  158. if (NULL == m_hFeedbackProgressThreadHandle)
  159. {
  160. strErrorMsg = GetLastErrorMsg(_T("_beginthreadex"), GetLastError());
  161. CloseAllHandles();
  162. return FALSE;
  163. }
  164. }
  165. CStopwatch stopwatch;
  166. BOOL bRet = CopyFileEx(lpSrcFileName,
  167. lpDesFileName,
  168. CopyProgressRoutine,
  169. this,
  170. &m_bCancel,
  171. COPY_FILE_ALLOW_DECRYPTED_DESTINATION | COPY_FILE_FAIL_IF_EXISTS);
  172. if (!bRet)
  173. {
  174. strErrorMsg = GetLastErrorMsg(_T("CopyFileEx"), GetLastError());
  175. }
  176. else
  177. {
  178. // 成功了才需计算速度
  179. __int64 n64ElapseTimeInMs = stopwatch.Now();
  180. dbSpeed = (DOUBLE)(__int64)m_dw64TotalFileSize / n64ElapseTimeInMs;
  181. }
  182. if (0 != dwProgressFeedbackTime)
  183. {
  184. SetEvent(m_hFeedbackExitEvent);
  185. WaitForSingleObject(m_hFeedbackProgressThreadHandle, INFINITE);
  186. }
  187. CloseAllHandles();
  188. return bRet;
  189. }
  190. DWORD CALLBACK CFileCopy::CopyProgressRoutine(
  191. LARGE_INTEGER TotalFileSize,
  192. LARGE_INTEGER TotalBytesTransferred,
  193. LARGE_INTEGER StreamSize,
  194. LARGE_INTEGER StreamBytesTransferred,
  195. DWORD dwStreamNumber,
  196. DWORD dwCallbackReason,
  197. HANDLE hSourceFile,
  198. HANDLE hDestinationFile,
  199. LPVOID lpData
  200. )
  201. {
  202. CFileCopy *pFileCopy = (CFileCopy *)lpData;
  203. if (!pFileCopy)
  204. {
  205. return PROGRESS_CANCEL;
  206. }
  207. pFileCopy->m_dw64TotalFileSize = TotalFileSize.QuadPart;
  208. pFileCopy->m_dw64TotalBytesTransferred = TotalBytesTransferred.QuadPart;
  209. // 用于控制暂停
  210. WaitForSingleObject(pFileCopy->m_hPauseEvent, INFINITE);
  211. return PROGRESS_CONTINUE;
  212. }
  213. tstring CFileCopy::GetLastErrorMsg(LPCTSTR lpszFunction, const DWORD dwLastError)
  214. {
  215. LPVOID lpMsgBuf = NULL;
  216. LPVOID lpDisplayBuf = NULL;
  217. FormatMessage(
  218. FORMAT_MESSAGE_ALLOCATE_BUFFER |
  219. FORMAT_MESSAGE_FROM_SYSTEM |
  220. FORMAT_MESSAGE_IGNORE_INSERTS,
  221. NULL,
  222. dwLastError,
  223. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  224. (LPTSTR) &lpMsgBuf,
  225. 0, NULL );
  226. lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
  227. (lstrlen((LPCTSTR)lpMsgBuf)+lstrlen((LPCTSTR)lpszFunction)+40)*sizeof(TCHAR));
  228. StringCchPrintf((LPTSTR)lpDisplayBuf,
  229. LocalSize(lpDisplayBuf) / sizeof(TCHAR),
  230. TEXT("%s failed with error %d: %s"),
  231. lpszFunction, dwLastError, lpMsgBuf);
  232. tstring strLastError = (LPTSTR)lpDisplayBuf;
  233. LocalFree(lpMsgBuf);
  234. LocalFree(lpDisplayBuf);
  235. return strLastError;
  236. }
  237. void CFileCopy::CloseAllHandles()
  238. {
  239. if (m_hPauseEvent)
  240. {
  241. CloseHandle(m_hPauseEvent);
  242. m_hPauseEvent = NULL;
  243. }
  244. if (m_hFeedbackExitEvent)
  245. {
  246. CloseHandle(m_hFeedbackExitEvent);
  247. m_hFeedbackExitEvent = NULL;
  248. }
  249. if (m_hAsyncCopyThreadHandle)
  250. {
  251. CloseHandle(m_hAsyncCopyThreadHandle);
  252. m_hAsyncCopyThreadHandle = NULL;
  253. }
  254. if (m_hFeedbackProgressThreadHandle)
  255. {
  256. CloseHandle(m_hFeedbackProgressThreadHandle);
  257. m_hFeedbackProgressThreadHandle = NULL;
  258. }
  259. }
  260. void CFileCopy::Pause()
  261. {
  262. if (m_hPauseEvent)
  263. {
  264. ResetEvent(m_hPauseEvent);
  265. }
  266. }
  267. void CFileCopy::Resume()
  268. {
  269. if (m_hPauseEvent)
  270. {
  271. SetEvent(m_hPauseEvent);
  272. }
  273. }
  274. void CFileCopy::Cancel()
  275. {
  276. m_bCancel = TRUE;
  277. Resume();
  278. }
  279. unsigned CFileCopy::AsyncCopy()
  280. {
  281. unsigned usRet = 1;
  282. DOUBLE dbSpeed = 0.0;
  283. tstring strErrorMsg;
  284. BOOL bCopySuccess = SynchronousCopyFile(
  285. m_strSrcFile.c_str(),
  286. m_strDesFile.c_str(),
  287. m_dwProgressFeedbackTime,
  288. dbSpeed,
  289. strErrorMsg
  290. );
  291. if (m_pAsyncCopyResultCB)
  292. {
  293. m_pAsyncCopyResultCB(m_pUserData, bCopySuccess, dbSpeed, strErrorMsg);
  294. }
  295. m_bIsCoping = FALSE;
  296. return usRet;
  297. }
  298. unsigned CFileCopy::AsyncCopyThreadFunc(void* pArguments)
  299. {
  300. CFileCopy *pThis = (CFileCopy *)pArguments;
  301. if (NULL == pThis)
  302. {
  303. _endthreadex (1);
  304. return 1;
  305. }
  306. unsigned usRet = pThis->AsyncCopy();
  307. _endthreadex (usRet);
  308. return usRet;
  309. }
  310. unsigned CFileCopy::FeedbackProgress()
  311. {
  312. unsigned usRet = 1;
  313. DWORD64 dw64TotalBytesTransferred = 0;
  314. DWORD64 dw64TotalBytesTransferredBak = 0;
  315. DOUBLE dbSpeed = 0.0;
  316. DWORD dwPercentage = 0;
  317. __int64 n64ElapseTimeInMs = 0;
  318. __int64 n64UsedTimeInMs = 0;
  319. __int64 n64NowInMs = 0;
  320. CStopwatch stopwatch;
  321. while (WAIT_TIMEOUT == WaitForSingleObject(m_hFeedbackExitEvent, m_dwProgressFeedbackTime))
  322. {
  323. n64NowInMs = stopwatch.Now();
  324. dw64TotalBytesTransferred = m_dw64TotalBytesTransferred;
  325. n64ElapseTimeInMs = n64NowInMs - n64UsedTimeInMs;
  326. n64UsedTimeInMs = n64NowInMs;
  327. if (0 == n64ElapseTimeInMs)
  328. {
  329. dbSpeed = 0.0;
  330. }
  331. else
  332. {
  333. dbSpeed = (DOUBLE)(__int64)(dw64TotalBytesTransferred - dw64TotalBytesTransferredBak)
  334. / n64ElapseTimeInMs;
  335. }
  336. dw64TotalBytesTransferredBak = dw64TotalBytesTransferred;
  337. if (0 == m_dw64TotalFileSize)
  338. {
  339. dwPercentage = 0;
  340. }
  341. else
  342. {
  343. dwPercentage = m_dw64TotalBytesTransferred * 100 / m_dw64TotalFileSize;
  344. }
  345. if (m_pCopingProgressCB)
  346. {
  347. m_pCopingProgressCB(m_pUserData, dbSpeed, dwPercentage);
  348. }
  349. }
  350. return usRet;
  351. }
  352. unsigned CFileCopy::FeedbackProgressThreadFunc(void* pArguments)
  353. {
  354. CFileCopy *pThis = (CFileCopy *)pArguments;
  355. if (NULL == pThis)
  356. {
  357. _endthreadex (1);
  358. return 1;
  359. }
  360. unsigned usRet = pThis->FeedbackProgress();
  361. _endthreadex (usRet);
  362. return usRet;
  363. }