如何使用 IMAPI 异步写入 CD/DVD?

Posted

技术标签:

【中文标题】如何使用 IMAPI 异步写入 CD/DVD?【英文标题】:How to asynchronously write CD/DVD using IMAPI? 【发布时间】:2019-08-11 22:16:48 【问题描述】:

有人告诉我编写一个软件来根据用户的选择同步/异步刻录 CD。我在项目中使用带有 C# 的 IMAPIv2,它没有明确提供异步写入数据的功能。

为了设计功能,我研究了在线资源,但没有成功。

谁能解释一下什么是同步/异步 I/O,就在光盘上刻录映像而言?

感谢任何帮助。

【问题讨论】:

如果我们希望程序在将数据写入光盘时执行其他操作,例如更新 UI 中的状态/进度,我们希望异步刻录 CD。我不确定您使用的是哪种语言。在 C++ 或 C# 中,这通常意味着在一个单独的线程中写入磁盘,而主线程处理用户交互。在this PowerShell example 中,这可能意味着使用Start-Job cmdlet 添加一些将$disc.Write() 包装到后台作业中的代码。 【参考方案1】:

IMAPI 不提供异步写入数据的内置类/方法。但它被设计成一种可以使用任何支持异步编程的技术的方式。您正在使用的那个(您在 cmets 中提到的 C#)确实支持它。

IMAPI 公开了那些报告进度和操作状态的接口。您需要做的就是使用线程异步运行活动;这将释放您的 UI,您可以执行其他活动。然后,您可以订阅向您报告状态的事件。

请参阅 CodeProject 上的 this 项目,该项目使用 BackgroundWorker 相同:

多线程

刻录或格式化媒体可能需要一些时间,因此我们不希望在主 UI 线程上执行这些操作。我使用BackgroundWorker 类来处理这些冗长任务的多线程。 BackgroundWorker 类允许您在线程中设置值,然后调用ReportProgress 方法,该方法在调用线程中触发ProgressChanged 事件。当您完成工作线程时,它会触发 RunWorkerCompleted 事件以通知调用线程它已完成。

以下是DoWorkUpdate 事件:

private void backgroundBurnWorker_DoWork(object sender, DoWorkEventArgs e)

    MsftDiscRecorder2 discRecorder = null;
    MsftDiscFormat2Data discFormatData = null;

   try
    
        //
        // Create and initialize the IDiscRecorder2 object
        //
        discRecorder = new MsftDiscRecorder2();
        var burnData = (BurnData)e.Argument;
        discRecorder.InitializeDiscRecorder(burnData.uniqueRecorderId);

       //
        // Create and initialize the IDiscFormat2Data
        //
        discFormatData = new MsftDiscFormat2Data
            
                Recorder = discRecorder,
                ClientName = ClientName,
                ForceMediaToBeClosed = _closeMedia
            ;

       //
        // Set the verification level
        //
        var burnVerification = (IBurnVerification)discFormatData;
        burnVerification.BurnVerificationLevel = _verificationLevel;

       //
        // Check if media is blank, (for RW media)
        //
        object[] multisessionInterfaces = null;
        if (!discFormatData.MediaHeuristicallyBlank)
        
            multisessionInterfaces = discFormatData.MultisessionInterfaces;
        

       //
        // Create the file system
        //
        IStream fileSystem;
        if (!CreateMediaFileSystem(discRecorder, multisessionInterfaces, out fileSystem))
        
            e.Result = -1;
            return;
        

       //
        // add the Update event handler
        //
        discFormatData.Update += discFormatData_Update;

       //
        // Write the data here
        //
        try
        
            discFormatData.Write(fileSystem);
            e.Result = 0;
        
        catch (COMException ex)
        
            e.Result = ex.ErrorCode;
            MessageBox.Show(ex.Message, "IDiscFormat2Data.Write failed",
                MessageBoxButtons.OK, MessageBoxIcon.Stop);
        
        finally
        
            if (fileSystem != null)
            
                Marshal.FinalReleaseComObject(fileSystem);
            
        

       //
        // remove the Update event handler
        //
        discFormatData.Update -= discFormatData_Update;

       if (_ejectMedia)
        
            discRecorder.EjectMedia();
        
    
    catch (COMException exception)
    
        //
        // If anything happens during the format, show the message
        //
        MessageBox.Show(exception.Message);
        e.Result = exception.ErrorCode;
    
    finally
    
        if (discRecorder != null)
        
            Marshal.ReleaseComObject(discRecorder);
        

       if (discFormatData != null)
        
            Marshal.ReleaseComObject(discFormatData);
        
    


void discFormatData_Update([In, MarshalAs(UnmanagedType.IDispatch)] object sender,
                           [In, MarshalAs(UnmanagedType.IDispatch)] objectprogress)

    //
    // Check if we've cancelled
    //
    if (backgroundBurnWorker.CancellationPending)
    
        var format2Data = (IDiscFormat2Data)sender;
        format2Data.CancelWrite();
        return;
    

   var eventArgs = (IDiscFormat2DataEventArgs)progress;

   _burnData.task = BURN_MEDIA_TASK.BURN_MEDIA_TASK_WRITING;

   // IDiscFormat2DataEventArgs Interface
    _burnData.elapsedTime = eventArgs.ElapsedTime;
    _burnData.remainingTime = eventArgs.RemainingTime;
    _burnData.totalTime = eventArgs.TotalTime;

   // IWriteEngine2EventArgs Interface
    _burnData.currentAction = eventArgs.CurrentAction;
    _burnData.startLba = eventArgs.StartLba;
    _burnData.sectorCount = eventArgs.SectorCount;
    _burnData.lastReadLba = eventArgs.LastReadLba;
    _burnData.lastWrittenLba = eventArgs.LastWrittenLba;
    _burnData.totalSystemBuffer = eventArgs.TotalSystemBuffer;
    _burnData.usedSystemBuffer = eventArgs.UsedSystemBuffer;
    _burnData.freeSystemBuffer = eventArgs.FreeSystemBuffer;

   //
    // Report back to the UI
    //
    backgroundBurnWorker.ReportProgress(0, _burnData);


【讨论】:

以上是关于如何使用 IMAPI 异步写入 CD/DVD?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 IMAPI2 检索和设置刻录速度?

IMAPI:如果图像大小超过可用空间,如何获取图像大小而不抛出异常?

Windows XP 上的 IMAPI2 错误

IMAPI界面可以选择刻录模式吗?

在 Windows XP 中使用 .NET 刻录 DVD 需要哪些基本 COM 组件?

如何在使用 IMAPI 创建的 ISO 文件中显式创建目录结构?