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:
http://social.msdn.microsoft.com/Forums/en-US/windowsopticalplatform/thread/5ae4a173-ccb2-4c10-8fd5-c6e59a9c0ac9
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/en-AU/windowsopticalplatform/thread/124017ea-79c5-45e2-b62e-589b3b4505af
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.
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.
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);
}
}
}
I hope this works for you!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With