copyfiles.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613
  1. #include "main.h"
  2. #include "./copyfiles.h"
  3. #include "./copyinternal.h"
  4. #include "./resource.h"
  5. #include "./settings.h"
  6. #include "../nu/trace.h"
  7. #include <api/service/waServiceFactory.h>
  8. #include <shlwapi.h>
  9. #include <strsafe.h>
  10. static LONG szBusyDrive[26] = {0, };
  11. static CRITICAL_SECTION cs_copy = { 0,};
  12. static void NotifyDialog(COPYDATA *pcd, UINT uTask, UINT uOperation, LPARAM lParam)
  13. {
  14. if(pcd->hDialog) PostMessage(pcd->hDialog, CFM_NOTIFY, MAKEWPARAM(uTask, uOperation), lParam);
  15. }
  16. static INT_PTR QueryDialog(COPYDATA *pcd, UINT uTask, UINT uOperation, LPARAM lParam)
  17. {
  18. return (pcd->hDialog) ? SendMessage(pcd->hDialog, CFM_NOTIFY, MAKEWPARAM(uTask, uOperation), lParam) : FALSE;
  19. }
  20. static void CopyFiles_MarkDrivesBusy(LPCTSTR *ppsz, INT count, BOOL bBusy)
  21. {
  22. INT i, n;
  23. DWORD driveMask = 0x00;
  24. EnterCriticalSection(&cs_copy);
  25. if (bBusy)
  26. {
  27. for(i = 0; i < count; i++)
  28. {
  29. n = PathGetDriveNumber(ppsz[i]);
  30. if (-1 != n)
  31. {
  32. if (0 == szBusyDrive[n]) driveMask |= (((DWORD)0x01) << n);
  33. szBusyDrive[n]++;
  34. }
  35. }
  36. }
  37. else
  38. {
  39. for(i = 0; i < count; i++)
  40. {
  41. n = PathGetDriveNumber(ppsz[i]);
  42. if (-1 != n)
  43. {
  44. if (szBusyDrive[n] <= 0) continue;
  45. szBusyDrive[n]--;
  46. if (0 == szBusyDrive[n]) driveMask |= (((DWORD)0x01) << n);
  47. }
  48. }
  49. }
  50. LeaveCriticalSection(&cs_copy);
  51. if (0x00 != driveMask)
  52. {
  53. static UINT uMsgCopyNotify = 0;
  54. if (!uMsgCopyNotify) uMsgCopyNotify = RegisterWindowMessageA("WACOPY_BROADCAST_MSG");
  55. if (uMsgCopyNotify)
  56. {
  57. for (CHAR c = 'A'; 0x00 != driveMask; c++, driveMask>>=1)
  58. {
  59. if (0 == (0x01 & driveMask)) continue;
  60. if (bBusy) SendNotifyMessage(HWND_BROADCAST, uMsgCopyNotify, MAKEWPARAM(c, 0), (LPARAM)TRUE);
  61. else
  62. {
  63. SendNotifyMessage(HWND_BROADCAST, uMsgCopyNotify, MAKEWPARAM(c, 0), (LPARAM)FALSE);
  64. SendNotifyMessage(HWND_BROADCAST, uMsgCopyNotify, MAKEWPARAM(0, 0xffff), (LPARAM)plugin.hwndWinampParent);
  65. }
  66. }
  67. }
  68. }
  69. }
  70. static BOOL ReadCopyParameters(COPYDATA *pcd)
  71. {
  72. BOOL bVal;
  73. HRESULT hr = S_OK;
  74. pcd->uFlags = 0;
  75. if (S_OK == hr) hr = Settings_ReadString(C_COPY, CF_PATH, pcd->szDestination, ARRAYSIZE(pcd->szDestination));
  76. if (S_OK == hr) hr = Settings_ReadString(C_COPY, CF_TITLEFMT, pcd->szTitleFormat, ARRAYSIZE(pcd->szTitleFormat));
  77. if (S_OK == hr && S_OK == (hr = Settings_GetBool(C_COPY, CF_ADDTOMLDB, &bVal)) && bVal) pcd->uFlags |= FCF_ADDTOMLDB;
  78. if (S_OK == hr && S_OK == (hr = Settings_GetBool(C_COPY, CF_USETITLEFMT, &bVal)) && bVal) pcd->uFlags |= FCF_USETITLEFMT;
  79. CleanupDirectoryString(pcd->szDestination);
  80. return (S_OK == hr);
  81. }
  82. void MLDisc_InitializeCopyData()
  83. {
  84. InitializeCriticalSection(&cs_copy);
  85. }
  86. void MLDisc_ReleaseCopyData()
  87. {
  88. DeleteCriticalSection(&cs_copy);
  89. }
  90. BOOL MLDisc_IsDiscCopying(CHAR cLetter)
  91. {
  92. if (cLetter >= 'a' && cLetter <= 'z') cLetter -= 0x20;
  93. return (cLetter >= 'A' && cLetter <= 'Z' && szBusyDrive[cLetter - 'A'] > 0);
  94. }
  95. BOOL MLDisc_CopyFiles(HWND hParent, LPWSTR *ppszFiles, ULONGLONG *pFSizes, INT count)
  96. {
  97. if (!ppszFiles || !count) return FALSE;
  98. if (NULL == hParent) hParent = plugin.hwndLibraryParent;
  99. COPYDATA *pcd = (COPYDATA*)CoTaskMemAlloc(sizeof(COPYDATA));
  100. if (!pcd) return FALSE;
  101. ZeroMemory(pcd, sizeof(COPYDATA));
  102. CopyFiles_AddRef(pcd);
  103. pcd->hOwner = hParent;
  104. pcd->ppszFiles = ppszFiles;
  105. pcd->pFSizes = pFSizes;
  106. pcd->count = count;
  107. pcd->bCancel = FALSE;
  108. waServiceFactory *factory = plugin.service->service_getServiceByGuid(api_metadataGUID);
  109. if (factory) pcd->pMetaReader = (api_metadata*) factory->getInterface();
  110. factory = plugin.service->service_getServiceByGuid(mldbApiGuid);
  111. if (factory) pcd->pMlDb = (api_mldb*) factory->getInterface();
  112. HWND hRoot = GetAncestor(hParent, GA_ROOT);
  113. if (NULL == hRoot) hRoot = hParent;
  114. INT_PTR result = WASABI_API_DIALOGBOXPARAMW(IDD_FILECOPY_PREPARE, hRoot, CopyPrepare_DialogProc, (LPARAM)pcd);
  115. if (IDCANCEL != result)
  116. {
  117. if (ReadCopyParameters(pcd))
  118. {
  119. HWND hCopy = WASABI_API_CREATEDIALOGPARAMW(IDD_FILECOPY_PROGRESS, hRoot, CopyProgress_DialogProc, (LPARAM)pcd);
  120. if (hCopy)
  121. {
  122. pcd->hDialog = hCopy;
  123. ShowWindow(hCopy, SW_SHOWNORMAL);
  124. RedrawWindow(hCopy, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN);
  125. }
  126. CopyFiles_StartCopy(pcd);
  127. }
  128. }
  129. CopyFiles_Release(pcd);
  130. return TRUE;
  131. }
  132. BOOL CopyFiles_CancelCopy(COPYDATA *pcd)
  133. {
  134. if (pcd) pcd->bCancel = TRUE;
  135. return (NULL != pcd);
  136. }
  137. LONG CopyFiles_AddRef(COPYDATA *pcd)
  138. {
  139. return (pcd) ? InterlockedIncrement(&pcd->ref) : 0;
  140. }
  141. LONG CopyFiles_Release(COPYDATA *pcd)
  142. {
  143. if (pcd && pcd->ref > 0)
  144. {
  145. LONG r = InterlockedDecrement(&pcd->ref);
  146. if ( 0 == r)
  147. {
  148. if (pcd->ppszFiles)
  149. {
  150. for (int i = 0; i < pcd->count; i++) CoTaskMemFree(pcd->ppszFiles[i]);
  151. CoTaskMemFree(pcd->ppszFiles);
  152. }
  153. if (pcd->pFSizes) CoTaskMemFree(pcd->pFSizes);
  154. if (pcd->hThread) CloseHandle(pcd->hThread);
  155. if(pcd->pMetaReader)
  156. {
  157. waServiceFactory *factory = plugin.service->service_getServiceByGuid(api_metadataGUID);
  158. if (factory) factory->releaseInterface(pcd->pMetaReader);
  159. }
  160. if(pcd->pMlDb)
  161. {
  162. waServiceFactory *factory = plugin.service->service_getServiceByGuid(mldbApiGuid);
  163. if (factory) factory->releaseInterface(pcd->pMlDb);
  164. }
  165. CoTaskMemFree(pcd);
  166. }
  167. return r;
  168. }
  169. return 0;
  170. }
  171. static ULONGLONG CopyFiles_CalculateTotalSize(COPYDATA *pcd)
  172. {
  173. ULONGLONG total = 0;
  174. if (!pcd->pFSizes)
  175. {
  176. pcd->pFSizes = (ULONGLONG*)CoTaskMemAlloc(sizeof(ULONGLONG)*pcd->count);
  177. if (!pcd->pFSizes)
  178. {
  179. pcd->errorCode = ERROR_NOT_ENOUGH_MEMORY;
  180. return 0;
  181. }
  182. LARGE_INTEGER fs;
  183. for(int i = 0; i < pcd->count; i++)
  184. {
  185. HANDLE hFile = CreateFile(pcd->ppszFiles[i], FILE_READ_ATTRIBUTES, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
  186. if (INVALID_HANDLE_VALUE == hFile)
  187. {
  188. pcd->errorCode = GetLastError();
  189. return 0;
  190. }
  191. if (!GetFileSizeEx(hFile, &fs)) { pcd->errorCode = GetLastError(); CloseHandle(hFile); return 0; }
  192. CloseHandle(hFile);
  193. pcd->pFSizes[i] = fs.QuadPart;
  194. }
  195. }
  196. for(int i = 0; i < pcd->count; i++) total += pcd->pFSizes[i];
  197. return total;
  198. }
  199. BOOL CopyFiles_CreateDirectory(LPCTSTR pszDirectory)
  200. {
  201. DWORD ec = ERROR_SUCCESS;
  202. if (!CreateDirectory(pszDirectory, NULL))
  203. {
  204. ec = GetLastError();
  205. if (ERROR_PATH_NOT_FOUND == ec)
  206. {
  207. LPCTSTR pszBlock = pszDirectory;
  208. TCHAR szBuffer[MAX_PATH] = {0};
  209. LPCTSTR pszCursor = PathFindNextComponent(pszBlock);
  210. ec = (pszCursor == pszBlock || S_OK != StringCchCopyN(szBuffer, ARRAYSIZE(szBuffer), pszBlock, (pszCursor - pszBlock))) ?
  211. ERROR_INVALID_NAME : ERROR_SUCCESS;
  212. pszBlock = pszCursor;
  213. while (ERROR_SUCCESS == ec && NULL != (pszCursor = PathFindNextComponent(pszBlock)))
  214. {
  215. if (pszCursor == pszBlock || S_OK != StringCchCatN(szBuffer, ARRAYSIZE(szBuffer), pszBlock, (pszCursor - pszBlock)))
  216. ec = ERROR_INVALID_NAME;
  217. if (ERROR_SUCCESS == ec && !CreateDirectory(szBuffer, NULL))
  218. {
  219. ec = GetLastError();
  220. if (ERROR_ALREADY_EXISTS == ec) ec = ERROR_SUCCESS;
  221. }
  222. pszBlock = pszCursor;
  223. }
  224. }
  225. if (ERROR_ALREADY_EXISTS == ec) ec = ERROR_SUCCESS;
  226. }
  227. SetLastError(ec);
  228. return (ERROR_SUCCESS == ec);
  229. }
  230. static BOOL CopyFiles_CheckDestination(COPYDATA *pcd, ULONGLONG needSize)
  231. {
  232. TCHAR szRoot[MAX_PATH] = {0};
  233. if (S_OK != StringCchCopy(szRoot, ARRAYSIZE(szRoot), pcd->szDestination))
  234. {
  235. pcd->errorCode = ERROR_OUTOFMEMORY;
  236. return FALSE;
  237. }
  238. PathStripToRoot(szRoot);
  239. ULARGE_INTEGER free, total;
  240. if (!GetDiskFreeSpaceEx(szRoot, &free, &total, NULL))
  241. {
  242. pcd->errorCode = GetLastError();
  243. return FALSE;
  244. }
  245. if (needSize > free.QuadPart)
  246. {
  247. pcd->errorCode = ERROR_DISK_FULL;
  248. return FALSE;
  249. }
  250. if (INVALID_FILE_ATTRIBUTES == GetFileAttributes(pcd->szDestination))
  251. {
  252. DWORD ec = GetLastError();
  253. if (ERROR_PATH_NOT_FOUND == ec || ERROR_FILE_NOT_FOUND == ec)
  254. {
  255. if (TRUE == QueryDialog(pcd, CFT_CONFLICT, CFO_DESTNOTEXIST, (LPARAM)pcd->szDestination))
  256. pcd->errorCode = ERROR_REQUEST_ABORTED;
  257. }
  258. else pcd->errorCode = ec;
  259. if (ERROR_SUCCESS != pcd->errorCode)
  260. {
  261. pcd->errorMsgId = IDS_COPY_ERRMSG_DIRECTORYCREATE_FAILED;
  262. return FALSE;
  263. }
  264. }
  265. if (!CopyFiles_CreateDirectory(pcd->szDestination))
  266. {
  267. pcd->errorMsgId = IDS_COPY_ERRMSG_DIRECTORYCREATE_FAILED;
  268. pcd->errorCode = ERROR_CANNOT_MAKE;
  269. return FALSE;
  270. }
  271. return TRUE;
  272. }
  273. static BOOL CopyFiles_FixCdAttributes(LPCTSTR pszFileName)
  274. {
  275. DWORD attr = GetFileAttributes(pszFileName);
  276. if (INVALID_FILE_ATTRIBUTES == attr) return FALSE;
  277. return SetFileAttributes(pszFileName, (attr & ~FILE_ATTRIBUTE_READONLY) | FILE_ATTRIBUTE_ARCHIVE);
  278. }
  279. static BOOL CopyFiles_DeleteFile(LPCTSTR pszFileName, COPYDATA *pcd)
  280. {
  281. DWORD attr = GetFileAttributes(pszFileName);
  282. if (INVALID_FILE_ATTRIBUTES == attr) return FALSE;
  283. if (FILE_ATTRIBUTE_READONLY & attr)
  284. {
  285. BOOL bReset = FALSE;
  286. if (FCF_DELETEREADONLY & pcd->uFlags) bReset = TRUE;
  287. else
  288. {
  289. INT_PTR r = QueryDialog(pcd, CFT_CONFLICT, CFO_READONLY, (LPARAM)pszFileName);
  290. switch(r)
  291. {
  292. case READONLY_CANCELCOPY:
  293. pcd->errorMsgId = IDS_COPY_ERRMSG_COPYFILE_USERABORT;
  294. SetLastError(ERROR_REQUEST_ABORTED);
  295. return FALSE;
  296. case READONLY_DELETEALL: pcd->uFlags |= FCF_DELETEREADONLY; // no break
  297. case READONLY_DELETE: bReset = TRUE; break;
  298. }
  299. }
  300. if (bReset)
  301. {
  302. if (!SetFileAttributes(pszFileName, (attr & ~FILE_ATTRIBUTE_READONLY)))
  303. return FALSE;
  304. }
  305. }
  306. return DeleteFile(pszFileName);
  307. }
  308. #define NOT_EXIST 0
  309. #define EXIST_AND_SKIP 1
  310. #define EXIST_AND_OVERWRITE 2
  311. #define EXIST_AND_CANCEL 3
  312. static DWORD CopyFiles_CheckIfExist(LPCTSTR pszFileNameDest, LPCTSTR pszFileNameSource, COPYDATA *pcd)
  313. {
  314. if (INVALID_FILE_ATTRIBUTES == GetFileAttributes(pszFileNameDest))
  315. {
  316. return NOT_EXIST;
  317. }
  318. if (FCF_SKIPFILE & pcd->uFlags) return EXIST_AND_SKIP;
  319. if (FCF_OVERWRITEFILE & pcd->uFlags) return EXIST_AND_OVERWRITE;
  320. FILECONFLICT conflict;
  321. ZeroMemory(&conflict, sizeof(FILECONFLICT));
  322. pcd->uFlags &= ~(FCF_SKIPFILE | FCF_OVERWRITEFILE);
  323. conflict.pszNameExisting = pszFileNameDest;
  324. conflict.pszNameNew = pszFileNameSource;
  325. INT_PTR r = QueryDialog(pcd, CFT_CONFLICT, CFO_FILEALREDYEXIST, (LPARAM)&conflict);
  326. switch(0xFF & r)
  327. {
  328. case EXISTFILE_CANCELCOPY: return EXIST_AND_CANCEL;
  329. case EXISTFILE_SKIP:
  330. if (EXISTFILE_APPLY_TO_ALL & r) pcd->uFlags |= FCF_SKIPFILE;
  331. return EXIST_AND_SKIP;
  332. case EXISTFILE_OVERWRITE:
  333. if (EXISTFILE_APPLY_TO_ALL & r) pcd->uFlags |= FCF_OVERWRITEFILE;
  334. return EXIST_AND_OVERWRITE;
  335. }
  336. return NOT_EXIST;
  337. }
  338. typedef struct _COPYPROGRESS
  339. {
  340. ULONGLONG total;
  341. ULONGLONG completed;
  342. HWND hDialog;
  343. INT percent;
  344. } COPYPROGRESS;
  345. static DWORD CALLBACK CopyFiles_ProgressRoutine(LARGE_INTEGER TotalFileSize, LARGE_INTEGER TotalBytesTransferred, LARGE_INTEGER StreamSize,
  346. LARGE_INTEGER StreamBytesTransferred, DWORD dwStreamNumber, DWORD dwCallbackReason,
  347. HANDLE hSourceFile, HANDLE hDestinationFile, LPVOID lpData)
  348. {
  349. COPYPROGRESS *pProgress = (COPYPROGRESS*)lpData;
  350. if (pProgress)
  351. {
  352. switch(dwCallbackReason)
  353. {
  354. case CALLBACK_STREAM_SWITCH:
  355. pProgress->completed += TotalFileSize.QuadPart;
  356. break;
  357. }
  358. INT p = (INT)((pProgress->completed - TotalFileSize.QuadPart + TotalBytesTransferred.QuadPart) * 100 / pProgress->total);
  359. if (p != pProgress->percent)
  360. {
  361. pProgress->percent = p;
  362. if (pProgress->hDialog)
  363. PostMessage(pProgress->hDialog, CFM_NOTIFY, MAKEWPARAM(CFT_COPYING, CFO_PROGRESS), p);
  364. }
  365. }
  366. return PROGRESS_CONTINUE;
  367. };
  368. static DWORD WINAPI CopyFiles_ThreadProc(LPVOID param)
  369. {
  370. COPYDATA *pcd = (COPYDATA*)param;
  371. if (!pcd) return 1;
  372. CopyFiles_MarkDrivesBusy((LPCTSTR*)pcd->ppszFiles, pcd->count, TRUE);
  373. ULONGLONG needSize;
  374. NotifyDialog(pcd, CFT_INITIALIZING, CFO_INIT, 0L);
  375. NotifyDialog(pcd, CFT_INITIALIZING, CFO_CACLSIZE, 0L);
  376. needSize = CopyFiles_CalculateTotalSize(pcd);
  377. BOOL bSuccess = (ERROR_SUCCESS == pcd->errorCode);
  378. if (bSuccess)
  379. {
  380. NotifyDialog(pcd, CFT_INITIALIZING, CFO_CHECKDESTINATION, 0L);
  381. bSuccess = CopyFiles_CheckDestination(pcd, needSize);
  382. }
  383. if (!bSuccess)
  384. {
  385. if (0 == pcd->errorMsgId)
  386. pcd->errorMsgId = IDS_COPY_ERRMSG_INITIALIZATION_FAILED;
  387. NotifyDialog(pcd, CFT_FINISHED, CFO_FAILED, pcd->errorCode);
  388. CopyFiles_MarkDrivesBusy((LPCTSTR*)pcd->ppszFiles, pcd->count, FALSE);
  389. CopyFiles_Release(pcd);
  390. return 0;
  391. }
  392. COPYPROGRESS progress;
  393. ZeroMemory(&progress, sizeof(COPYPROGRESS));
  394. progress.total = needSize;
  395. progress.hDialog = pcd->hDialog;
  396. NotifyDialog(pcd, CFT_COPYING, CFO_INIT, 0L);
  397. TCHAR szFile[MAX_PATH] = {0};
  398. for (int i = 0; i < pcd->count && ERROR_SUCCESS == pcd->errorCode; i++)
  399. {
  400. if (pcd->bCancel)
  401. {
  402. pcd->errorMsgId = IDS_COPY_ERRMSG_COPYFILE_USERABORT;
  403. pcd->errorCode = ERROR_REQUEST_ABORTED;
  404. }
  405. LPCTSTR pszOrigFileName = PathFindFileName(pcd->ppszFiles[i]);
  406. NotifyDialog(pcd, CFT_COPYING, CFO_NEXTFILE, MAKELPARAM(i, pcd->count));
  407. if (NULL == PathCombine(szFile, pcd->szDestination, pszOrigFileName))
  408. {
  409. pcd->errorMsgId = IDS_COPY_ERRMSG_COPYFILE_FAILED;
  410. pcd->errorCode = ERROR_BAD_PATHNAME;
  411. }
  412. DWORD r = CopyFiles_CheckIfExist(szFile, pcd->ppszFiles[i], pcd);
  413. switch(r)
  414. {
  415. case EXIST_AND_SKIP:
  416. continue;
  417. break;
  418. case EXIST_AND_OVERWRITE:
  419. if (!CopyFiles_DeleteFile(szFile, pcd))
  420. {
  421. pcd->errorMsgId = IDS_COPY_ERRMSG_DELETEFILE_FAILED;
  422. pcd->errorCode = GetLastError();
  423. }
  424. break;
  425. case EXIST_AND_CANCEL:
  426. pcd->errorMsgId = IDS_COPY_ERRMSG_COPYFILE_USERABORT;
  427. pcd->errorCode = ERROR_REQUEST_ABORTED;
  428. break;
  429. }
  430. // copy
  431. if (ERROR_SUCCESS == pcd->errorCode && !CopyFileEx(pcd->ppszFiles[i], szFile, CopyFiles_ProgressRoutine, &progress, &pcd->bCancel, 0))
  432. {
  433. pcd->errorMsgId = IDS_COPY_ERRMSG_COPYFILE_FAILED;
  434. pcd->errorCode = GetLastError();
  435. }
  436. if (pcd->bCancel)
  437. {
  438. pcd->errorMsgId = IDS_COPY_ERRMSG_COPYFILE_USERABORT;
  439. pcd->errorCode = ERROR_REQUEST_ABORTED;
  440. }
  441. if (ERROR_SUCCESS == pcd->errorCode) // post copy
  442. {
  443. // fix attributes
  444. if (ERROR_SUCCESS == pcd->errorCode && !CopyFiles_FixCdAttributes(szFile))
  445. {
  446. pcd->errorMsgId = IDS_COPY_ERRMSG_SETATTRIBUTES_FAILED;
  447. pcd->errorCode = GetLastError();
  448. }
  449. // format title & rename
  450. if (ERROR_SUCCESS == pcd->errorCode && (FCF_USETITLEFMT & pcd->uFlags) && pcd->pMetaReader)
  451. {
  452. TCHAR szBuffer[MAX_PATH] = {0};
  453. if (!CopyFiles_FormatFileName(szBuffer, ARRAYSIZE(szBuffer), szFile, pszOrigFileName,
  454. pcd->szDestination, pcd->szTitleFormat, pcd->pMetaReader))
  455. {
  456. pcd->errorMsgId = IDS_COPY_ERRMSG_TITLEFORMAT_FAILED;
  457. pcd->errorCode = GetLastError();
  458. }
  459. if (pcd->bCancel)
  460. {
  461. pcd->errorMsgId = IDS_COPY_ERRMSG_COPYFILE_USERABORT;
  462. pcd->errorCode = ERROR_REQUEST_ABORTED;
  463. }
  464. if (ERROR_SUCCESS == pcd->errorCode &&
  465. CSTR_EQUAL != CompareString(STRCOMP_INVARIANT, 0, szBuffer, -1, szFile, -1))
  466. {
  467. DWORD r = CopyFiles_CheckIfExist(szBuffer, szFile, pcd);
  468. switch(r)
  469. {
  470. case EXIST_AND_SKIP:
  471. CopyFiles_DeleteFile(szFile, pcd);
  472. continue;
  473. break;
  474. case EXIST_AND_OVERWRITE:
  475. if (!CopyFiles_DeleteFile(szBuffer, pcd))
  476. {
  477. pcd->errorMsgId = IDS_COPY_ERRMSG_DELETEFILE_FAILED;
  478. pcd->errorCode = GetLastError();
  479. }
  480. break;
  481. case EXIST_AND_CANCEL:
  482. pcd->errorMsgId = IDS_COPY_ERRMSG_COPYFILE_USERABORT;
  483. pcd->errorCode = ERROR_REQUEST_ABORTED;
  484. break;
  485. }
  486. if (ERROR_SUCCESS == pcd->errorCode)
  487. {
  488. if (!MoveFileEx(szFile, szBuffer, MOVEFILE_WRITE_THROUGH | MOVEFILE_COPY_ALLOWED))
  489. {
  490. pcd->errorMsgId = IDS_COPY_ERRMSG_TITLEFORMAT_FAILED;
  491. pcd->errorCode = GetLastError();
  492. }
  493. else StringCchCopy(szFile, ARRAYSIZE(szFile), szBuffer);
  494. }
  495. }
  496. }
  497. if (ERROR_SUCCESS != pcd->errorCode)
  498. {
  499. CopyFiles_DeleteFile(szFile, pcd);
  500. }
  501. else if ((FCF_ADDTOMLDB & pcd->uFlags) && pcd->pMlDb)
  502. {
  503. if (0 == pcd->pMlDb->AddFile(szFile))
  504. {
  505. pcd->errorMsgId = IDS_COPY_ERRMSG_ADDTOMLDB_FAILED;
  506. pcd->errorCode = ERROR_FILE_NOT_FOUND;
  507. }
  508. }
  509. }
  510. }
  511. NotifyDialog(pcd, CFT_FINISHED, (ERROR_SUCCESS == pcd->errorCode) ? CFO_SUCCESS : CFO_FAILED, pcd->errorCode);
  512. if ((FCF_ADDTOMLDB & pcd->uFlags) && pcd->pMlDb) pcd->pMlDb->Sync();
  513. CopyFiles_MarkDrivesBusy((LPCTSTR*)pcd->ppszFiles, pcd->count, FALSE);
  514. CopyFiles_Release(pcd);
  515. return 0;
  516. }
  517. BOOL CopyFiles_StartCopy(COPYDATA *pcd)
  518. {
  519. DWORD threadId;
  520. CopyFiles_AddRef(pcd);
  521. pcd->hThread = CreateThread(NULL, 0, CopyFiles_ThreadProc, pcd, 0, &threadId);
  522. if (pcd->hThread) return TRUE;
  523. pcd->errorCode = GetLastError();
  524. NotifyDialog(pcd, CFT_FINISHED, CFO_FAILED, pcd->errorCode);
  525. CopyFiles_Release(pcd);
  526. return FALSE;
  527. }