在 C# 或 PowerShell 中是否有一种相对直接的方法来完成 CD 或 DVD?
Is there a relatively straightforward way to finalize a CD or DVD in C# or PowerShell?
首先,对术语进行一些澄清。 finalize, 我不是说关闭会话;我的意思是在 CD 或 DVD 上以这样一种方式写入导出信息,即无法再通过通常的方式(Roxio、Nero、Windows Explorer 等)向其中添加信息
我对此进行了大量研究。有一些像 InfraRecorder 这样的开源程序,我们可以从中得到一些启发,但它们似乎都涉及使用 IMAPI 的相当复杂的 C++ 代码,这似乎是一种非常低级的做事方式。 None 我们团队中的开发人员拥有支持此类代码库的 C++ 或 IMAPI 专业知识。
Internet 上最有前途的资源似乎是 this one,但它似乎不包含最终确定功能。这是“写入图像”的代码:
public void WriteImage(BurnVerificationLevel verification, bool finalize, bool eject)
{
if (!_recorderLoaded)
throw new InvalidOperationException("LoadMedia must be called first.");
MsftDiscRecorder2 recorder = null;
MsftDiscFormat2Data discFormatData = null;
try
{
recorder = new MsftDiscRecorder2();
recorder.InitializeDiscRecorder(_recorders.SelectedItem.InternalUniqueId);
discFormatData = new MsftDiscFormat2Data
{
Recorder = recorder,
ClientName = ClientName,
ForceMediaToBeClosed = finalize
};
//
// Set the verification level
//
var burnVerification = (IBurnVerification)discFormatData;
burnVerification.BurnVerificationLevel = IMAPI_BURN_VERIFICATION_LEVEL.IMAPI_BURN_VERIFICATION_NONE;
//
// Check if media is blank, (for RW media)
//
object[] multisessionInterfaces = null;
if (!discFormatData.MediaHeuristicallyBlank)
multisessionInterfaces = discFormatData.MultisessionInterfaces;
//
// Create the file system
//
IStream fileSystem;
_CreateImage(recorder, multisessionInterfaces, out fileSystem);
discFormatData.Update += _discFormatWrite_Update;
//
// Write the data
//
try
{
discFormatData.Write(fileSystem);
}
finally
{
if (fileSystem != null) Marshal.FinalReleaseComObject(fileSystem);
}
discFormatData.Update -= _discFormatWrite_Update;
if (eject) recorder.EjectMedia();
}
finally
{
_isWriting = false;
if (discFormatData != null) Marshal.ReleaseComObject(discFormatData);
if (recorder != null) Marshal.ReleaseComObject(recorder);
}
}
代码的关键部分似乎是这个:
discFormatData = new MsftDiscFormat2Data
{
Recorder = recorder,
ClientName = ClientName,
ForceMediaToBeClosed = finalize // <-- Here
};
但这不是终结函数;它是一种将实际数据刻录到磁盘上的功能。您是否必须实际创建一个新会话才能在现有磁盘上执行终结?
在 IMAPI2.MsftDiscFormat2Data
对象上设置 ForceMediaToBeClosed
标志,并在启用关闭标志的情况下写出光盘。
- 如果您已经知道这是您的最后一个会话,请设置标志,添加要写入的数据,然后将其写出,它将关闭。
- 如果您已经编写了最后一个会话,则导入最后一个会话,设置标志并写入关闭。
下面是一个很好的 Powershell 刻录脚本的 link,您所要做的就是用新的 param
更新 Out-CD
来设置 $DiscFormatData.ForceMediaToBeClosed = true
你准备好结束写作了。
Link: https://www.adamtheautomator.com/use-powershell-to-automate-burning-cds/
仅供参考:
# this fetches all the properties (as you probably already know)
$DiscFormatData = New-Object -com IMAPI2.MsftDiscFormat2Data ;
$DiscFormatData | Get-Member ;
ForceMediaToBeClosed
属性 of IDiscFormat2Data
controls whether the IMAPI finalizes the disc 之后 next 写:
Set to VARIANT_TRUE to mark the disc as closed to prohibit additional writes when the next write session ends.
Image Mastering API 没有提供专门用于完成光盘的抽象,因此我们需要执行写入操作。如果我们用主映像写入器打开 ForceMediaToBeClosed
,API 将在初始刻录期间完成一张空白光盘。对于现有的多区段光盘,我们需要追加另一个区段。
这是一个简单的 PowerShell 示例,我们可以尝试使用它,这样我们就不需要构建项目了。 C# 中的概念相似:
$drives = New-Object -ComObject 'IMAPI2.MsftDiscMaster2'
$recorder = New-Object -ComObject 'IMAPI2.MsftDiscRecorder2'
$recorder.InitializeDiscRecorder($drives[0]) # Choose a drive here
$disc = New-Object -ComObject 'IMAPI2.MsftDiscFormat2Data'
$disc.ClientName = 'PowerShell Recorder'
$disc.Recorder = $recorder
$disc.ForceMediaToBeClosed = $true # Finalize the next session
$image = New-Object -ComObject 'IMAPI2FS.MsftFileSystemImage'
if (!$disc.IsCurrentMediaSupported($recorder)) {
throw 'Disc is not writeable.'
} elseif ($disc.MediaHeuristicallyBlank) {
$image.ChooseImageDefaults($recorder)
} else {
$image.MultisessionInterfaces = $disc.MultisessionInterfaces
$image.ImportFileSystem() > $null
}
这会设置一些我们将在下面用来刻录光盘的样板文件。我们需要为实际使用添加错误处理和功能检测,但它作为演示效果很好。如果我们将此代码粘贴或点源到 PowerShell 会话中,我们可以交互式地使用 COM 对象。
此时,如果我们检查一张空白或打开的光盘的状态,我们应该看到 2
、4
或 6
的值对应于 "blank" 或 "appendable" 位掩码(两者均为 6
)在 IMAPI_FORMAT2_DATA_MEDIA_STATE
.
上枚举
PS> $disc.CurrentMediaStatus # 4 for an open, multi-session disc
然后,我们可以添加一些文件。如果我们只想关闭多区段光盘,则不需要向图像添加任何内容。 API记录会话的引入和引出,数据轨道为空。
PS> $image.Root.AddTree('path\to\root\folder', $false)
最后,我们会将更改刻录到光盘。因为我们将 $disc.ForceMediaToBeClosed
设置为 $true
,此操作完成了光盘,并且不允许进一步的写入操作:
PS> $disc.Write($image.CreateResultImage().ImageStream)
如果我们现在查看光盘状态,应该会提示光盘不可写:
PS> $disc.CurrentMediaStatus # 16384 or 40960
对于单区段光盘,我们应该看到 16384
(0x4000
、"finalized")。我的系统报告 40960
为封闭的多区段光盘,其中包含位 0x2000
("write-protected") 和 0x8000
("unsupported media")。我们可能需要弹出或重启某些硬件才能在刻录后查看准确的值。
备注:
一般来说,多区段光盘上的每个区段都以导入开始,以导出结束。当我们完成光盘时,最后一个会话的导入会永久关闭媒体以进一步写入。这就是为什么即使我们没有更多的数据要添加,我们也需要向未关闭的光盘追加一个额外的会话。
IMAPI 将在免费 space 低于 2% 时自动完成光盘。
InfraRecorder——问题中提到的工具——不使用IMAPI。此应用程序为此软件包中包含的 cdrtools which controls the device IO directly. If we just need to finalize unclosed discs, we may want to use the cdrecord CLI 程序提供了一个前端,以避免维护额外的代码库:
PS> cdrecord -scanbus # Show <drive> IDs to choose from
PS> cdrecord -fix dev=<drive> # Close an open session
作为一个简短的起点,我们可以通过以下方式完成多区段光盘:
PS> $session = cdrecord -msinfo dev=<drive>
PS> mkisofs -rJ -C $session -M <drive> 'path\to\root' | cdrecord dev=<drive> -
这实现了与我们使用 IM 的 PowerShell 脚本相同的结果API:我们导入最后一个会话,创建映像,然后刻录一个新会话来完成光盘。通过省略 cdrecord 的 -multi
参数,该命令不会以允许多区段光盘继续的方式写入导入。
虽然我们通常在类 Unix 系统上看到此工具集,但 builds are available 用于 Windows。
对于更高级的应用,我们可以使用较低级别的实现IDiscRecorderEx
来查询并向记录设备发送命令。
首先,对术语进行一些澄清。 finalize, 我不是说关闭会话;我的意思是在 CD 或 DVD 上以这样一种方式写入导出信息,即无法再通过通常的方式(Roxio、Nero、Windows Explorer 等)向其中添加信息
我对此进行了大量研究。有一些像 InfraRecorder 这样的开源程序,我们可以从中得到一些启发,但它们似乎都涉及使用 IMAPI 的相当复杂的 C++ 代码,这似乎是一种非常低级的做事方式。 None 我们团队中的开发人员拥有支持此类代码库的 C++ 或 IMAPI 专业知识。
Internet 上最有前途的资源似乎是 this one,但它似乎不包含最终确定功能。这是“写入图像”的代码:
public void WriteImage(BurnVerificationLevel verification, bool finalize, bool eject)
{
if (!_recorderLoaded)
throw new InvalidOperationException("LoadMedia must be called first.");
MsftDiscRecorder2 recorder = null;
MsftDiscFormat2Data discFormatData = null;
try
{
recorder = new MsftDiscRecorder2();
recorder.InitializeDiscRecorder(_recorders.SelectedItem.InternalUniqueId);
discFormatData = new MsftDiscFormat2Data
{
Recorder = recorder,
ClientName = ClientName,
ForceMediaToBeClosed = finalize
};
//
// Set the verification level
//
var burnVerification = (IBurnVerification)discFormatData;
burnVerification.BurnVerificationLevel = IMAPI_BURN_VERIFICATION_LEVEL.IMAPI_BURN_VERIFICATION_NONE;
//
// Check if media is blank, (for RW media)
//
object[] multisessionInterfaces = null;
if (!discFormatData.MediaHeuristicallyBlank)
multisessionInterfaces = discFormatData.MultisessionInterfaces;
//
// Create the file system
//
IStream fileSystem;
_CreateImage(recorder, multisessionInterfaces, out fileSystem);
discFormatData.Update += _discFormatWrite_Update;
//
// Write the data
//
try
{
discFormatData.Write(fileSystem);
}
finally
{
if (fileSystem != null) Marshal.FinalReleaseComObject(fileSystem);
}
discFormatData.Update -= _discFormatWrite_Update;
if (eject) recorder.EjectMedia();
}
finally
{
_isWriting = false;
if (discFormatData != null) Marshal.ReleaseComObject(discFormatData);
if (recorder != null) Marshal.ReleaseComObject(recorder);
}
}
代码的关键部分似乎是这个:
discFormatData = new MsftDiscFormat2Data
{
Recorder = recorder,
ClientName = ClientName,
ForceMediaToBeClosed = finalize // <-- Here
};
但这不是终结函数;它是一种将实际数据刻录到磁盘上的功能。您是否必须实际创建一个新会话才能在现有磁盘上执行终结?
在 IMAPI2.MsftDiscFormat2Data
对象上设置 ForceMediaToBeClosed
标志,并在启用关闭标志的情况下写出光盘。
- 如果您已经知道这是您的最后一个会话,请设置标志,添加要写入的数据,然后将其写出,它将关闭。
- 如果您已经编写了最后一个会话,则导入最后一个会话,设置标志并写入关闭。
下面是一个很好的 Powershell 刻录脚本的 link,您所要做的就是用新的 param
更新 Out-CD
来设置 $DiscFormatData.ForceMediaToBeClosed = true
你准备好结束写作了。
Link: https://www.adamtheautomator.com/use-powershell-to-automate-burning-cds/
仅供参考:
# this fetches all the properties (as you probably already know)
$DiscFormatData = New-Object -com IMAPI2.MsftDiscFormat2Data ;
$DiscFormatData | Get-Member ;
ForceMediaToBeClosed
属性 of IDiscFormat2Data
controls whether the IMAPI finalizes the disc 之后 next 写:
Set to VARIANT_TRUE to mark the disc as closed to prohibit additional writes when the next write session ends.
Image Mastering API 没有提供专门用于完成光盘的抽象,因此我们需要执行写入操作。如果我们用主映像写入器打开 ForceMediaToBeClosed
,API 将在初始刻录期间完成一张空白光盘。对于现有的多区段光盘,我们需要追加另一个区段。
这是一个简单的 PowerShell 示例,我们可以尝试使用它,这样我们就不需要构建项目了。 C# 中的概念相似:
$drives = New-Object -ComObject 'IMAPI2.MsftDiscMaster2'
$recorder = New-Object -ComObject 'IMAPI2.MsftDiscRecorder2'
$recorder.InitializeDiscRecorder($drives[0]) # Choose a drive here
$disc = New-Object -ComObject 'IMAPI2.MsftDiscFormat2Data'
$disc.ClientName = 'PowerShell Recorder'
$disc.Recorder = $recorder
$disc.ForceMediaToBeClosed = $true # Finalize the next session
$image = New-Object -ComObject 'IMAPI2FS.MsftFileSystemImage'
if (!$disc.IsCurrentMediaSupported($recorder)) {
throw 'Disc is not writeable.'
} elseif ($disc.MediaHeuristicallyBlank) {
$image.ChooseImageDefaults($recorder)
} else {
$image.MultisessionInterfaces = $disc.MultisessionInterfaces
$image.ImportFileSystem() > $null
}
这会设置一些我们将在下面用来刻录光盘的样板文件。我们需要为实际使用添加错误处理和功能检测,但它作为演示效果很好。如果我们将此代码粘贴或点源到 PowerShell 会话中,我们可以交互式地使用 COM 对象。
此时,如果我们检查一张空白或打开的光盘的状态,我们应该看到 2
、4
或 6
的值对应于 "blank" 或 "appendable" 位掩码(两者均为 6
)在 IMAPI_FORMAT2_DATA_MEDIA_STATE
.
PS> $disc.CurrentMediaStatus # 4 for an open, multi-session disc
然后,我们可以添加一些文件。如果我们只想关闭多区段光盘,则不需要向图像添加任何内容。 API记录会话的引入和引出,数据轨道为空。
PS> $image.Root.AddTree('path\to\root\folder', $false)
最后,我们会将更改刻录到光盘。因为我们将 $disc.ForceMediaToBeClosed
设置为 $true
,此操作完成了光盘,并且不允许进一步的写入操作:
PS> $disc.Write($image.CreateResultImage().ImageStream)
如果我们现在查看光盘状态,应该会提示光盘不可写:
PS> $disc.CurrentMediaStatus # 16384 or 40960
对于单区段光盘,我们应该看到 16384
(0x4000
、"finalized")。我的系统报告 40960
为封闭的多区段光盘,其中包含位 0x2000
("write-protected") 和 0x8000
("unsupported media")。我们可能需要弹出或重启某些硬件才能在刻录后查看准确的值。
备注:
一般来说,多区段光盘上的每个区段都以导入开始,以导出结束。当我们完成光盘时,最后一个会话的导入会永久关闭媒体以进一步写入。这就是为什么即使我们没有更多的数据要添加,我们也需要向未关闭的光盘追加一个额外的会话。
IMAPI 将在免费 space 低于 2% 时自动完成光盘。
InfraRecorder——问题中提到的工具——不使用IMAPI。此应用程序为此软件包中包含的 cdrtools which controls the device IO directly. If we just need to finalize unclosed discs, we may want to use the cdrecord CLI 程序提供了一个前端,以避免维护额外的代码库:
PS> cdrecord -scanbus # Show <drive> IDs to choose from PS> cdrecord -fix dev=<drive> # Close an open session
作为一个简短的起点,我们可以通过以下方式完成多区段光盘:
PS> $session = cdrecord -msinfo dev=<drive> PS> mkisofs -rJ -C $session -M <drive> 'path\to\root' | cdrecord dev=<drive> -
这实现了与我们使用 IM 的 PowerShell 脚本相同的结果API:我们导入最后一个会话,创建映像,然后刻录一个新会话来完成光盘。通过省略 cdrecord 的
-multi
参数,该命令不会以允许多区段光盘继续的方式写入导入。虽然我们通常在类 Unix 系统上看到此工具集,但 builds are available 用于 Windows。
对于更高级的应用,我们可以使用较低级别的实现
IDiscRecorderEx
来查询并向记录设备发送命令。