有没有一种相对简单的方法可以在C#或PowerShell中完成CD或DVD的定型? [英] Is there a relatively straightforward way to finalize a CD or DVD in C# or PowerShell?

查看:160
本文介绍了有没有一种相对简单的方法可以在C#或PowerShell中完成CD或DVD的定型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

首先,对术语进行一些澄清. 最终确定,我的意思不是结束会议.我的意思是将引导写到CD或DVD,这样就不再可以通过通常的方式(Roxio,Nero,Windows资源管理器等)将信息添加到其中.

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.)

我对此进行了大量研究.我们可以从中获得一些启发性的开源程序,例如 InfraRecorder ,但它们似乎都包含了相当详尽的内容大量使用IMAPI的C ++代码,这似乎是一种非常底层的处理方式.我们谁都没有C ++或IMAPI专业知识来支持这样的代码库.

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. None of us have the C++ or IMAPI expertise to support such a code base.

互联网上最有希望的资源似乎是

The most promising resource on the internet appears to be this one, but it doesn't seem to include a finalize function. 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; 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?

推荐答案

IDiscFormat2DataForceMediaToBeClosed属性

设置为VARIANT_TRUE可将光盘标记为已关闭,以在下一个写会话结束时禁止进行其他写操作.

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将在初始刻录过程中最终确定一张空白光盘.对于现有的多会话光盘,我们需要追加另一个会话.

The Image Mastering API does not provide an abstraction used specifically to finalize the disc, so we need to perform a write operation. The API will finalize a blank disc during the initial burn if we switch on ForceMediaToBeClosed with the main image writer. For an existing multi-session disc, we need to append another session.

这是我们可以尝试的一个简单的PowerShell示例,因此我们不需要构建项目.这些概念在C#中相似:

Here's a simple PowerShell example that we can try so we don't need to build the project. The concepts are similar in 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对象.

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.

在这一点上,如果我们检查空白光盘或打开的光盘的状态,我们应该看到与2,46值(两者均6)在 IMAPI_FORMAT2_DATA_MEDIA_STATE

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.

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

然后,我们可以添加一些文件.如果我们只想关闭多区段光盘,则无需在映像中添加任何内容. API使用空数据轨道记录会话的导入和导出.

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.

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

最后,我们将所做的更改刻录到光盘上.因为我们将$disc.ForceMediaToBeClosed设置为$true,所以此操作将最终化光盘,并且不允许进行进一步的写操作:

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:

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

对于单会话光盘,我们应该看到16384(0x4000,已完成").对于封闭的多区段光盘,我的系统报告40960,其中包含位0x2000(写保护")和0x8000(不受支持的媒体").刻录后,我们可能需要弹出某些硬件或对这些硬件重新通电,以查看准确的值.

For a single-session disc, we should see 16384 (0x4000, "finalized"). My system reports 40960 for closed, multi-session discs which contains the bits 0x2000 ("write-protected") and 0x8000 ("unsupported media"). We may need to eject or power-cycle some hardware to see accurate values after burning.

备注:

  • 通常,多区段光盘上的每个区段都以引入为起点,以引出为结束.当我们完成光盘刻录时,最后一个会话的导入将永久关闭媒体以进行进一步写入.这就是为什么即使我们没有更多数据要添加,我们也需要在未关闭的光盘上附加一个会话.

  • 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.

如果可用空间降到2%以下,IMAPI将自动定版光盘.

IMAPI will automatically finalize a disc if the free space drops below 2%.

InfraRecorder—问题中提到的工具不使用IMAPI.此应用程序提供了 cdrtools 的前端,该前端可直接控制设备IO.如果我们只需要敲定未封闭的光盘,则可以使用 cdrecord 此软件包随附的CLI程序,以避免维护额外的代码库:

InfraRecorder—the tool mentioned in the question—does not use the IMAPI. This application provides a frontend to cdrtools which controls the device IO directly. 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:

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> -

这将获得与使用IMAPI的PowerShell脚本相同的结果:我们导入最后一个会话,创建映像,然后刻录一个新会话以最终确定光盘.通过省略 cdrecord -multi参数,该命令将不会以允许继续使用多会话光盘的方式来编写导入文件.

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. 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.

虽然我们通常在类似Unix的系统上看到此工具集,但构建可用 Windows.

While we typically see this toolset on Unix-like systems, builds are available for Windows.

对于更高级的应用程序,我们可以使用较低级别的 IDiscRecorderEx 来查询并将命令发送到记录设备.

For more advanced applications, we can use an implementation of the lower-level IDiscRecorderEx to query and send commands to the recording device.

这篇关于有没有一种相对简单的方法可以在C#或PowerShell中完成CD或DVD的定型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆