是否有一种相对简单的方法来在C#或PowerShell中完成CD或DVD的最终化?

时间:2017-12-04 18:34:11

标签: c# powershell imapi

首先,对术语进行一些澄清。通过敲定,我并不是说会议结束;我的意思是写一张CD或DVD的引出方式,以便不再通过常用手段(Roxio,Nero,Windows资源管理器等)添加信息。

我对此做了大量研究。有一些开源程序,如InfraRecorder,我们可以从中吸取一些灵感,但它们似乎都涉及使用IMAPI相当精细的C ++代码,这似乎是一种非常低级的做事方式。我们都没有C +或IMAPI专业知识来支持这样的代码库。

互联网上最有前途的资源似乎是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
};

但这不是最终确定的功能;它是将实际数据刻录到磁盘上的功能。您是否必须实际创建新会话以在现有磁盘上执行最终确定?

2 个答案:

答案 0 :(得分:11)

下一次后的ForceMediaToBeClosed controls whether the IMAPI finalizes the discIDiscFormat2Data属性:

  

设置为VARIANT_TRUE以将光盘标记为已关闭,以在下一个写入会话结束时禁止其他写入。

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对象。

此时,如果我们检查空白或打开光盘的状态,我们会看到246的值,对应于&#34 ;空白&#34;或&#34;可附加的&#34; IMAPI_FORMAT2_DATA_MEDIA_STATE枚举的位掩码(6)。

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

对于单会话光盘,我们应该看到163840x4000,&#34;已完成&#34;)。我的系统报告40960封闭的多会话光盘,其中包含0x2000位(&#34;写保护&#34;)和0x8000(&#34;不支持的媒体&# 34)。我们可能需要弹出或重新启动某些硬件才能在刻录后查看准确的值。

<强>说明:

  • 通常,多会话光盘上的每个会话都以引入线开始,并以引出线结束。当我们敲定光盘时,上一次会话的导入将永久关闭媒体以进一步写入。这就是为什么即使我们没有更多数据要添加,我们也需要在未封闭的光盘上附加一个会话。

  • 如果可用空间低于2%,IMAPI将自动敲定光盘。

  • InfraRecorder--问题中提到的工具 - 不使用IMAPI。此应用程序提供cdrtools的前端,直接控制设备IO。如果我们只需要完成未封闭的光盘,我们可能希望使用此软件包中包含的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> -
    

    这与使用IMAPI的PowerShell脚本实现了相同的结果:我们导入上一个会话,创建映像,然后刻录一个新的会话来完成光盘。通过省略 cdrecord -multi参数,命令不会以允许继续多会话光盘的方式写入引入。

    虽然我们通常在类Unix系统上看到此工具集,但builds are available用于Windows。

  • 对于更高级的应用程序,我们可以使用较低级IDiscRecorderEx的实现来查询并向记录设备发送命令。

答案 1 :(得分:8)

ForceMediaToBeClosed对象上设置IMAPI2.MsftDiscFormat2Data标志,并在启用关闭标志的情况下写出光盘。

  • 如果您已经知道上次会话,请设置标记,添加要写入的数据然后将其写出来并关闭。
  • 如果您已经编写了上一个会话,请导入上一个会话,设置标志并写入关闭。

此处描述了方法:https://social.msdn.microsoft.com/Forums/en-US/ce1ff136-39a1-4442-bc5c-61c119b6f4f2/finalize-question?forum=windowsopticalplatform#2e968a94-7347-4d94-9332-00fe7cd0ba89

以下是指向精彩的Powershell刻录脚本的链接,当您准备结束时,您只需更新Out-CD并使用新param设置$DiscFormatData.ForceMediaToBeClosed = true写。

链接: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 ;