Есть ли относительно простой способ для завершения CD или DVD в С# или PowerShell?

Во-первых, некоторые разъяснения терминов. По финализировать я не подразумеваю закрытие сеанса; Я имею в виду написать вывод на CD или DVD таким образом, что информация больше не может быть добавлена ​​к нему обычными средствами (Roxio, Nero, Windows Explorer и т.д.).

Я провел много исследований по этому вопросу. Есть некоторые программы с открытым исходным кодом, такие как InfraRecorder, из которых мы могли бы нарисовать некоторое вдохновение, но все они, похоже, содержат довольно сложные строки С++ код с использованием IMAPI, который выглядит как очень низкоуровневый способ делать что-то. Никто из нас не обладает опытом С++ или IMAPI для поддержки такой базы кода.

Самый многообещающий ресурс в Интернете выглядит этот, но, похоже, он не включает функцию финализации. Вот код, который "пишет изображение":

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

Но это не функция финализации; это функция, которая записывает фактические данные на диск. Вам нужно создать новый сеанс для завершения финализации на существующем диске?

Ответ 1

Свойство ForceMediaToBeClosed IDiscFormat2Data определяет, завершает ли IMAPI диск после следующей записи:

Установите значение VARIANT_TRUE, чтобы пометить диск как закрытый, чтобы запретить дополнительные записи при завершении следующего сеанса записи.

API-интерфейс Image Mastering API не обеспечивает абстракции, используемой специально для завершения диска, поэтому нам нужно выполнить операцию записи. API завершит чистый диск во время первоначального ожога, если мы включим ForceMediaToBeClosed с основным устройством записи изображений. Для существующего многосеансового диска нам нужно добавить еще один сеанс.

Вот простой пример PowerShell, который мы можем попробовать, поэтому нам не нужно создавать проект. Понятия аналогичны в С#:

$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, которые соответствуют "пустым" или "добавочным" битмаскам (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 ( "защищенные от записи" ) и 0x8000 ( "неподдерживаемый носитель" ). Нам может потребоваться выгрузить или сработать некоторое количество аппаратного обеспечения, чтобы увидеть точные значения после записи.

Примечания:

  • В общем, каждый сеанс на многосеансовом диске начинается с ввода и заканчивается выводом. Ввод последней сессии постоянно закрывает носитель для дальнейшей записи, когда мы завершаем диск. Вот почему нам нужно добавить дополнительный сеанс к закрытому диску, даже если у нас больше нет данных для добавления.

  • IMAPI автоматически завершит создание диска, если свободное пространство опустится ниже 2%.

  • InfraRecorder - средство, упомянутое в вопросе – не использует IMAPI. Это приложение предоставляет интерфейс cdrtools, который напрямую управляет IO устройства. Если нам просто нужно завершить закрытые диски, мы можем использовать программу cdrecord, включенную в этот пакет, чтобы избежать сохранение дополнительной базы кода:

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

    Это дает тот же результат, что и наш PowerShell script, который использует IMAPI: мы импортируем последний сеанс, создаем образ и затем записываем новый сеанс, который завершает работу с диском. Опуская аргумент -multi в cdrecord, команда не будет записывать ввод в файл таким образом, чтобы разрешить продолжение многосеансового диска.

    Хотя мы обычно видим этот набор инструментов в Unix-подобных системах, сборки доступны для Windows.

  • Для более сложных приложений мы можем использовать реализацию IDiscRecorderEx нижнего уровня для запроса и отправки команд на записывающее устройство.

Ответ 2

Установите флаг 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 script, все, что вам нужно сделать, это обновить Out-CD с помощью нового param, чтобы установить $DiscFormatData.ForceMediaToBeClosed = true, когда вы будете готовы к вашей заключительной записи.

Ссылка: 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 ;