How to explicitly create a directory structure in ISO file created with IMAPI?

713 views Asked by At

I have copied a program that writes an ISO file using the IMAPI. It seems to truncate directory names. For example, if I call this function:

image.Root.AddTree("C:\\DIR\\SUBDIR", true);

What I get in the ISO is:

SUBDIR\file 1
SUBDIR\file 2
...

The "DIR" part is dropped.

What I want is:

DIR\SUBDIR\file 1
DIR\SUBDIR\file 2
...

I have seen Create a folder in disk and Burn Into it using IMAPI 2, one of the replies suggests using

rootItem.AddDirectory(directoryName);
rootItem.get_Item(directoryName, newDirItem);   

but get_Item causes a compilation error "cannot explicitly call operator or accessor"

Any suggestions on how to explicitly create directories (and write to them) in the ISO file?

Here is the code. Add IMAPI2 and IMAPI2FS to the References.

using System;
using System.IO;
using System.Runtime.InteropServices;
using IMAPI2FS;     // COM reference: Microsoft IMAPI2 File System Image Creator
using IStream = System.Runtime.InteropServices.ComTypes.IStream;
using STATSTG = System.Runtime.InteropServices.ComTypes.STATSTG;

namespace CreateISO
{

    class IsoImage
    {
        [DllImport("shlwapi.dll", CharSet = CharSet.Unicode, PreserveSig = true)]
        static extern void SHCreateStreamOnFile(string pszFile, uint grfMode, out IStream ppstm);

        public void CreateISO(string path)
        {
            var image = (IFileSystemImage)new MsftFileSystemImage();    // same as Activator.CreateInstance(Type.GetTypeFromProgID("IMAPI2FS.MsftFileSystemImage"))
            image.ChooseImageDefaultsForMediaType(IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_DISK);
            image.FileSystemsToCreate = FsiFileSystems.FsiFileSystemJoliet | FsiFileSystems.FsiFileSystemISO9660;
            image.VolumeName = Path.GetDirectoryName(path);
            image.Root.AddTree(path, true);

            var inStream = (IStream)image.CreateResultImage().ImageStream;
            STATSTG stat;
            inStream.Stat(out stat, 0x01);
            IStream outStream;
            SHCreateStreamOnFile("C:\\temp\\demo.iso", 0x00001001, out outStream);

            unsafe
            {
                long inBytes;
                long outBytes;
                long* pin = &inBytes;
                long* pout = &outBytes;
                inStream.CopyTo(outStream, stat.cbSize, (IntPtr)pin, (IntPtr)pout);
                outStream.Commit(0);
            }
        }
    }
}
1

There are 1 answers

0
Pierre On

I think I got it. The solution is to create a directory, attach the directory to the ISO file, and add the sub-directory to the new object:

        IFsiDirectoryItem newItem = image.CreateDirectoryItem("DIR");
        image.Root.Add(newItem);
        newItem.AddTree("C:\\DIR\\SUBDIR", true);

and lo and behold the ISO looks like:

DIR\SUBDIR\file 1
DIR\SUBDIR\file 2
...

To create multiple levels of directories:

        IFsiDirectoryItem newDir = image.CreateDirectoryItem("DIR");
        IFsiDirectoryItem newDir2 = image.CreateDirectoryItem("SUBDIR1");
        image.Root.Add(newDir);   // must be added first
        newDir.Add(newDir2);
        newDir2.AddTree("C:\\DIR\\SUBDIR1\\SUBDIR2", true);

I must say this is not the most intuitive API I've had to deal with.