Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CopyFileEx wrapper parameters

Tags:

c#

pinvoke

I have recently had to change from using File.Copy() to CopyFileEx and I am struggling to find how to use it.

After a lot of googling I found this nice wrapper to use it, but what I need is to get the progress of the copied bytes of the current file, and if possible calculate the progress of copying all files I pass to it.

(I know there are projects that have progress bars linked to CopyFileEx but I'm not experienced enough to pull out the relevant code, and I would like to use this wrapper).

Presumably just by comparing it to the total bytes of the files to be copied, which I would find beforehand, and working out the percentage from that.

My current method of copying is

FileRoutines.CopyFile(new FileInfo("source.txt"), new FileInfo("dest.txt"));

What I am stuck on is how to overload it with the parameter's needed to get the progress info.

public sealed class FileRoutines
{
    public static void CopyFile(FileInfo source, FileInfo destination)
    {
        CopyFile(source, destination, CopyFileOptions.None);
    }

    public static void CopyFile(FileInfo source, FileInfo destination, 
        CopyFileOptions options)
    {
        CopyFile(source, destination, options, null);
    }

    public static void CopyFile(FileInfo source, FileInfo destination, 
        CopyFileOptions options, CopyFileCallback callback)
    {
        CopyFile(source, destination, options, callback, null);
    }

    public static void CopyFile(FileInfo source, FileInfo destination, 
        CopyFileOptions options, CopyFileCallback callback, object state)
    {
        if (source == null) throw new ArgumentNullException("source");
        if (destination == null) 
            throw new ArgumentNullException("destination");
        if ((options & ~CopyFileOptions.All) != 0) 
            throw new ArgumentOutOfRangeException("options");

        new FileIOPermission(
            FileIOPermissionAccess.Read, source.FullName).Demand();
        new FileIOPermission(
            FileIOPermissionAccess.Write, destination.FullName).Demand();

        CopyProgressRoutine cpr = callback == null ? 
            null : new CopyProgressRoutine(new CopyProgressData(
                source, destination, callback, state).CallbackHandler);

        bool cancel = false;
        if (!CopyFileEx(source.FullName, destination.FullName, cpr, 
            IntPtr.Zero, ref cancel, (int)options))
        {
            throw new IOException(new Win32Exception().Message);
        }
    }

    private class CopyProgressData
    {
        private FileInfo _source = null;
        private FileInfo _destination = null;
        private CopyFileCallback _callback = null;
        private object _state = null;

        public CopyProgressData(FileInfo source, FileInfo destination, 
            CopyFileCallback callback, object state)
        {
            _source = source; 
            _destination = destination;
            _callback = callback;
            _state = state;
        }

        public int CallbackHandler(
            long totalFileSize, long totalBytesTransferred, 
            long streamSize, long streamBytesTransferred, 
            int streamNumber, int callbackReason,
            IntPtr sourceFile, IntPtr destinationFile, IntPtr data)
        {
            return (int)_callback(_source, _destination, _state, 
                totalFileSize, totalBytesTransferred);
        }
    }

    private delegate int CopyProgressRoutine(
        long totalFileSize, long TotalBytesTransferred, long streamSize, 
        long streamBytesTransferred, int streamNumber, int callbackReason,
        IntPtr sourceFile, IntPtr destinationFile, IntPtr data);

    [SuppressUnmanagedCodeSecurity]
    [DllImport("Kernel32.dll", CharSet=CharSet.Auto, SetLastError=true)]
    private static extern bool CopyFileEx(
        string lpExistingFileName, string lpNewFileName,
        CopyProgressRoutine lpProgressRoutine,
        IntPtr lpData, ref bool pbCancel, int dwCopyFlags);
}

public delegate CopyFileCallbackAction CopyFileCallback(
    FileInfo source, FileInfo destination, object state, 
    long totalFileSize, long totalBytesTransferred);

public enum CopyFileCallbackAction
{
    Continue = 0,
    Cancel = 1,
    Stop = 2,
    Quiet = 3
}

[Flags]
public enum CopyFileOptions
{
    None = 0x0,
    FailIfDestinationExists = 0x1,
    Restartable = 0x2,
    AllowDecryptedDestination = 0x8,
    All = FailIfDestinationExists | Restartable | AllowDecryptedDestination
}

Any pointers really appreciated.

like image 938
Bali C Avatar asked Dec 20 '12 16:12

Bali C


1 Answers

The wrapper already has the plumbing needed to handle the progress. Just implement the code to update your progress bar in CallbackHandler before the return. The progressBar1.Maximum defaults to 100, so the code below will calculate the percentage.

Replace your current CopyFile call with this:

CopyFileCallbackAction myCallback(FileInfo source, FileInfo destination, object state, long totalFileSize, long totalBytesTransferred)
{
    double dProgress = (totalBytesTransferred / (double)totalFileSize) * 100.0;
    progressBar1.Value = (int)dProgress;
    return CopyFileCallbackAction.Continue;
}

FileRoutines.CopyFile(new FileInfo("source.txt"), new FileInfo("dest.txt"), myCallback);
like image 104
Sean Kornish Avatar answered Sep 22 '22 09:09

Sean Kornish