【问题标题】:C# CopyFileEx - ProgressRoutine : do we really need to close the destination file handle while progress?C# CopyFileEx - ProgressRoutine:我们真的需要在进行过程中关闭目标文件句柄吗?
【发布时间】:2015-03-28 06:36:26
【问题描述】:

当传输的字节大小大于或等于文件总长度时,我尝试关闭ProgressRoutine 中的句柄。但是整个操作很少会抛出System.IO.IOException : The Handle is invalid.

bool result = CopyFileEx(source, destination, new CopyProgressRoutine(CopyProgressHandler), IntPtr.Zero, ref IsCancelled, copyFileFlags);
if (!result)
{
    //when ever we get the result as false it means some error occured so get the last win 32 error.
    throw new Win32Exception(Marshal.GetLastWin32Error());
}

这里是CopyProgressHandler 方法

private CopyProgressResult CopyProgressHandler(long total, long transferred, long streamSize, long streamByteTrans, uint dwStreamNumber,
                                                CopyProgressCallbackReason reason, IntPtr hSourceFile, IntPtr hDestinationFile, IntPtr lpData)
{
    //when a chunk is finished call the progress changed.
    if (reason == CopyProgressCallbackReason.CALLBACK_CHUNK_FINISHED)
    {
        OnProgressChanged((transferred / (double)total) * 100.0);
    }

    //transfer completed
    if (transferred >= total)
    {
        if (CloseHandle(hDestinationFile)) // here is that valid!! ?
        {
            //if file is read only, remove read-only attribute(case to handle CD drive import)
            FileAttributes attr = File.GetAttributes(destinationFilePath);
            if ((attr & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)
            {
                attr =  attr & ~FileAttributes.ReadOnly;
                File.SetAttributes(destinationFilePath, attr);
            }

            OnCompleted(CopyCompletedType.Succeeded, null);
        }
        else
        {
            OnCompleted(CopyCompletedType.Exception,
                new System.IO.IOException("Unable to close the file handle"));
        }
    }

    return CopyProgressResult.PROGRESS_CONTINUE;
}
[System.Runtime.InteropServices.DllImport("Kernel32")]
private extern static Boolean CloseHandle(IntPtr handle);

[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);

private delegate CopyProgressResult CopyProgressRoutine(long TotalFileSize, long TotalBytesTransferred, long StreamSize, long StreamBytesTransferred, uint dwStreamNumber, CopyProgressCallbackReason dwCallbackReason,
                                                IntPtr hSourceFile, IntPtr hDestinationFile, IntPtr lpData);

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

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

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

如果这是有效的,为什么会出错? 我们真的需要关闭句柄或者它会被CopyFileEx 关闭吗?但是如果我删除了代码CloseHandle 我永远不会得到这个异常。但是目标文件在这个副本之后被另一个操作使用,这就是我装备这个的原因。!

请帮助避免System.IO.IOException : The handle is invalid 错误。

【问题讨论】:

  • CopyProgressRoutine MSDN 主题没有提到应该关闭文件句柄。不关闭手柄有什么问题吗?
  • 是的@AlexFarber'文件被另一个进程使用'当我试图通过我的另一个操作再次打开文件时。为了避免这种情况,我把CloseHandle

标签: c# pinvoke kernel32


【解决方案1】:

您不得关闭把手。句柄归CopyFileEx 所有,并关闭它们。删除对CloseHandle 的调用。

【讨论】:

  • CopyFileEx 是否会在复制完成后立即关闭这些句柄?还是需要一些时间?
  • 句柄在CopyFileEx 返回时关闭。现在,您的防病毒软件可能会妨碍您。或者可能还有其他事情发生。但作为一般规则,除非另有说明,否则只关闭您创建的句柄。这些不是您创建的,关闭它们不是您的责任。
猜你喜欢
  • 1970-01-01
  • 2012-12-19
  • 2014-01-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多