如何使用 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
事件以通知调用线程它已完成。
以下是DoWork
和Update
事件:
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?的主要内容,如果未能解决你的问题,请参考以下文章
IMAPI:如果图像大小超过可用空间,如何获取图像大小而不抛出异常?