Добавление потока в ISO как файл

Я использую IMAPI2FS Image Mastering API в Windows, и я пытаюсь выяснить, как добавить поток в виде файла в образ файловой системы, прежде чем я создаю 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, тип кокласса. Это тип, который вы не можете создать, он имеет атрибут [noncreatable] библиотеки типов. Конвертер библиотеки типов был введен в заблуждение, метод фактически принимает аргумент IStream. Что вы должны сделать, это создать свою собственную реализацию IStream и передать ее экземпляр в качестве 2-го аргумента.

Это можно обойти с помощью динамического ключевого слова C# версии 4, поэтому компилятор не будет жаловаться на 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));
}

Вы можете столкнуться с еще некоторыми проблемами, я только протестировал размещенный вами фрагмент. Я должен указать на этот проект Codeproject.com, написанный программистом, который также сражался с IMAPI2. Он выбрал гораздо более широкий подход, довольно опасный, и переписал всю библиотеку типов с помощью созданных вручную объявлений C#. Он потратил много времени на это, и вопросы поддержки сосредоточены только на изучении, как использовать IMAPI2, так что вы, вероятно, можете полагаться на него.

Другие вопросы по тегам