将流作为文件添加到 ISO
Adding a stream to an ISO as a File
我正在 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);
}
您正在尝试使用 IMAPI2FS 类型库,并且 运行遇到该库的一个常见问题。它的创作相当糟糕,很难直接从 .NET 程序中使用。大多数以 api 为目标的程序都是用 C++ 编写的,并使用 imap2fs.h SDK 头文件。
您在此处 运行 遇到的具体问题是类型库导入程序将 AddFile() 的第二个参数转换为 FsiStream,一个 coclass 类型。它是您无法创建的类型,它具有 [noncreatable] 类型库属性。类型库转换器误入歧途,方法 实际上 采用 IStream 参数。你应该做的是创建你自己的 IStream 实现并将它的一个实例作为第二个参数传递。
这可以在 C# 版本 4 dynamic 关键字的帮助下解决,因此编译器不会抱怨 FsiStream。这是实现 IStream 的示例实现 class:
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 project,由一位也在与 IMAPI2 作斗争的程序员编写。他采用了一种更广泛的方法,一种相当危险的方法,并用手工制作的 C# 声明重写了整个类型库。他花了很多时间在这上面,支持问题只关注学习如何使用 IMAPI2,所以你可能可以依赖它。
我正在 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);
}
您正在尝试使用 IMAPI2FS 类型库,并且 运行遇到该库的一个常见问题。它的创作相当糟糕,很难直接从 .NET 程序中使用。大多数以 api 为目标的程序都是用 C++ 编写的,并使用 imap2fs.h SDK 头文件。
您在此处 运行 遇到的具体问题是类型库导入程序将 AddFile() 的第二个参数转换为 FsiStream,一个 coclass 类型。它是您无法创建的类型,它具有 [noncreatable] 类型库属性。类型库转换器误入歧途,方法 实际上 采用 IStream 参数。你应该做的是创建你自己的 IStream 实现并将它的一个实例作为第二个参数传递。
这可以在 C# 版本 4 dynamic 关键字的帮助下解决,因此编译器不会抱怨 FsiStream。这是实现 IStream 的示例实现 class:
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 project,由一位也在与 IMAPI2 作斗争的程序员编写。他采用了一种更广泛的方法,一种相当危险的方法,并用手工制作的 C# 声明重写了整个类型库。他花了很多时间在这上面,支持问题只关注学习如何使用 IMAPI2,所以你可能可以依赖它。