IMAPI2 MsftFileSystemImage в .NET не выпускает файлы при создании ISO - PullRequest
3 голосов
/ 26 октября 2011

Я успешно создаю iso-образ, но получаю ошибки ввода-вывода 'file in use', пытаясь удалить файлы в rootFolderPath после возврата из вызова этого метода Create.Я пропускаю вызов Marshal.ReleaseComObject?

спасибо,

cw

/// <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); 
    }
}

Ответы [ 2 ]

6 голосов
/ 10 декабря 2011

Конечно, есть проблема с блокировками на больших файлах.Копание в сети дает следующие кусочки головоломки:

Итак, после всего этого, у меня есть решение: после записи итерируйте корень образа файловой системы и освободите все данные потока.

Существует несколько проблем для мультисессионного диска - поскольку существующие файлы импортируются (с помощью ImportFileSystem), все они проверяются на блокировку, и это может занять некоторое время, и для каждого из них генерируется исключение COMException.не написано в текущей сессии.Приложив немного усилий, я уверен, что разница между файловой системой до и после AddTree может быть кэширована, и проверяются только эти файлы.

Во всяком случае ... После вызова Write мы вызываем 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);
        }
     }
  }

Я надеюсь, что это работает для вас!

0 голосов
/ 12 января 2017

Существует исправление для Windows 7, решающее проблему утечки дескриптора в IMAPIv2. https://support.microsoft.com/en-us/kb/2878035

Эта проблема возникает из-за утечки дескриптора в IMAPIv2, когда многосессионный сеанс записи для носителей DVD-RW.

...