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.)
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 the developers on our team 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?
The
ForceMediaToBeClosed
property ofIDiscFormat2Data
controls whether the IMAPI finalizes the disc after the next write: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.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#:
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.
At this point, if we check the status of a blank or open disc, we should see a value of
2
,4
, or6
which correspond to the "blank" or "appendable" bitmasks (6
for both) enumerated onIMAPI_FORMAT2_DATA_MEDIA_STATE
.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.
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:If we inspect the disc status now, it should indicate that the disc is not writable:
For a single-session disc, we should see
16384
(0x4000
, "finalized"). My system reports40960
for closed, multi-session discs which contains the bits0x2000
("write-protected") and0x8000
("unsupported media"). 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%.
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:
As a brief starting point, here's how we can finalize a multi-session disc:
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.While we typically see this toolset on Unix-like systems, builds are available for Windows.
For more advanced applications, we can use an implementation of the lower-level
IDiscRecorderEx
to query and send commands to the recording device.