C# 将流作为文件添加到ISO

C# 将流作为文件添加到ISO,c#,stream,filesystems,imapi,C#,Stream,Filesystems,Imapi,我正在Windows中使用IMAPI2FS映像主控API,我试图在生成ISO之前找出如何将流作为文件添加到文件系统映像中 var fsi = new MsftFileSystemImage(); fsi.ChooseImageDefaultsForMediaType(IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_DISK); fsi.FileSystemsToCreate = FsiFileSystems.FsiFileSystemISO9660

我正在Windows中使用IMAPI2FS映像主控API,我试图在生成ISO之前找出如何将流作为文件添加到文件系统映像中

var fsi = new MsftFileSystemImage();
fsi.ChooseImageDefaultsForMediaType(IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_DISK);
fsi.FileSystemsToCreate = 
    FsiFileSystems.FsiFileSystemISO9660 | FsiFileSystems.FsiFileSystemJoliet;

using (var stream = new MemoryStream())
{
    stream.Write(buffer, 0, bufferSize);

    // Here is where I need to either instantiate an FsiStream and copy
    // stream to it, but I can't figure out how to do this.

    fsi.Root.AddFile(relativePathFromImageRoot, iStreamObject);
}

您试图使用IMAPI2FS类型库,但该库遇到了一个常见问题。它编写得相当糟糕,很难直接从.NET程序中使用。以API为目标的大多数程序都是用C++编写的,使用了IMAP2FS .h SDK头文件。 您在这里遇到的具体问题是,类型库导入程序将AddFile()的第二个参数转换为FsiStream,这是一种coclass类型。它是无法创建的类型,具有[noncreatable]类型库属性。类型库转换器被引入歧途,该方法实际上使用了一个IStream参数。您应该做的是创建自己的IStream实现,并将其实例作为第二个参数传递

这可以在C#version 4 dynamic关键字的帮助下解决,这样编译器就不会抱怨FsiStream了。下面是一个实现IStream的示例实现类:

using System;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.IO;

[ComVisible(true)]
class FsiStreamImpl : IStream {
    private Stream source;
    private FsiStreamImpl() { }
    public static dynamic Create(Stream from) {
        var stream = new FsiStreamImpl();
        stream.source = from;
        return stream;
    }

    public void Read(byte[] pv, int cb, IntPtr pcbRead) {
        int read = source.Read(pv, 0, cb);
        Marshal.WriteInt32(pcbRead, read);
    }

    public void Seek(long dlibMove, int dwOrigin, IntPtr plibNewPosition) {
        long pos = source.Seek(dlibMove, (SeekOrigin)dwOrigin);
        Marshal.WriteInt64(plibNewPosition, pos);
    }

    public void Stat(out STATSTG pstatstg, int grfStatFlag) {
        var stat = new STATSTG();
        stat.type = 2;
        stat.cbSize = source.Length;
        stat.grfMode = 2;
        pstatstg = stat;
    }

    // Methods that we don't have to implement:
    public void Write(byte[] pv, int cb, IntPtr pcbWritten) {
        throw new NotImplementedException();
    }
    public void Clone(out IStream ppstm) {
        throw new NotImplementedException();
    }
    public void Commit(int grfCommitFlags) {
        throw new NotImplementedException();
    }
    public void SetSize(long libNewSize) {
        throw new NotImplementedException();
    }
    public void CopyTo(IStream pstm, long cb, IntPtr pcbRead, IntPtr pcbWritten) {
        throw new NotImplementedException();
    }
    public void LockRegion(long libOffset, long cb, int dwLockType) {
        throw new NotImplementedException();
    }
    public void Revert() {
        throw new NotImplementedException();
    }
    public void UnlockRegion(long libOffset, long cb, int dwLockType) {
        throw new NotImplementedException();
    }
}
现在,您可以这样编写代码:

using (var stream = new MemoryStream(buffer))
{
    stream.Write(buffer, 0, bufferSize);
    stream.Position = 0;
    fsi.Root.AddFile(relativePathFromImageRoot, FsiStreamImpl.Create(stream)));
}
或者像这样的代码,我测试的:

using (var file = new FileStream(@"c:\temp\test.txt", FileMode.Open, FileAccess.Read)) {
    fsi.Root.AddFile("test.txt", FsiStreamImpl.Create(file));
}
你可能会遇到更多的问题,我只测试了你发布的代码片段。我应该指出这一点,它是由一位与IMAPI2进行斗争的程序员编写的。他采取了一种更为广泛、相当危险的方法,用手工制作的C#声明重写了整个类型库。他在这方面花了很多时间,而支持问题只关注于学习如何使用IMAPI2,因此您可能可以依赖它