CopyRoutines.pas 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388
  1. //******************************************************************************
  2. //*** COMMON DELPHI FUNCTIONS ***
  3. //*** ***
  4. //*** (c) Massimo Magnano 2004-2005 ***
  5. //*** ***
  6. //*** ***
  7. //******************************************************************************
  8. // File : CopyRoutines.pas
  9. //
  10. // Description : functions for copy e delete Dirs
  11. //
  12. //******************************************************************************
  13. unit CopyRoutines;
  14. interface
  15. uses Windows, SysUtils, Masks, Controls, FileVer, Dialogs;
  16. const
  17. faOnlyFile =$27;
  18. faAnyDir =$1F;
  19. EXISTING_DONTCOPY =0;
  20. EXISTING_IF_VER_GREATER =1; //Copy if New File have greater version
  21. EXISTING_IF_ASK =2;
  22. EXISTING_OVERWRITE =3;
  23. type
  24. TCopyPathProgressRoutine =procedure (Data :Pointer;
  25. totalfiles,
  26. currentfile :Integer;
  27. FileName :String;
  28. TotalFileSize,
  29. TotalBytesTransferred :LARGE_INTEGER;
  30. var cancelled :Boolean
  31. );
  32. TCopyProgressRoutine = function (
  33. TotalFileSize, // total file size, in bytes
  34. TotalBytesTransferred, // total number of bytes transferred
  35. StreamSize, // total number of bytes for this stream
  36. StreamBytesTransferred : LARGE_INTEGER; // total number of bytes transferred for this stream
  37. dwStreamNumber, // the current stream
  38. dwCallbackReason :DWord; // reason for callback
  39. hSourceFile, // handle to the source file
  40. hDestinationFile :THandle; // handle to the destination file
  41. lpData :Pointer // passed by CopyFileEx
  42. ) :DWord; stdcall;
  43. procedure CopyPath(SourcePath, DestPath, wild :String;
  44. OnExistingFile :Integer; Recursive :Boolean =True;
  45. Data :Pointer=Nil; CopyProgressRoutine :TCopyPathProgressRoutine=Nil);
  46. procedure CopyFile(SourceFile, DestPath:String; OnExistingFile :Integer; DestFileName :String='';
  47. Data :Pointer=Nil; CopyProgressRoutine :TCopyPathProgressRoutine=Nil);
  48. procedure DeleteDir(BaseDir:String; SelName :String; Recursive, RemoveDirs :Boolean);
  49. function AdjustPath(Path :String) :String;
  50. implementation
  51. type
  52. TCopyPathData =record
  53. Data :Pointer;
  54. FileName :String;
  55. CopyProgressRoutine :TCopyPathProgressRoutine;
  56. totalfiles,
  57. currentfile :Integer;
  58. cancelled :Boolean;
  59. Check_Ask :TModalResult;
  60. end;
  61. function internalProgress(
  62. TotalFileSize, // total file size, in bytes
  63. TotalBytesTransferred, // total number of bytes transferred
  64. StreamSize, // total number of bytes for this stream
  65. StreamBytesTransferred : LARGE_INTEGER; // total number of bytes transferred for this stream
  66. dwStreamNumber, // the current stream
  67. dwCallbackReason :DWord; // reason for callback
  68. hSourceFile, // handle to the source file
  69. hDestinationFile :THandle; // handle to the destination file
  70. lpData :Pointer // passed by CopyFileEx
  71. ) :DWord; stdcall;
  72. var
  73. copyData :^TCopyPathData;
  74. begin
  75. Result :=PROGRESS_CONTINUE;
  76. copyData :=lpData;
  77. if (copyData=Nil)
  78. then Exit;
  79. if assigned(copyData^.CopyProgressRoutine) then
  80. begin
  81. copyData^.CopyProgressRoutine(copyData^.Data,
  82. copyData^.totalfiles,
  83. copyData^.currentfile,
  84. copyData^.FileName,
  85. TotalFileSize, TotalBytesTransferred,
  86. copyData^.cancelled);
  87. if (copyData^.cancelled)
  88. then Result :=PROGRESS_CANCEL;
  89. end;
  90. end;
  91. function CheckExisting(SourceFileName, DestFileName :String;
  92. OnExistingFile :Integer; var AskResult :TModalResult) :Boolean;
  93. Var
  94. SVer,
  95. DVer,
  96. SLang,
  97. DLang,
  98. SInfo,
  99. DInfo :String;
  100. FInfo :TSearchRec;
  101. function Ask(MsgSource, MsgDest :String) :TModalResult;
  102. begin
  103. Result :=MessageDlg('Overwrite EXISTING File :'+#13#10#13#10+
  104. DestFileName+#13#10+MsgDest+#13#10#13#10+
  105. 'With NEW File :'+#13#10#13#10+
  106. SourceFileName+#13#10+MsgSource+#13#10#13#10,
  107. mtConfirmation, mbYesAllNoAllCancel, 0);
  108. end;
  109. begin
  110. if FileExists(DestFileName)
  111. then begin
  112. Result :=True;
  113. Case OnExistingFile of
  114. EXISTING_DONTCOPY : Result :=False;
  115. EXISTING_IF_VER_GREATER : begin
  116. SVer :=GetFileVerLang(SourceFileName, SLang);
  117. DVer :=GetFileVerLang(DestFileName, DLang);
  118. Result := (CompareVer(SVer, DVer)>=0);
  119. end;
  120. EXISTING_IF_ASK : begin
  121. if AskResult=mrYesToAll
  122. then begin
  123. Result :=True;
  124. Exit;
  125. end
  126. else
  127. if AskResult=mrNoToAll
  128. then begin
  129. Result :=False;
  130. Exit;
  131. end;
  132. SVer :=GetFileVerLang(SourceFileName, SLang);
  133. DVer :=GetFileVerLang(DestFileName, DLang);
  134. FindFirst(SourceFilename, faAnyFile,
  135. FInfo);
  136. SInfo :=' Version '+SVer+' Lang '+SLang+#13#10+
  137. ' Date '+DateTimeToStr(FileDateToDateTime(FInfo.Time))+#13#10+
  138. ' Size '+IntToStr(FInfo.Size)+#13#10;
  139. FindClose(FInfo);
  140. FindFirst(DestFilename, faAnyFile,
  141. FInfo);
  142. DInfo :=' Version '+DVer+' Lang '+DLang+#13#10+
  143. ' Date '+DateTimeToStr(FileDateToDateTime(FInfo.Time))+#13#10+
  144. ' Size '+IntToStr(FInfo.Size)+#13#10;
  145. FindClose(FInfo);
  146. AskResult :=Ask(SInfo, DInfo);
  147. Result := (AskResult in [mrYes, mrYesToAll]);
  148. end;
  149. EXISTING_OVERWRITE : Result :=True;
  150. end;
  151. end
  152. else Result :=True;
  153. end;
  154. procedure CopyPath(SourcePath, DestPath, wild :String;
  155. OnExistingFile :Integer; Recursive :Boolean =True;
  156. Data :Pointer=Nil; CopyProgressRoutine :TCopyPathProgressRoutine=Nil);
  157. var
  158. xSourcePath,
  159. xDestPath :String;
  160. myData :TCopyPathData;
  161. int0 :LARGE_INTEGER;
  162. CanCopy :Boolean;
  163. procedure copyDir(rSource, rDest, wild :String);
  164. Var
  165. fileInfo :TSearchRec;
  166. Error :Integer;
  167. begin
  168. ForceDirectories(rDest);
  169. //find first non entra nelle sotto dir se non è *.*
  170. // non posso fare (*.*, faDirectory) perchè mi prende anche i file
  171. // Questa si che è un mostro di API...
  172. Error := FindFirst(rSource+'*.*', faAnyFile, FileInfo); //+wild
  173. While (Error=0) Do
  174. begin
  175. if (FileInfo.Name[1] <> '.') then //non è [.] o [..]
  176. begin
  177. if ((FileInfo.Attr and faDirectory) = faDirectory)
  178. then begin
  179. if Recursive
  180. then copyDir(rSource+FileInfo.Name+'\',
  181. rDest+FileInfo.Name+'\', wild);
  182. end
  183. else if MatchesMask(FileInfo.Name, wild) then
  184. begin
  185. myData.FileName :=rSource+FileInfo.Name;
  186. inc(myData.currentfile);
  187. CanCopy :=CheckExisting(myData.FileName, rDest+FileInfo.Name,
  188. OnExistingFile, myData.Check_Ask);
  189. myData.cancelled := myData.cancelled or
  190. (myData.Check_Ask = mrCancel);
  191. if CanCopy
  192. then CopyFileEx(PChar(myData.FileName),
  193. PChar(rDest+FileInfo.Name),
  194. @internalProgress, @myData, Nil,
  195. COPY_FILE_RESTARTABLE);
  196. end;
  197. end;
  198. Error :=FindNext(FileInfo);
  199. end;
  200. FindClose(FileInfo);
  201. end;
  202. procedure countDir(rSource, rDest, wild :String);
  203. Var
  204. fileInfo :TSearchRec;
  205. Error :Integer;
  206. begin
  207. Error := FindFirst(rSource+'*.*', faAnyFile, FileInfo);
  208. While (Error=0) Do
  209. begin
  210. if (FileInfo.Name[1] <> '.') then //non è [.] o [..]
  211. begin
  212. if ((FileInfo.Attr and faDirectory) = faDirectory)
  213. then begin
  214. if Recursive
  215. then countDir(rSource+FileInfo.Name+'\',
  216. rDest+FileInfo.Name+'\', wild);
  217. end
  218. else if MatchesMask(FileInfo.Name, wild)
  219. then inc(myData.totalfiles);
  220. end;
  221. Error :=FindNext(FileInfo);
  222. end;
  223. FindClose(FileInfo);
  224. end;
  225. begin
  226. xSourcePath :=AdjustPath(SourcePath);
  227. xDestPath :=AdjustPath(DestPath);
  228. myData.totalfiles :=0;
  229. myData.currentfile :=0;
  230. myData.cancelled :=False;
  231. myData.Data :=Data;
  232. myData.CopyProgressRoutine :=CopyProgressRoutine;
  233. myData.Check_Ask :=mrNone;
  234. if assigned(CopyProgressRoutine) then
  235. begin
  236. int0.QuadPart :=0;
  237. CopyProgressRoutine(Data, 0, 0,
  238. 'Preparing for Copy...', int0, int0, myData.Cancelled);
  239. countDir(xSourcePath, xDestPath, wild);
  240. CopyProgressRoutine(Data, myData.totalfiles, 0,
  241. 'Starting Copy...', int0, int0, myData.Cancelled);
  242. end;
  243. copyDir(xSourcePath, xDestPath, wild);
  244. if assigned(CopyProgressRoutine)
  245. then CopyProgressRoutine(Data, myData.totalfiles, 0,
  246. 'Copy completed...', int0, int0, myData.Cancelled);
  247. end;
  248. procedure CopyFile(SourceFile, DestPath :String; OnExistingFile :Integer; DestFileName :String='';
  249. Data :Pointer=Nil; CopyProgressRoutine :TCopyPathProgressRoutine=Nil);
  250. var
  251. xDestPath,
  252. xDestFileName :String;
  253. myData :TCopyPathData;
  254. int0 :LARGE_INTEGER;
  255. begin
  256. xDestPath :=AdjustPath(DestPath);
  257. if (DestFileName='')
  258. then xDestFileName :=ExtractFilename(SourceFile)
  259. else xDestFileName :=ExtractFilename(DestFileName);
  260. myData.totalfiles :=1;
  261. myData.currentfile :=0;
  262. myData.cancelled :=False;
  263. myData.Data :=Data;
  264. myData.CopyProgressRoutine :=CopyProgressRoutine;
  265. myData.Check_Ask :=mrNone;
  266. if assigned(CopyProgressRoutine) then
  267. begin
  268. int0.QuadPart :=0;
  269. CopyProgressRoutine(Data, myData.totalfiles, 0,
  270. 'Starting Copy...', int0, int0, myData.Cancelled);
  271. end;
  272. myData.FileName :=SourceFile;
  273. myData.currentfile :=1;
  274. if ForceDirectories(xDestPath)
  275. then begin
  276. if (CheckExisting(SourceFile, xDestPath+xDestFileName, OnExistingFile,
  277. myData.Check_Ask))
  278. then CopyFileEx(PChar(SourceFile),
  279. PChar(xDestPath+xDestFileName),
  280. @internalProgress, @myData, Nil,
  281. COPY_FILE_RESTARTABLE);
  282. if assigned(CopyProgressRoutine)
  283. then CopyProgressRoutine(Data, myData.totalfiles, 0,
  284. 'Copy completed...', int0, int0, myData.Cancelled);
  285. end
  286. else raise Exception.Create('Cannot copy Files on '+xDestPath);
  287. end;
  288. procedure DeleteDir(BaseDir:String; SelName :String; Recursive, RemoveDirs :Boolean);
  289. procedure _DeleteDir(BaseDir:String; SelName :String; Recursive, RemoveDirs :Boolean);
  290. Var
  291. SFile,
  292. SDir :TSearchRec;
  293. Error :Integer;
  294. begin
  295. //Display('Deleting Dir '+BaseDir+'\'+SelName);
  296. if (BaseDir[Length(BaseDir)]<>'\')
  297. then BaseDir := BaseDir + '\';
  298. Error :=FindFirst(BaseDir+Selname, faOnlyFile, Sfile);
  299. While (Error=0) Do
  300. begin
  301. if (SFile.Name[1]<>'.') and
  302. not(Sfile.Attr in[faDirectory..faAnyDir])
  303. then DeleteFile(BaseDir+SFile.Name);
  304. Error :=FindNext(SFile);
  305. end;
  306. FindClose(SFile);
  307. if Recursive then
  308. begin
  309. Error :=FindFirst(BaseDir+'*.*', faAnyDir, SDir);
  310. While (Error=0) Do
  311. begin
  312. if (SDir.Name[1]<>'.') and
  313. (SDir.Attr in[faDirectory..faAnyDir])
  314. then begin
  315. DeleteDir(BaseDir+Sdir.Name, SelName, Recursive, RemoveDirs);
  316. if RemoveDirs
  317. then RemoveDirectory(PChar(BaseDir+Sdir.Name));
  318. end;
  319. Error :=FindNext(SDir);
  320. end;
  321. FindClose(SDir);
  322. end;
  323. end;
  324. begin
  325. _DeleteDir(BaseDir, SelName, Recursive, RemoveDirs);
  326. if RemoveDirs
  327. then RemoveDirectory(PChar(BaseDir));
  328. end;
  329. function AdjustPath(Path :String) :String;
  330. begin
  331. if Path[Length(Path)]<>'\'
  332. then Result :=Path+'\'
  333. else Result :=Path;
  334. end;
  335. end.