copyprogress.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  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 <shlwapi.h>
  8. #include <strsafe.h>
  9. typedef struct _PROGDLG
  10. {
  11. COPYDATA *pCopyData;
  12. HBITMAP hbmpLogo;
  13. } PROGDLG;
  14. #define PROGDLG_PROP TEXT("PROGDLG")
  15. #define GetProgDlg(__hdlg) ((PROGDLG*)GetProp((__hdlg), PROGDLG_PROP))
  16. #define SetControlText(__hwnd, __ctrlId, __pszText)\
  17. SetDlgItemText((__hwnd), (__ctrlId), (IS_INTRESOURCE(__pszText) ? WASABI_API_LNGSTRINGW((UINT)(UINT_PTR)(__pszText)) : (__pszText)))
  18. #define SetTaskText(__hwnd, __pszText) SetControlText(__hwnd, IDC_LBL_TASK, __pszText)
  19. #define SetOperationText(__hwnd, __pszText) SetControlText(__hwnd, IDC_LBL_OPERATION, __pszText)
  20. static INT_PTR CopyProgress_OnInitDialog(HWND hdlg, HWND hFocus, LPARAM lParam)
  21. {
  22. HWND hctrl;
  23. PROGDLG *ppd = (PROGDLG*)calloc(1, sizeof(PROGDLG));
  24. if (!ppd) return 0;
  25. SetProp(hdlg, PROGDLG_PROP, ppd);
  26. ppd->pCopyData = (COPYDATA*)lParam;
  27. CopyFiles_AddRef(ppd->pCopyData);
  28. if (ppd->pCopyData && ppd->pCopyData->hOwner)
  29. {
  30. RECT rw;
  31. if (!GetWindowRect(ppd->pCopyData->hOwner, &rw)) SetRect(&rw, 0, 0, 0, 0);
  32. if (hdlg && rw.left != rw.right)
  33. {
  34. RECT rw2;
  35. GetWindowRect(hdlg, &rw2);
  36. SetWindowPos(hdlg, HWND_TOP,
  37. rw.left + ((rw.right - rw.left) - (rw2.right - rw2.left))/2,
  38. rw.top + ((rw.bottom - rw.top) - (rw2.bottom - rw2.top))/2,
  39. 0, 0, SWP_NOACTIVATE | SWP_NOSIZE);
  40. }
  41. }
  42. hctrl = GetDlgItem(hdlg, IDC_PRG_TOTAL);
  43. if (NULL != hctrl)
  44. {
  45. SendMessage(hctrl, PBM_SETRANGE32, (WPARAM)0, (LPARAM)100);
  46. SendMessage(hctrl, PBM_SETPOS, (WPARAM)0, 0L);
  47. SendMessage(hctrl, PBM_SETSTEP, (WPARAM)1, 0L);
  48. }
  49. SetTaskText(hdlg, MAKEINTRESOURCE(IDS_COPY_TASK_PREPARE));
  50. SetOperationText(hdlg, TEXT(""));
  51. SendMessage(hdlg, DM_REPOSITION, 0, 0L);
  52. ppd->hbmpLogo = CopyFiles_LoadResourcePng(MAKEINTRESOURCE(IDB_FILECOPY));
  53. if (ppd->hbmpLogo) SendDlgItemMessage(hdlg, IDC_PIC_LOGO, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)ppd->hbmpLogo);
  54. else ShowWindow(GetDlgItem(hdlg, IDC_PIC_LOGO), SW_HIDE);
  55. return FALSE;
  56. }
  57. static void CopyProgress_OnDestroy(HWND hdlg)
  58. {
  59. PROGDLG *ppd = GetProgDlg(hdlg);
  60. RemoveProp(hdlg, PROGDLG_PROP);
  61. if (ppd)
  62. {
  63. if (ppd->pCopyData) CopyFiles_Release(ppd->pCopyData);
  64. if (ppd->hbmpLogo)
  65. {
  66. HBITMAP hbmp = (HBITMAP)SendDlgItemMessage(hdlg, IDC_PIC_LOGO, STM_GETIMAGE, IMAGE_BITMAP, 0L);
  67. if (hbmp != ppd->hbmpLogo) DeleteObject(hbmp);
  68. DeleteObject(ppd->hbmpLogo);
  69. }
  70. free(ppd);
  71. }
  72. }
  73. static void ShowErrorBox(HWND hdlg)
  74. {
  75. PROGDLG *ppd = GetProgDlg(hdlg);
  76. if (!ppd || !ppd->pCopyData) return;
  77. TCHAR szBuffer[2048] = {0}, szFormat[256] = {0}, szUnknown[64] = {0};
  78. LPTSTR pszMessage;
  79. if (ERROR_REQUEST_ABORTED == ppd->pCopyData->errorCode) return; // ignore user aborts
  80. FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL,
  81. ppd->pCopyData->errorCode, 0, (LPTSTR)&pszMessage, 0, NULL);
  82. WASABI_API_LNGSTRINGW_BUF(IDS_UNKNOWN, szUnknown, ARRAYSIZE(szUnknown));
  83. WASABI_API_LNGSTRINGW_BUF(IDS_COPY_ERROR_MESSAGE, szFormat, ARRAYSIZE(szFormat));
  84. StringCchPrintf(szBuffer, ARRAYSIZE(szBuffer), szFormat,
  85. ppd->pCopyData->szDestination,
  86. (ppd->pCopyData->errorMsgId) ? WASABI_API_LNGSTRINGW(ppd->pCopyData->errorMsgId) : szUnknown,
  87. ppd->pCopyData->errorCode,
  88. (pszMessage) ? pszMessage : szUnknown);
  89. MessageBox(hdlg, szBuffer, WASABI_API_LNGSTRINGW(IDS_COPY_ERROR_CAPTION), MB_OK | MB_ICONERROR);
  90. if (pszMessage) LocalFree(pszMessage);
  91. }
  92. static void CopyProgress_OnDisplayNextFile(HWND hdlg, INT iFile, INT iCount)
  93. {
  94. PROGDLG *ppd = GetProgDlg(hdlg);
  95. if (!ppd || !ppd->pCopyData) return;
  96. SetOperationText(hdlg, PathFindFileName(ppd->pCopyData->ppszFiles[iFile]));
  97. }
  98. static INT_PTR CopyProgress_OnDestiantionNotExist(HWND hdlg, LPCTSTR pszDestination)
  99. {
  100. PROGDLG *ppd = GetProgDlg(hdlg);
  101. if (!ppd || !ppd->pCopyData) return FALSE;
  102. QUESTIONBOX qb = {0};
  103. TCHAR szFormat[MAX_PATH] = {0}, szMessage[MAX_PATH*2] = {0};
  104. WASABI_API_LNGSTRINGW_BUF(IDS_DESTINATION_NOT_EXIST_FORMAT, szFormat, ARRAYSIZE(szFormat));
  105. StringCchPrintf(szMessage, ARRAYSIZE(szMessage), szFormat, pszDestination);
  106. qb.hParent =hdlg;
  107. qb.pszIcon = IDI_QUESTION;
  108. qb.pszTitle = MAKEINTRESOURCE(IDS_CONFIRM_CREATE_DESTINATION);
  109. qb.pszMessage = szMessage;
  110. qb.pszBtnOkText = MAKEINTRESOURCE(IDS_YES);
  111. qb.pszBtnCancelText = MAKEINTRESOURCE(IDS_NO);
  112. qb.uBeepType = MB_ICONEXCLAMATION;
  113. qb.uFlags = QBF_DEFAULT_OK | QBF_SETFOREGROUND | QBF_BEEP;
  114. return (IDCANCEL == MLDisc_ShowQuestionBox(&qb));
  115. }
  116. static INT_PTR CopyProgress_OnReadOnly(HWND hdlg, LPCTSTR pszFile)
  117. {
  118. PROGDLG *ppd = GetProgDlg(hdlg);
  119. if (!ppd || !ppd->pCopyData) return FALSE;
  120. QUESTIONBOX qb = {0};
  121. TCHAR szFormat[MAX_PATH] = {0}, szMessage[MAX_PATH*2] = {0};
  122. WASABI_API_LNGSTRINGW_BUF(IDS_READONLY_FILE_DELETE_FORMAT, szFormat, ARRAYSIZE(szFormat));
  123. StringCchPrintf(szMessage, ARRAYSIZE(szMessage), szFormat, pszFile);
  124. qb.hParent =hdlg;
  125. qb.pszIcon = IDI_QUESTION;
  126. qb.pszTitle = MAKEINTRESOURCE(IDS_CONFIRM_FILE_DELETE);
  127. qb.pszMessage = szMessage;
  128. qb.pszBtnOkText = MAKEINTRESOURCE(IDS_YES);
  129. qb.pszBtnCancelText = MAKEINTRESOURCE(IDS_CANCEL);
  130. qb.pszCheckboxText = MAKEINTRESOURCE(IDS_APPLY_TO_ALL_FILES);
  131. qb.uBeepType = MB_ICONEXCLAMATION;
  132. qb.uFlags = QBF_DEFAULT_OK | QBF_SETFOREGROUND | QBF_BEEP | QBF_SHOW_CHECKBOX;
  133. switch(MLDisc_ShowQuestionBox(&qb))
  134. {
  135. case IDCANCEL: return READONLY_CANCELCOPY;
  136. case IDOK: return (qb.checkboxChecked) ? READONLY_DELETEALL : READONLY_DELETE;
  137. }
  138. return FALSE;
  139. }
  140. static LPTSTR FormatFileInfo(LPTSTR pszBuffer, size_t cchBufferMax, LPCTSTR pszFilePath)
  141. {
  142. HANDLE hFile;
  143. HRESULT hr;
  144. BY_HANDLE_FILE_INFORMATION fi;
  145. pszBuffer[0] = TEXT('\0');
  146. hFile = CreateFile(pszFilePath, FILE_READ_ATTRIBUTES | FILE_READ_EA,
  147. FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
  148. NULL,OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, NULL);
  149. if (INVALID_HANDLE_VALUE != hFile &&
  150. GetFileInformationByHandle(hFile, &fi))
  151. {
  152. TCHAR szTemp[1024] = {0}, szKeyword[64] = {0};
  153. SYSTEMTIME st = {0};
  154. LONGLONG fsize = (LONGLONG)(((__int64)fi.nFileSizeHigh<< 32) | fi.nFileSizeLow);
  155. WASABI_API_LNGSTRINGW_BUF(IDS_SIZE, szKeyword, ARRAYSIZE(szKeyword));
  156. hr = StringCchPrintfEx(pszBuffer, cchBufferMax, &pszBuffer, &cchBufferMax, STRSAFE_IGNORE_NULLS, TEXT("\n %s: %s"), szKeyword, StrFormatByteSize64(fsize, szTemp, ARRAYSIZE(szTemp)));
  157. if (S_OK == hr && FileTimeToSystemTime(&fi.ftCreationTime, &st) &&
  158. GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, szTemp, ARRAYSIZE(szTemp)))
  159. {
  160. WASABI_API_LNGSTRINGW_BUF(IDS_CREATED, szKeyword, ARRAYSIZE(szKeyword));
  161. hr = StringCchPrintfEx(pszBuffer, cchBufferMax, &pszBuffer, &cchBufferMax, STRSAFE_IGNORE_NULLS, TEXT("\n %s: %s"), szKeyword, szTemp);
  162. if (S_OK == hr && GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, NULL, szTemp, ARRAYSIZE(szTemp)))
  163. hr = StringCchPrintfEx(pszBuffer, cchBufferMax, &pszBuffer, &cchBufferMax, STRSAFE_IGNORE_NULLS, TEXT(", %s"), szTemp);
  164. }
  165. if (S_OK == hr && FileTimeToSystemTime(&fi.ftLastWriteTime, &st) &&
  166. GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, szTemp, ARRAYSIZE(szTemp)))
  167. {
  168. WASABI_API_LNGSTRINGW_BUF(IDS_MODIFIED, szKeyword, ARRAYSIZE(szKeyword));
  169. hr = StringCchPrintfEx(pszBuffer, cchBufferMax, &pszBuffer, &cchBufferMax, STRSAFE_IGNORE_NULLS, TEXT("\n %s: %s"), szKeyword, szTemp);
  170. if (S_OK == hr && GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, NULL, szTemp, ARRAYSIZE(szTemp)))
  171. hr = StringCchPrintfEx(pszBuffer, cchBufferMax, &pszBuffer, &cchBufferMax, STRSAFE_IGNORE_NULLS, TEXT(", %s"), szTemp);
  172. }
  173. if (S_OK == hr)
  174. {
  175. hr = StringCchCopyEx(pszBuffer, cchBufferMax, TEXT("\n\n"), &pszBuffer, &cchBufferMax, STRSAFE_IGNORE_NULLS);
  176. }
  177. }
  178. else hr = S_FALSE;
  179. if (S_OK != hr) pszBuffer[0] = TEXT('\0');
  180. if (INVALID_HANDLE_VALUE != hFile) CloseHandle(hFile);
  181. return pszBuffer;
  182. }
  183. static INT_PTR CopyProgress_OnFileAlreadyExist(HWND hdlg, FILECONFLICT *pConflict)
  184. {
  185. PROGDLG *ppd = GetProgDlg(hdlg);
  186. if (!ppd || !ppd->pCopyData) return FALSE;
  187. QUESTIONBOX qb = {0};
  188. TCHAR szFormat[128] = {0}, szMessage[MAX_PATH*2] = {0}, szPath[MAX_PATH] = {0}, szFileInfo1[128] = {0}, szFileInfo2[128] = {0};
  189. WASABI_API_LNGSTRINGW_BUF(IDS_FILE_REPLACE_FORMAT, szFormat, ARRAYSIZE(szFormat));
  190. StringCchCopy(szPath, ARRAYSIZE(szPath), pConflict->pszNameExisting);
  191. LPTSTR pszFileName = PathFindFileName(szPath);
  192. if (pszFileName && pszFileName > szPath) *(pszFileName - 1) = TEXT('\0');
  193. FormatFileInfo(szFileInfo1, ARRAYSIZE(szFileInfo1), pConflict->pszNameExisting);
  194. FormatFileInfo(szFileInfo2, ARRAYSIZE(szFileInfo2), pConflict->pszNameNew);
  195. StringCchPrintf(szMessage, ARRAYSIZE(szMessage), szFormat, szPath, pszFileName, szFileInfo1, szFileInfo2);
  196. qb.hParent = hdlg;
  197. qb.pszIcon = IDI_QUESTION;
  198. qb.pszTitle = MAKEINTRESOURCE(IDS_CONFIRM_FILE_REPLACE);
  199. qb.pszMessage = szMessage;
  200. qb.pszBtnExtraText = MAKEINTRESOURCE(IDS_SKIP);
  201. qb.pszBtnOkText = MAKEINTRESOURCE(IDS_OVERWRITE);
  202. qb.pszBtnCancelText = MAKEINTRESOURCE(IDS_CANCEL);
  203. qb.pszCheckboxText = MAKEINTRESOURCE(IDS_APPLY_TO_ALL_FILES);
  204. qb.uBeepType = MB_ICONEXCLAMATION;
  205. qb.uFlags = QBF_DEFAULT_OK | QBF_SETFOREGROUND | QBF_BEEP | QBF_SHOW_CHECKBOX | QBF_SHOW_EXTRA_BUTTON;
  206. INT_PTR qbr = MLDisc_ShowQuestionBox(&qb);
  207. INT r = 0;
  208. switch(qbr)
  209. {
  210. case IDCANCEL: r = EXISTFILE_CANCELCOPY; break;
  211. case IDOK: r = EXISTFILE_OVERWRITE; break;
  212. case IDC_BTN_EXTRA1: r = EXISTFILE_SKIP; break;
  213. }
  214. if (qb.checkboxChecked) r |= EXISTFILE_APPLY_TO_ALL;
  215. return r;
  216. }
  217. static INT_PTR CopyProgress_OnCopyNotify(HWND hdlg, UINT uTask, UINT uOperation, LPARAM lParam)
  218. {
  219. switch(uTask)
  220. {
  221. case CFT_INITIALIZING:
  222. switch(uOperation)
  223. {
  224. case CFO_INIT:
  225. SetTaskText(hdlg, MAKEINTRESOURCE(IDS_COPY_TASK_PREPARE));
  226. SetOperationText(hdlg, TEXT(""));
  227. break;
  228. case CFO_CACLSIZE:
  229. SetOperationText(hdlg, MAKEINTRESOURCE(IDS_COPY_OP_CALCULATESIZE));
  230. break;
  231. case CFO_CHECKDESTINATION:
  232. SetOperationText(hdlg, MAKEINTRESOURCE(IDS_COPY_OP_CHECKDESTINATION));
  233. break;
  234. }
  235. break;
  236. case CFT_COPYING:
  237. switch(uOperation)
  238. {
  239. case CFO_INIT:
  240. SetTaskText(hdlg, MAKEINTRESOURCE(IDS_COPY_TASK_COPY));
  241. SetOperationText(hdlg, TEXT(""));
  242. break;
  243. case CFO_NEXTFILE:
  244. CopyProgress_OnDisplayNextFile(hdlg, LOWORD(lParam), HIWORD(lParam));
  245. break;
  246. case CFO_PROGRESS:
  247. SendDlgItemMessage(hdlg, IDC_PRG_TOTAL, PBM_SETPOS, (WPARAM)lParam, 0L);
  248. break;
  249. }
  250. break;
  251. case CFT_FINISHED:
  252. SetTaskText(hdlg, MAKEINTRESOURCE(IDS_COPY_TASK_FINISHED));
  253. switch(uOperation)
  254. {
  255. case CFO_SUCCESS: SetOperationText(hdlg, MAKEINTRESOURCE(IDS_COMPLETED)); break;
  256. case CFO_CANCELLED: SetOperationText(hdlg, MAKEINTRESOURCE(IDS_CANCELLED)); break;
  257. case CFO_FAILED:
  258. SetOperationText(hdlg, MAKEINTRESOURCE(IDS_FAILED));
  259. ShowErrorBox(hdlg);
  260. break;
  261. }
  262. DestroyWindow(hdlg);
  263. break;
  264. case CFT_CONFLICT:
  265. switch(uOperation)
  266. {
  267. case CFO_DESTNOTEXIST: return CopyProgress_OnDestiantionNotExist(hdlg, (LPCTSTR)lParam);
  268. case CFO_FILEALREDYEXIST: return CopyProgress_OnFileAlreadyExist(hdlg, (FILECONFLICT*)lParam);
  269. case CFO_READONLY: return CopyProgress_OnReadOnly(hdlg, (LPCTSTR)lParam);
  270. }
  271. break;
  272. }
  273. return FALSE;
  274. }
  275. INT_PTR CALLBACK CopyProgress_DialogProc(HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  276. {
  277. PROGDLG *ppd = GetProgDlg(hdlg);
  278. switch(uMsg)
  279. {
  280. case WM_INITDIALOG: return CopyProgress_OnInitDialog(hdlg, (HWND)wParam, lParam);
  281. case WM_DESTROY: CopyProgress_OnDestroy(hdlg); break;
  282. case WM_COMMAND:
  283. switch(LOWORD(wParam))
  284. {
  285. case IDOK:
  286. case IDCANCEL:
  287. if (ppd && ppd->pCopyData)
  288. {
  289. SetOperationText(hdlg, MAKEINTRESOURCE(IDS_CANCELLING));
  290. SendDlgItemMessage(hdlg, IDCANCEL, BM_SETSTATE, (WPARAM)TRUE, 0L);
  291. EnableWindow(GetDlgItem(hdlg, IDCANCEL), FALSE);
  292. CopyFiles_CancelCopy(ppd->pCopyData);
  293. }
  294. else DestroyWindow(hdlg);
  295. break;
  296. }
  297. case CFM_NOTIFY: MSGRESULT(hdlg, CopyProgress_OnCopyNotify(hdlg, LOWORD(wParam), HIWORD(wParam), lParam));
  298. }
  299. return 0;
  300. }