C# 从CopyFileEx处理Marshall错误

C# 从CopyFileEx处理Marshall错误,c#,exception,task,marshalling,C#,Exception,Task,Marshalling,对于备份我们的用户数据大约10000个用户,我计划使用此包装器,但由于它在丢失用户数据方面有点危险,我真的需要捕获所有复制错误(文件存在、自动生成等…) 这是包装纸 using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.T

对于备份我们的用户数据大约10000个用户,我计划使用此包装器,但由于它在丢失用户数据方面有点危险,我真的需要捕获所有复制错误(文件存在、自动生成等…)

这是包装纸

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace PROBTP_BACKUP2.Model
{

    public static class FileEx
    {
        public static Task CopyAsync(string sourceFileName, string destFileName)
        {
            return CopyAsync(sourceFileName, destFileName, CancellationToken.None);
        }

        public static Task CopyAsync(string sourceFileName, string destFileName, CancellationToken token)
        {
            return CopyAsync(sourceFileName, destFileName, token, null);
        }

        public static Task CopyAsync(string sourceFileName, string destFileName, IProgress<double> progress)
        {

            return CopyAsync(sourceFileName, destFileName, CancellationToken.None, progress);

        }

        public static Task CopyAsync(string sourceFileName, string destFileName, CancellationToken token, IProgress<double> progress)
        {
            int pbCancel = 0;
            CopyProgressRoutine copyProgressHandler;
            bool bSuccess = true;
            if (progress != null)
            {
                copyProgressHandler = (total, transferred, streamSize, streamByteTrans, dwStreamNumber, reason, hSourceFile, hDestinationFile, lpData) =>
                {
                    progress.Report((double)transferred / total * 100);
                  Console.WriteLine((double)transferred );
                    return CopyProgressResult.PROGRESS_CONTINUE;
                };
            }
            else
            {
                copyProgressHandler = EmptyCopyProgressHandler;
            }
            token.ThrowIfCancellationRequested();
            var ctr = token.Register(() => pbCancel = 1);
            var copyTask = Task.Run(() =>
            {
                try
                {
                 bSuccess = CopyFileEx(sourceFileName, destFileName, copyProgressHandler, IntPtr.Zero, ref pbCancel, CopyFileFlags.COPY_FILE_FAIL_IF_EXISTS);
                 token.ThrowIfCancellationRequested();


                }

                finally
                {

                    ctr.Dispose();

                }
                if (!bSuccess)
                {
                    Console.WriteLine(bSuccess);
                    string errorMessage = new Win32Exception(Marshal.GetLastWin32Error()).Message;
                    Console.WriteLine(errorMessage);

                }
            }, token);

            return copyTask;
        }

        private static CopyProgressResult EmptyCopyProgressHandler(long total, long transferred, long streamSize, long streamByteTrans, uint dwStreamNumber, CopyProgressCallbackReason reason, IntPtr hSourceFile, IntPtr hDestinationFile, IntPtr lpData)
        {
            return CopyProgressResult.PROGRESS_CONTINUE;
        }

        #region DLL Import

        [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool CopyFileEx(string lpExistingFileName, string lpNewFileName,
           CopyProgressRoutine lpProgressRoutine, IntPtr lpData, ref Int32 pbCancel,
           CopyFileFlags dwCopyFlags);

        delegate CopyProgressResult CopyProgressRoutine(
            long totalFileSize,
            long totalBytesTransferred,
            long streamSize,
            long streamBytesTransferred,
            uint dwStreamNumber,
            CopyProgressCallbackReason dwCallbackReason,
            IntPtr hSourceFile,
            IntPtr hDestinationFile,
            IntPtr lpData);

        enum CopyProgressResult : uint
        {
            PROGRESS_CONTINUE = 0,
            PROGRESS_CANCEL = 1,
            PROGRESS_STOP = 2,
            PROGRESS_QUIET = 3
        }

        enum CopyProgressCallbackReason : uint
        {
            CALLBACK_CHUNK_FINISHED = 0x00000000,
            CALLBACK_STREAM_SWITCH = 0x00000001
        }

        [Flags]
        enum CopyFileFlags : uint
        {
            COPY_FILE_FAIL_IF_EXISTS = 0x00000001,
            COPY_FILE_RESTARTABLE = 0x00000002,
            COPY_FILE_OPEN_SOURCE_FOR_WRITE = 0x00000004,
            COPY_FILE_ALLOW_DECRYPTED_DESTINATION = 0x00000008
        }

        #endregion
    }
}
使用系统;
使用System.Collections.Generic;
使用系统组件模型;
使用System.Linq;
使用System.Runtime.InteropServices;
使用系统文本;
使用系统线程;
使用System.Threading.Tasks;
命名空间PROBTP_BACKUP2.Model
{
公共静态类FileEx
{
公共静态任务CopySync(字符串sourceFileName、字符串destFileName)
{
返回CopySync(sourceFileName、destFileName、CancellationToken.None);
}
公共静态任务CopySync(string sourceFileName、string destFileName、CancellationToken令牌)
{
返回CopySync(sourceFileName、destFileName、token、null);
}
公共静态任务CopySync(字符串sourceFileName、字符串destFileName、IProgress progress)
{
返回CopySync(sourceFileName、destFileName、CancellationToken.None、progress);
}
公共静态任务CopySync(字符串sourceFileName、字符串destFileName、CancellationToken令牌、IProgress进度)
{
int-pbCancel=0;
copyProgressHandler例程;
bool bSuccess=true;
如果(进度!=null)
{
copyProgressHandler=(总计、已传输、streamSize、StreamByTerans、dwStreamNumber、原因、hSourceFile、hDestinationFile、lpData)=>
{
进度报告((双倍)转账/合计*100);
控制台写入线((双)传输);
返回CopyProgressResult.PROGRESS\u CONTINUE;
};
}
其他的
{
copyProgressHandler=EmptyCopyProgressHandler;
}
token.ThrowIfCancellationRequested();
var ctr=token.Register(()=>pbCancel=1);
var copyTask=Task.Run(()=>
{
尝试
{
bSuccess=CopyFileEx(sourceFileName、destFileName、copyProgressHandler、IntPtr.Zero、ref-pbCancel、CopyFileFlags.COPY\u FILE\u FAIL\u如果存在);
token.ThrowIfCancellationRequested();
}
最后
{
ctr.Dispose();
}
如果(!b成功)
{
控制台写入线(bSuccess);
string errorMessage=新的Win32Exception(Marshal.GetLastWin32Error()).Message;
控制台写入线(错误消息);
}
},代币);
返回复制任务;
}
私有静态CopyProgressResult EmptyCopyProgressHandler(长总计、长传输、长流大小、长流字节数、uint dwStreamNumber、CopyProgressCallbackReason、IntPtr hSourceFile、IntPtr hDestinationFile、IntPtr lpData)
{
返回CopyProgressResult.PROGRESS\u CONTINUE;
}
#区域DLL导入
[DllImport(“kernel32.dll”,SetLastError=true,CharSet=CharSet.Auto)]
[返回:Marshallas(UnmanagedType.Bool)]
私有静态外部bool CopyFileEx(字符串lpExistingFileName,字符串lpNewFileName,
CopyProgressRoutine lpProgressRoutine,IntPtr lpData,ref Int32 pbCancel,
CopyFileFlags(dwCopyFlags);
委托CopyProgressResult CopyProgress例程(
长文件大小,
long TotalByTestTransferr,
长径,
长流被转移,
uint数据流编号,
CopyProgressCallbackReason dwCallbackReason,
IntPtr hSourceFile,
IntPtr hDestinationFile,
IntPtr lpData);
枚举CopyProgressResult:uint
{
继续的进度=0,
进度\取消=1,
进度停止=2,
进度=3
}
枚举CopyProgressCallback原因:uint
{
回调\u CHUNK\u FINISHED=0x00000000,
回调\流\开关=0x00000001
}
[旗帜]
枚举CopyFileFlags:uint
{
复制\u文件\u失败\u如果\u存在=0x00000001,
复制\u文件\u可重新启动=0x00000002,
复制\u文件\u打开\u源\u以便写入=0x00000004,
复制\u文件\u允许\u解密\u目的地=0x00000008
}
#端区
}
}
这里是点击按钮的启动器

public async void StartProcessing(string test)
        {
            var progressIndicator = new Progress<double>(ReportProgress =>
            {
                fileName = ReportProgress.ToString();
                totalPercent = (int)ReportProgress;
            });
            CancellationToken cts = new CancellationToken();
            await Task.Run(() => FileEx.CopyAsync(@"input.rar","C:\cop\output.rar", progressIndicator));

        }
public异步void启动处理(字符串测试)
{
var progressIndicator=新进度(ReportProgress=>
{
fileName=ReportProgress.ToString();
totalPercent=(int)报告进度;
});
CancellationToken cts=新的CancellationToken();
等待任务。运行(()=>FileEx.copyanc(@“input.rar”,“C:\cop\output.rar”,progressIndicator));
}
假设我在这里点击3次输出(文件aalready出于测试目的而存在)

-假的 -描述无效 -假的 -费希尔酒店 -假的 -费希尔酒店

这是我翻译的 -无效描述符 -文件存在 -文件存在

你明白了,我不知道为什么一开始我会得到一个“无效描述符” 第二次,我不确定我是否会以这种方式捕捉到任何错误

因此,如果有人能帮助添加一个严重的错误处理代码,我很高兴

ps:我知道有人会问,为什么我不使用copyTo或robocopy等。。
这是因为我们需要进步,否则用户会认为应用程序已经崩溃而在loooong文件拷贝上终止进程。(如果我对wrapper i plan copyTo()不满意,那就很难了。

我不知道从封送函数中捕获错误的其他方法(除了lastWin32Error),但您始终可以从将要复制的文件中计算哈希值,然后进行检查