创建ISO时.NET中的IMAPI2 MsftFileSystemImage不释放文件 [英] IMAPI2 MsftFileSystemImage in .NET not releasing files when creating ISO

查看:294
本文介绍了创建ISO时.NET中的IMAPI2 MsftFileSystemImage不释放文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我成功创建了ISO映像,但是在调用此Create方法返回后,尝试删除rootFolderPath中的文件时遇到正在使用文件"的IO错误.我是否错过了Marshal.ReleaseComObject通话?

I succesfully create the ISO image, but I get 'file in use' IO errors trying to delete files in the rootFolderPath after returning from calling this Create method. Am I missing a Marshal.ReleaseComObject call?

/// <summary>
/// Create iso image from rootFolderPath and write to isoImageFilePath. Does not include the actual rootFolder itself
/// </summary>
public void Create()
{
    IFileSystemImage ifsi = new MsftFileSystemImage();
    try
    {
        ifsi.ChooseImageDefaultsForMediaType(IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_DISK);
        ifsi.FileSystemsToCreate =
                FsiFileSystems.FsiFileSystemJoliet | FsiFileSystems.FsiFileSystemISO9660;
        ifsi.VolumeName = this.volumeName;
        ifsi.Root.AddTree(rootFolderPath, false);//use a valid folder
        //this will implement the Write method for the formatter
        IStream imagestream = ifsi.CreateResultImage().ImageStream;
        if (imagestream != null)
        {
            System.Runtime.InteropServices.ComTypes.STATSTG stat;
            imagestream.Stat(out stat, 0x01);
            IStream newStream;
            if (0 == SHCreateStreamOnFile(isoImageFilepath, 0x00001001, out newStream) && newStream != null)
            {
                IntPtr inBytes = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(long)));
                IntPtr outBytes = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(long)));
                try
                {
                    imagestream.CopyTo(newStream, stat.cbSize, inBytes, outBytes);
                    Marshal.ReleaseComObject(imagestream);
                    imagestream = null;
                    newStream.Commit(0);
                }
                finally
                {
                    Marshal.ReleaseComObject(newStream);
                    Marshal.FreeHGlobal(inBytes);
                    Marshal.FreeHGlobal(outBytes);
                    if (imagestream != null)
                        Marshal.ReleaseComObject(imagestream);
                }
            }
        }
    }
    finally
    {
        Marshal.ReleaseComObject(ifsi); 
    }
}

推荐答案

大文件锁定肯定存在问题.在网上闲逛会产生以下难题:

There is certainly a problem with locks on large files. Digging around on the net produces the following bits of the puzzle:

MS的第一个答案承认大文件存在问题. (NB设置"Staging = false"对我不起作用.)

The first answer from MS acknowledges a problem with large files. (NB setting "Staging = false" does not work for me.)

http://www.codeproject.com/KB/miscctrl/ISOImage.aspx?msg=2532334

使用流添加要刻录的文件.

Uses a stream to add files to be burned.

http ://social.msdn.microsoft.com/Forums/zh-CN/windowsopticalplatform/thread/124017ea-79c5-45e2-b62e-589b3b4505af

讨论了AddRef/Release的不平衡情况.

Discusses an AddRef/Release imbalance.

因此,在消化了所有这些信息后,我有了一个解决方案:在写入之后,迭代文件系统映像根并释放所有流数据.

So, with all of this digested, I’ve got a solution: after Write, iterate the file system image root and release any stream data.

多会话光盘有两个问题-由于(通过ImportFileSystem)导入了现有文件,因此将检查所有文件是否锁定,这可能需要一些时间,并且会为每个未写入的文件抛出COMException异常当前会话.通过一点努力,我确定可以缓存AddTree之前和之后的文件系统之间的差异,并且仅检查那些文件.

There are a couple of issues for a multisession disc – as the existing files are imported (by ImportFileSystem) they all are checked for a lock and this may take some time, and a COMException is thrown for each that was not written in the current session. With a bit of effort I’m sure the difference between the file system before and after AddTree can be cached, and only those files checked.

无论如何...在调用Write之后,我们调用ReleaseIFsiItems ...

Anyhow... After the call to Write, we call ReleaseIFsiItems...

       {
          // Write...

          // Call to release any locks
          ReleaseIFsiItems(fileSystemImage.Root);

           // Complete tidy up...
          Marshal.FinalReleaseComObject(fileSystem);
          Marshal.FinalReleaseComObject(fileSystemImageResult);
        }

 private static void ReleaseIFsiItems(IFsiDirectoryItem rootItem)
  {
     if (rootItem == null)
     {
        return;
     }

     var enm = rootItem.GetEnumerator();
     while (enm.MoveNext())
     {
        var currentItem = enm.Current as IFsiItem;
        var fsiFileItem = currentItem as IFsiFileItem;
        if (fsiFileItem != null)
        {
           try
           {
              var stream = fsiFileItem.Data;
              var iUnknownForObject = Marshal.GetIUnknownForObject(stream);
              // Get a reference - things go badly wrong if we release a 0 ref count stream!
              var i = Marshal.AddRef(iUnknownForObject);
              // Release all references
              while (i > 0)
              {
                 i = Marshal.Release(iUnknownForObject);
              }
              Marshal.FinalReleaseComObject(stream);
           }
           catch (COMException)
           {
              // Thrown when accessing fsiFileItem.Data
           }
        }
        else
        {
           ReleaseIFsiItems(currentItem as IFsiDirectoryItem);
        }
     }
  }

我希望这对您有用!

这篇关于创建ISO时.NET中的IMAPI2 MsftFileSystemImage不释放文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆