将流作为文件添加到 ISO

Posted

技术标签:

【中文标题】将流作为文件添加到 ISO【英文标题】:Adding a stream to an ISO as a File 【发布时间】:2015-08-19 18:07:01 【问题描述】:

我在 Windows 中使用 IMAPI2FS Image Mastering 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);

【问题讨论】:

【参考方案1】:

您正在尝试使用 IMAPI2FS 类型库并且遇到了该库的常见问题。它的创作相当糟糕,而且很难直接从 .NET 程序中使用。大多数以 api 为目标的程序都是用 C++ 编写的,并使用 imap2fs.h SDK 头文件。

您在这里遇到的具体问题是类型库导入器将 AddFile() 的第二个参数转换为 FsiStream,一个 coclass 类型。它是您无法创建的类型,它具有 [noncreatable] 类型库属性。类型库转换器误入歧途,该方法实际上 采用 IStream 参数。您应该做的是创建自己的 IStream 实现并将其实例作为第二个参数传递。

这可以在 C# 版本 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));

您可能会遇到更多问题,我只测试了您发布的sn-p。我应该指出这个Codeproject.com project,它是由一个也在与 IMAPI2 作斗争的程序员编写的。他采用了一种更广泛、相当危险的方法,并使用手工制作的 C# 声明重写了整个类型库。他花了很多时间在这上面,支持问题只集中在学习如何使用 IMAPI2 上,所以你可以依靠它。

【讨论】:

以上是关于将流作为文件添加到 ISO的主要内容,如果未能解决你的问题,请参考以下文章

向已有的系统镜像iso文件添加软件安装包,制作一个新的系统盘iso文件,如何实现

WinPE - 将自定义应用程序添加到 boot.wim 或 iso

将流嵌入网站

家用台式机安装ESXI 5.x网卡驱动添加到iso镜像文件及制作工具

如何重新封装linux系统成iso文件

ISO 通过 vue.config.js 链接 Webpack 以将全局 .scss 导入添加到我的 .vue 文件的正确方法(vue-cli-plugin-nativescript-vue)