简体   繁体   English

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

[英]Is there a relatively straightforward way to finalize a CD or DVD in C# or PowerShell?

First, some clarification of terms.首先,一些术语的澄清。 By finalize, I don't mean closing a session;完成,我的意思不是关闭会话; I mean writing a lead-out to a CD or DVD in such a way that information can no longer be added to it via the usual means (Roxio, Nero, Windows Explorer, etc.)我的意思是将导引写入 CD 或 DVD,这样信息就不能再通过通常的方式(Roxio、Nero、Windows 资源管理器等)添加到其中

I've done a fair amount of research on this.我对此进行了大量研究。 There are some open-source programs like InfraRecorder from which we could draw some inspiration, but they all seem to involve rather elaborate reams of C++ code using IMAPI, which seems like a very low-level way to do things.有一些像InfraRecorder这样的开源程序,我们可以从中汲取一些灵感,但它们似乎都涉及使用 IMAPI 的大量 C++ 代码,这似乎是一种非常低级的做事方式。 None of the developers on our team have the C++ or IMAPI expertise to support such a code base.我们团队中的所有开发人员都不具备支持此类代码库的 C++ 或 IMAPI 专业知识。

The most promising resource on the internet appears to be this one , but it doesn't seem to include a finalize function.互联网上最有前途的资源似乎是this ,但它似乎不包含 finalize 功能。 Here is the code that "writes an image":这是“写入图像”的代码:

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);                
    }
}

The critical section of code seems to be this one:代码的关键部分似乎是这样的:

discFormatData = new MsftDiscFormat2Data
{
    Recorder = recorder,
    ClientName = ClientName,
    ForceMediaToBeClosed = finalize // <-- Here
};

But this isn't a finalize function;但这不是一个 finalize 函数; it's a function that burns actual data onto a disk.它是一种将实际数据刻录到磁盘上的功能。 Do you have to actually create a new session to perform a finalization on an existing disk?您是否必须实际创建一个新会话才能在现有磁盘上执行终结?

The ForceMediaToBeClosed property of IDiscFormat2Data controls whether the IMAPI finalizes the disc after the next write:ForceMediaToBeClosed财产IDiscFormat2Data 控制是否将IMAPI定型盘下一个写操作后:

Set to VARIANT_TRUE to mark the disc as closed to prohibit additional writes when the next write session ends.设置为 VARIANT_TRUE 以将磁盘标记为关闭以在下一个写入会话结束时禁止额外写入。

The Image Mastering API does not provide an abstraction used specifically to finalize the disc, so we need to perform a write operation. Image Mastering API 没有提供专门用于定型光盘的抽象,因此我们需要执行写入操作。 The API will finalize a blank disc during the initial burn if we switch on ForceMediaToBeClosed with the main image writer.如果我们使用主映像ForceMediaToBeClosed器打开ForceMediaToBeClosed ,API 将在初始刻录期间完成一张空白光盘。 For an existing multi-session disc, we need to append another session.对于现有的多会话光盘,我们需要附加另一个会话。

Here's a simple PowerShell example that we can try so we don't need to build the project.这是一个简单的 PowerShell 示例,我们可以尝试使用它,因此我们不需要构建项目。 The concepts are similar in C#:这些概念在 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
}

This sets up some boilerplate that we'll use below to burn a disc.这将设置一些样板,我们将在下面使用它们来刻录光盘。 We'll need to add error handling and capability detection for practical use, but it works fine as a demonstration.我们需要为实际使用添加错误处理和功能检测,但它作为演示工作正常。 If we paste or dot-source this code into a PowerShell session, we can play with the COM objects interactively.如果我们将此代码粘贴或点源到 PowerShell 会话中,我们就可以交互地使用 COM 对象。

At this point, if we check the status of a blank or open disc, we should see a value of 2 , 4 , or 6 which correspond to the "blank" or "appendable" bitmasks ( 6 for both) enumerated on IMAPI_FORMAT2_DATA_MEDIA_STATE .在这一点上,如果我们检查空白或开放光盘的状态,我们应该看到的值24 ,或6 ,其对应于“空白”或“追加”位掩码( 6列举对两者) IMAPI_FORMAT2_DATA_MEDIA_STATE

PS> $disc.CurrentMediaStatus  # 4 for an open, multi-session disc 

Then, we can add some files.然后,我们可以添加一些文件。 If we just want to close-off a multi-session disc, we don't need to add anything to the image.如果我们只想关闭多会话光盘,我们不需要向图像添加任何内容。 The API records the session's lead-in and lead-out with an empty data track. API 使用空数据轨道记录会话的导入和导出。

PS> $image.Root.AddTree('path\to\root\folder', $false)

Finally, we'll burn our changes to the disc.最后,我们将更改刻录到光盘上。 Because we set $disc.ForceMediaToBeClosed to $true , this operation finalizes the disc, and no further write operations are allowed:因为我们将$disc.ForceMediaToBeClosed设置$disc.ForceMediaToBeClosed $true ,此操作完成了磁盘,并且不允许进一步的写入操作:

PS> $disc.Write($image.CreateResultImage().ImageStream)

If we inspect the disc status now, it should indicate that the disc is not writable:如果我们现在检查光盘状态,应该表明该光盘不可写:

PS> $disc.CurrentMediaStatus  # 16384 or 40960

For a single-session disc, we should see 16384 ( 0x4000 , "finalized").对于单会话光盘,我们应该看到16384 ( 0x4000 ,“已完成”)。 My system reports 40960 for closed, multi-session discs which contains the bits 0x2000 ("write-protected") and 0x8000 ("unsupported media").对于包含位0x2000 (“写保护”)和0x8000 (“不受支持的媒体”)的封闭式多会话光盘,我的系统报告40960 We may need to eject or power-cycle some hardware to see accurate values after burning.我们可能需要弹出或重启某些硬件才能看到刻录后的准确值。

Remarks:评论:

  • In general, each session on a multi-session disc starts with a lead-in and ends with a lead-out.通常,多区段光盘上的每个区段以导入开始并以导出结束。 The lead-in of the last session permanently closes the media to further writes when we finalize a disc.当我们完成光盘时,最后一个会话的导入将永久关闭媒体以进一步写入。 This is why we need to append an additional session to an unclosed disc even if we have no more data to add.这就是为什么即使我们没有更多数据要添加,我们也需要将附加会话附加到未关闭的磁盘。

  • IMAPI will automatically finalize a disc if the free space drops below 2%.如果可用空间低于 2%,IMAPI 将自动终结光盘。

  • InfraRecorder—the tool mentioned in the question—does not use the IMAPI. InfraRecorder(问题中提到的工具)不使用 IMAPI。 This application provides a frontend to cdrtools which controls the device IO directly.此应用程序为cdrtools提供了一个前端,它直接控制设备 IO。 If we just need to finalize unclosed discs, we may want to use the cdrecord CLI program included with this package to avoid maintaining an extra codebase:如果我们只需要完成未封闭的光盘,我们可能需要使用此包中包含的cdrecord CLI 程序来避免维护额外的代码库:

     PS> cdrecord -scanbus # Show <drive> IDs to choose from PS> cdrecord -fix dev=<drive> # Close an open session

    As a brief starting point, here's how we can finalize a multi-session disc:作为一个简短的起点,以下是我们如何完成多区段光盘:

     PS> $session = cdrecord -msinfo dev=<drive> PS> mkisofs -rJ -C $session -M <drive> 'path\\to\\root' | cdrecord dev=<drive> -

    This achieves the same result as our PowerShell script that uses the IMAPI: we import the last session, create the image, and then burn a new session which finalizes the disc.这实现了与使用 IMAPI 的 PowerShell 脚本相同的结果:我们导入最后一个会话,创建映像,然后刻录一个新会话来完成光盘。 By omitting the -multi argument to cdrecord , the command won't write the lead-in in a way that allows for continuation of a multi-session disc.通过省略cdrecord-multi参数,该命令不会以允许连续多会话光盘的方式写入导入。

    While we typically see this toolset on Unix-like systems, builds are available for Windows.虽然我们通常在类 Unix 系统上看到此工具集,但构建可用于 Windows。

  • For more advanced applications, we can use an implementation of the lower-level IDiscRecorderEx to query and send commands to the recording device.对于更高级的应用程序,我们可以使用较低级别的IDiscRecorderEx来查询并向记录设备发送命令。

Set the ForceMediaToBeClosed flag on the IMAPI2.MsftDiscFormat2Data object and write out the disc with the close flag enabled.IMAPI2.MsftDiscFormat2Data对象上设置ForceMediaToBeClosed标志,并在启用关闭标志的情况下写出光盘。

  • If you already know its your last session, set the flag, add your data to write and then write it out and it will close.如果您已经知道它的最后一个会话,请设置标志,添加要写入的数据,然后将其写出,它就会关闭。
  • If you have already written your last session, import the last session, set the flag and write to close.如果您已经编写了最后一个会话,请导入最后一个会话,设置标志并写入关闭。

Approach is described here: https://social.msdn.microsoft.com/Forums/en-US/ce1ff136-39a1-4442-bc5c-61c119b6f4f2/finalize-question?forum=windowsopticalplatform#2e968a94-7347-4d94-9332-00fe7cd0ba89方法在这里描述: https : //social.msdn.microsoft.com/Forums/en-US/ce1ff136-39a1-4442-bc5c-61c119b6f4f2/finalize-question?forum=windowsopticalplatform#2e968a94-7347-4d94-ba09322

Below is a link to a nice Powershell burning script, all you'd have to do is update Out-CD with a new param to set $DiscFormatData.ForceMediaToBeClosed = true when you are ready for your closing write.下面是一个很好的 Powershell 刻录脚本的链接,当您准备好结束写入时,您所要做的就是使用新param更新Out-CD以设置$DiscFormatData.ForceMediaToBeClosed = true

Link: https://www.adamtheautomator.com/use-powershell-to-automate-burning-cds/链接: https : //www.adamtheautomator.com/use-powershell-to-automate-burning-cds/

FYI:供参考:

# this fetches all the properties (as you probably already know)
$DiscFormatData  = New-Object -com IMAPI2.MsftDiscFormat2Data ;
$DiscFormatData | Get-Member ;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM