一.背景介绍
最近公司一个老项目需要添加导出数据到光盘的功能.开始对这功能添加有点抵触的.光盘?都啥年代了.
光盘一种即将淘汰的存储媒介.就像当年的随身听,Mp3,Mp4一样,即将退出历史舞台.领导让加,发牢骚归发牢骚,活还是得干哈.
从网上找了一些资料,都是特别古老的文档了.很多方法用起来并不是特别的方便.
1.CodePlex Archive https://archive.codeplex.com/?p=csimapi2samples 其中的例子功能不全,参数都使用dynamic类型,刚开始不了解那些基础概念时,理解起来比较难.可以参考学习.
2.博客:https://blog.csdn.net/huanghunjiuba/article/details/12967463 中的例子BurnCdDemo.
里面的BurnCdDemo对ImApi2做了封装.其实例子里面的封装做的挺不错的.注释也特别全.
在做测试的时候发现刻录功能在本机运行的非常好.在公司的测试机上却获取不到光盘大小,取到的大小是负数.对着Demo的源代码检查了半天,没找到原因.╮( ̄▽ ̄")╭,脑袋好大的.后来找到原因了,在下面的过程中会描述下.
PS:个人不喜欢啥都做抽象.抽象,意味着要多写代码,查找问题也不方便.抽象,依赖注入,控制反转是个好东西,就是要多写许多代码.
个人觉得,很多技术还是要看实际项目情况而使用,没有必要去为了追求使用而滥用.看起来高大上,实际多写了代码维护也不方便.
So,自己搞个简单点的.因为就那么几个功能:获取光驱设备列表,获取光盘信息,添加媒体文件,刻录,进度通知.
二.工欲善其事必先利其器
因工作电脑没有光驱,测试非常不方便.那我们就安装一个虚拟光驱.
推荐一个比较好用的虚拟光驱软件PhantomBurner,带注册码.下载地址:https://download.csdn.net/download/zjhaag/10909339
安装过程就不说了.选下安装路径,一路Next.安装完成后提示重启.其实不重启也可以用.
安装完成后界面如下.在About中输入注册码激活.点击Create,选择Dvd+RW创建Virtual Disc Image.在资源管理器中就可以看到我们创建的虚拟光驱了.
三.开工
1.设备列表获取
(1)首先添加一个RecorderHelper.在RecorderHelper类中添加一个静态方法GetRecorderList用于获取光驱设备列表.

1 /// <summary> 2 /// 获取光驱设备列表 3 /// </summary> 4 /// <returns></returns> 5 public static List<Recorder> GetRecorderList() 6 { 7 List<Recorder> recordList = new List<Recorder>(); 8 9 // Create a DiscMaster2 object to connect to optical drives. 10 MsftDiscMaster2 discMaster = new MsftDiscMaster2(); 11 for (int i = 0; i < discMaster.Count; i++) 12 { 13 if (discMaster[i] != null) 14 { 15 Recorder recorder = new Recorder(discMaster[i]); 16 recordList.Add(recorder); 17 } 18 } 19 return recordList; 20 }
此时,需要Recorder光驱对象主要属性如下

1 MsftDiscRecorder2 msRecorder = null; //Recorder 2 3 /// <summary> 4 /// 当前磁盘标签 5 /// </summary> 6 public string RecorderName { get; private set; } 7 8 /// <summary> 9 /// 是否支持当前刻录机 10 /// </summary> 11 public bool IsRecorderSupported { get; private set; } 12 13 /// <summary> 14 /// 是否支持当前磁盘媒体 15 /// </summary> 16 public bool IsCurrentMediaSupported { get; private set; } 17 18 /// <summary> 19 /// 当前磁盘可用大小 20 /// </summary> 21 public long FreeDiskSize { get; private set; } 22 23 /// <summary> 24 /// 当前磁盘总大小 25 /// </summary> 26 public long TotalDiskSize { get; private set; } 27 28 /// <summary> 29 /// 当前媒体状态 30 /// </summary> 31 public IMAPI_FORMAT2_DATA_MEDIA_STATE CurMediaState { get; private set; } 32 33 /// <summary> 34 /// 当前媒体状态 35 /// </summary> 36 public string CurMediaStateName { get; private set; } 37 38 /// <summary> 39 /// 当前媒体类型 40 /// </summary> 41 public IMAPI_MEDIA_PHYSICAL_TYPE CurMediaType { get; private set; } 42 43 /// <summary> 44 /// 当前媒体类型 45 /// </summary> 46 public string CurMediaTypeName { get; private set; } 47 48 /// <summary> 49 /// 是否可以刻录 50 /// </summary> 51 public bool CanBurn {get;private set;}
(2)对Recorder各属性进行初始化,赋值.主要方法如下

1 /// <summary> 2 /// Recorder Ctor 3 /// </summary> 4 /// <param name="uniqueId">标识Id</param> 5 public Recorder(string uniqueId) 6 { 7 this.uniqueId = uniqueId; 8 msRecorder = new MsftDiscRecorder2(); 9 msRecorder.InitializeDiscRecorder(uniqueId); 10 InitRecorder(); 11 12 this.BurnMediaList = new List<BurnMedia>(); 13 this.BurnMediaFileSize = 0; 14 } 15 16 /// <summary> 17 /// 初始化Recorder 18 /// 更新Recorder信息,更新光盘后可重试. 19 /// </summary> 20 public void InitRecorder() 21 { 22 try 23 { 24 if (msRecorder.VolumePathNames != null && msRecorder.VolumePathNames.Length > 0) 25 { 26 foreach (object mountPoint in msRecorder.VolumePathNames) 27 { //挂载点 取其中一个 28 RecorderName = mountPoint.ToString(); 29 break; 30 } 31 } 32 // Define the new disc format and set the recorder 33 MsftDiscFormat2Data dataWriter = new MsftDiscFormat2Data(); 34 dataWriter.Recorder = msRecorder; 35 36 if (!dataWriter.IsRecorderSupported(msRecorder)) 37 { 38 return; 39 } 40 if (!dataWriter.IsCurrentMediaSupported(msRecorder)) 41 { 42 return; 43 } 44 if (dataWriter.FreeSectorsOnMedia >= 0) 45 { //可用大小 46 FreeDiskSize = dataWriter.FreeSectorsOnMedia * 2048L; 47 } 48 49 if (dataWriter.TotalSectorsOnMedia >= 0) 50 { //总大小 51 TotalDiskSize = dataWriter.TotalSectorsOnMedia * 2048L; 52 } 53 CurMediaState = dataWriter.CurrentMediaStatus; //媒体状态 54 CurMediaStateName = RecorderHelper.GetMediaStateName(CurMediaState); 55 CurMediaType = dataWriter.CurrentPhysicalMediaType; //媒介类型 56 CurMediaTypeName = RecorderHelper.GetMediaTypeName(CurMediaType); 57 CanBurn = RecorderHelper.GetMediaBurnAble(CurMediaState); //判断是否可刻录 58 } 59 catch (COMException ex) 60 { 61 string errMsg = ex.Message.Replace("\r\n", ""); //去掉异常信息里的\r\n 62 this.CurMediaStateName = $"COM Exception:{errMsg}"; 63 } 64 catch (Exception ex) 65 { 66 this.CurMediaStateName = $"{ex.Message}"; 67 } 68 }
(3)测试代码如下

1 #region 查找光驱设备 2 Console.Clear(); 3 Console.WriteLine("正在查找光驱设备.."); 4 List<Recorder> recorderList = RecorderHelper.GetRecorderList(); 5 if (recorderList.Count <= 0) 6 { 7 Console.WriteLine("没有可以使用的光驱,请检查."); 8 Console.WriteLine("请连接光驱后,按任意键重试..."); 9 Console.ReadKey(); 10 continue; 11 } 12 for (int i = 0; i < recorderList.Count; i++) 13 { 14 Recorder tempRecorder = recorderList[i]; 15 Console.WriteLine($"发现光驱设备:[{i+1}] {tempRecorder.RecorderName}"); 16 Console.WriteLine($"媒体类型:{tempRecorder.CurMediaTypeName}"); 17 Console.WriteLine($"媒体状态:{tempRecorder.CurMediaStateName}"); 18 Console.WriteLine("支持刻录:" + (tempRecorder.CanBurn ? "√" : "×")); 19 Console.WriteLine($"可用大小:{FormatFileSize(tempRecorder.FreeDiskSize)}"); 20 Console.WriteLine($"总大小:{FormatFileSize(tempRecorder.TotalDiskSize)}"); 21 } 22 if (!recorderList.Any(r=>r.CanBurn)) 23 { 24 Console.WriteLine("没有可以用于刻录的光驱设备,请检查后,按任意键重试."); 25 Console.ReadKey(); 26 continue; 27 } 28 #endregion
测试结果:
至此,我们完成了对于光驱设备列表的获取及Recorder对象各属性的初始化工作.
说明下,对光驱设备操作需要有管理员权限,没有管理员权限会导致获取失败.对于C#应用程序设置以管理员身份启动请参照https://www.cnblogs.com/babycool/p/3569183.html
2.添加刻录文件
(1)我们为Recorder对象添加待刻录媒体对象列表和待刻录媒体文件大小两个属性

1 /// <summary> 2 /// 待刻录媒体对象List 3 /// </summary> 4 public List<BurnMedia> BurnMediaList {get;set;} 5 6 /// <summary> 7 /// 待刻录媒体文件大小 8 /// </summary> 9 public long BurnMediaFileSize { get; set; }
待刻录媒体对象定义如下

1 /// <summary> 2 /// 刻录媒体 3 /// </summary> 4 public class BurnMedia 5 { 6 /// <summary> 7 /// 路径 8 /// </summary> 9 public string MediaPath { get; set; } 10 11 /// <summary> 12 /// 名称 13 /// </summary> 14 public string MediaName { get; set; } 15 16 /// <summary> 17 /// 是否是文件夹 18 /// </summary> 19 public bool IsDirectory { get; set; } 20 21 /// <summary> 22 /// 大小 23 /// </summary> 24 public long Size { get; set; } 25 }
(2)为Recorder对象添加AddBurnMedia方法

1 /// <summary> 2 /// 添加刻录媒体对象 3 /// </summary> 4 public BurnMedia AddBurnMedia(string path) 5 { 6 BurnMedia media = null; 7 if(string.IsNullOrEmpty(path)) 8 { 9 throw new Exception("文件路径不能为空."); 10 } 11 if(!CanBurn) 12 { 13 throw new Exception("当前磁盘状态不支持刻录."); 14 } 15 media = new BurnMedia(); 16 long fileSize = 0; 17 if (Directory.Exists(path)) 18 { 19 DirectoryInfo dirInfo = new DirectoryInfo(path); 20 fileSize = GetDirectorySize(path); 21 media.MediaName = dirInfo.Name; 22 media.MediaPath = dirInfo.FullName; 23 media.Size = fileSize; 24 media.IsDirectory = true; 25 } 26 else if (File.Exists(path)) 27 { 28 FileInfo fileInfo = new FileInfo(path); 29 fileSize = fileInfo.Length; 30 media.MediaName = fileInfo.Name; 31 media.MediaPath = fileInfo.FullName; 32 media.Size = fileSize; 33 media.IsDirectory = false; 34 } 35 else 36 { 37 throw new Exception("文件不存在"); 38 } 39 if (BurnMediaFileSize + fileSize >= FreeDiskSize) 40 { 41 throw new Exception("剩余空间不足"); 42 } 43 if (BurnMediaList.Any(m => m.MediaName.ToLower() == media.MediaName.ToLower())) 44 { 45 throw new Exception($"已存在媒体名称为{media.MediaName}的对象"); 46 } 47 BurnMediaList.Add(media); 48 BurnMediaFileSize += fileSize; 49 return media; 50 }
(3)测试代码如下

1 while (true) 2 { 3 Console.WriteLine("添加文件:请输入待刻录文件或文件夹路径. 0完成 1查看已添加文件"); 4 string filePath = Console.ReadLine(); 5 if (string.IsNullOrEmpty(filePath)) 6 { 7 continue; 8 } 9 else if (filePath == "0") 10 { 11 break; 12 } 13 else if (filePath == "1") 14 { 15 ShowBurnMediaListInfo(recorder); 16 } 17 else 18 { 19 try 20 { 21 BurnMedia media = recorder.AddBurnMedia(filePath); 22 Console.WriteLine($"添加成功:{filePath}"); 23 Console.WriteLine("文件大小:" + FormatFileSize(media.Size)); 24 Console.WriteLine("已添加文件总大小:" + FormatFileSize(recorder.BurnMediaFileSize)); 25 } 26 catch (Exception ex) 27 { 28 Console.WriteLine($"添加失败:{ex.Message}"); 29 } 30 } 31 }
运行结果:
3.刻录及刻录进度通知
为Recorder对象添加Burn方法.同时,添加刻录进度通知.
(1)添加BurnProgressChanged委托用于通知刻录进度

1 /// <summary> 2 /// 刻录进度delegate 3 /// </summary> 4 public delegate void BurnProgressChanged(BurnProgress burnProgress);
刻录进度通知对象定义如下(其属性为根据需求添加):

1 /// <summary> 2 /// 刻录进度对象 3 /// </summary> 4 public class BurnProgress 5 { 6 /// <summary> 7 /// 当前操作 8 /// 对应IMAPI2.IMAPI_FORMAT2_DATA_WRITE_ACTION枚举 9 /// 4 正在写入数据 5完成数据写入 6 刻录完成 10 /// </summary> 11 public int CurrentAction { get; set; } 12 13 /// <summary> 14 /// 当前操作Name 15 /// </summary> 16 public string CurrentActionName { get; set; } 17 18 /// <summary> 19 /// 已用时间单位S 20 /// </summary> 21 public int ElapsedTime { get; set; } 22 23 /// <summary> 24 /// 预计总时间单位S 25 /// </summary> 26 public int TotalTime { get; set; } 27 28 /// <summary> 29 /// 数据写入进度 30 /// </summary> 31 public decimal Percent { get; set; } 32 33 /// <summary> 34 /// 数据写入进度% 35 /// </summary> 36 public string PercentStr { get { return Percent.ToString("0.00%"); } } 37 }
(2)为Recorder对象添加委托属性

1 /// <summary> 2 /// 刻录进度变化通知 3 /// </summary> 4 public BurnProgressChanged OnBurnProgressChanged { get; set; }
(3)为Recorder添加Burn方法

1 /// <summary> 2 /// 刻录 3 /// </summary> 4 public void Burn(string diskName = "SinoUnion") 5 { 6 if(!CanBurn) 7 { 8 throw new Exception("当前磁盘状态不支持刻录"); 9 } 10 if (string.IsNullOrEmpty(diskName)) 11 { 12 throw new Exception("DiskName不能为空"); 13 } 14 if (BurnMediaList.Count <= 0) 15 { 16 throw new Exception("待刻录文件列表不能为空"); 17 } 18 if(BurnMediaFileSize<=0) 19 { 20 throw new Exception("待刻录文件大小为0"); 21 } 22 23 try 24 { //说明 25 //1.fsi.ChooseImageDefaults用的是IMAPI2FS的,我们定义的msRecorder是IMAPI2的.所以必须用动态类型 26 //2.dataWriter也要使用动态类型,要不然Update事件会出异常. 27 // Create an image stream for a specified directory. 28 dynamic fsi = new IMAPI2FS.MsftFileSystemImage(); // Disc file system 29 IMAPI2FS.IFsiDirectoryItem dir = fsi.Root; // Root directory of the disc file system 30 dynamic dataWriter = new MsftDiscFormat2Data(); //Create the new disc format and set the recorder 31 32 dataWriter.Recorder = msRecorder; 33 dataWriter.ClientName = "SinoGram"; 34 //不知道这方法不用行不行.用的参数是IMAPI2FS的. 35 //所以学官网的例子,把fsi改成了动态的.使用msRecorder作为参数 36 fsi.ChooseImageDefaults(msRecorder); 37 38 //设置相关信息 39 fsi.VolumeName = diskName; //刻录磁盘名称 40 for (int i = 0; i < BurnMediaList.Count; i++) 41 { 42 dir.AddTree(BurnMediaList[i].MediaPath, true); 43 } 44 // Create an image from the file system 45 IStream stream = fsi.CreateResultImage().ImageStream; 46 try 47 { 48 dataWriter.Update += new DDiscFormat2DataEvents_UpdateEventHandler(BurnProgressChanged); 49 dataWriter.Write(stream);// Write stream to disc 50 } 51 catch (System.Exception ex) 52 { 53 throw ex; 54 } 55 finally 56 { 57 if (stream != null) 58 { 59 Marshal.FinalReleaseComObject(stream); 60 } 61 } 62 } 63 catch (Exception ex) 64 { 65 Console.WriteLine($"刻录失败:{ex.Message}"); 66 } 67 } 68 69 /// <summary> 70 /// 刻录进度通知 71 /// </summary> 72 /// <param name="object"></param> 73 /// <param name="progress"></param> 74 void BurnProgressChanged(dynamic @object, dynamic progress) 75 { 76 BurnProgress burnProgress = new BurnProgress(); 77 try 78 { 79 burnProgress.ElapsedTime = progress.ElapsedTime; 80 burnProgress.TotalTime = progress.TotalTime; 81 burnProgress.CurrentAction = progress.CurrentAction; 82 if (burnProgress.ElapsedTime > burnProgress.TotalTime) 83 { //如果已用时间已超过预估总时间.则将预估总时间设置为已用时间 84 burnProgress.TotalTime = burnProgress.ElapsedTime; 85 } 86 string strTimeStatus; 87 strTimeStatus = "Time: " + progress.ElapsedTime + " / " + progress.TotalTime; 88 int currentAction = progress.CurrentAction; 89 switch (currentAction) 90 { 91 case (int)IMAPI2.IMAPI_FORMAT2_DATA_WRITE_ACTION.IMAPI_FORMAT2_DATA_WRITE_ACTION_CALIBRATING_POWER: 92 burnProgress.CurrentActionName = "Calibrating Power (OPC)"; 93 break; 94 case (int)IMAPI2.IMAPI_FORMAT2_DATA_WRITE_ACTION.IMAPI_FORMAT2_DATA_WRITE_ACTION_COMPLETED: 95 burnProgress.CurrentActionName = "Completed the burn"; 96 burnProgress.Percent = 1; 97 burnProgress.TotalTime = burnProgress.ElapsedTime; //刻录完成,将预估用时,修正为已用时间 98 break; 99 case (int)IMAPI2.IMAPI_FORMAT2_DATA_WRITE_ACTION.IMAPI_FORMAT2_DATA_WRITE_ACTION_FINALIZATION: 100 burnProgress.CurrentActionName = "Finishing the writing"; 101 burnProgress.Percent = 1; 102 burnProgress.TotalTime = burnProgress.ElapsedTime; //写入完成,将预估用时,修正为已用时间 103 break; 104 case (int)IMAPI2.IMAPI_FORMAT2_DATA_WRITE_ACTION.IMAPI_FORMAT2_DATA_WRITE_ACTION_FORMATTING_MEDIA: 105 burnProgress.CurrentActionName = "Formatting media"; 106 break; 107 case (int)IMAPI2.IMAPI_FORMAT2_DATA_WRITE_ACTION.IMAPI_FORMAT2_DATA_WRITE_ACTION_INITIALIZING_HARDWARE: 108 burnProgress.CurrentActionName = "Initializing Hardware"; 109 break; 110 case (int)IMAPI2.IMAPI_FORMAT2_DATA_WRITE_ACTION.IMAPI_FORMAT2_DATA_WRITE_ACTION_VALIDATING_MEDIA: 111 burnProgress.CurrentActionName = "Validating media"; 112 break; 113 case (int)IMAPI2.IMAPI_FORMAT2_DATA_WRITE_ACTION.IMAPI_FORMAT2_DATA_WRITE_ACTION_VERIFYING: 114 burnProgress.CurrentActionName = "Verifying the data"; 115 break; 116 case (int)IMAPI2.IMAPI_FORMAT2_DATA_WRITE_ACTION.IMAPI_FORMAT2_DATA_WRITE_ACTION_WRITING_DATA: 117 dynamic totalSectors; 118 dynamic writtenSectors; 119 dynamic startLba; 120 dynamic lastWrittenLba; 121 totalSectors = progress.SectorCount; 122 startLba = progress.StartLba; 123 lastWrittenLba = progress.LastWrittenLba; 124 writtenSectors = lastWrittenLba - startLba; 125 burnProgress.CurrentActionName = "Writing data"; 126 burnProgress.Percent = Convert.ToDecimal(writtenSectors)/ Convert.ToDecimal(totalSectors); 127 break; 128 default: 129 burnProgress.CurrentActionName = "Unknown action"; 130 break; 131 } 132 } 133 catch (Exception ex) 134 { 135 burnProgress.CurrentActionName = ex.Message; 136 } 137 if (OnBurnProgressChanged != null) 138 { 139 OnBurnProgressChanged(burnProgress); 140 } 141 }
(4)测试代码如下

1 if (recorder.BurnMediaList.Count <= 0) 2 { 3 Console.WriteLine($"未添加任何刻录文件.已退出刻录过程."); 4 } 5 else 6 { 7 #region 刻录前确认 8 bool confirmBurn = false; 9 Console.Clear(); 10 ShowBurnMediaListInfo(recorder); 11 while (true) 12 { 13 Console.WriteLine(); 14 Console.ForegroundColor = ConsoleColor.DarkGreen;//设置颜色. 15 Console.WriteLine($"刻录过程一旦开始,终止可能会造成磁盘损坏.确认要开始刻录(y/n)?"); 16 Console.ForegroundColor = colorFore;//还原颜色. 17 string confirmStr = Console.ReadLine(); 18 if (confirmStr.ToLower() == "n") 19 { 20 break; 21 } 22 else if (confirmStr.ToLower() == "y") 23 { 24 confirmBurn = true; 25 break; 26 } 27 } 28 if (!confirmBurn) 29 { 30 Console.WriteLine($"本次刻录过程已退出"); 31 continue; 32 } 33 #endregion 34 Console.CursorVisible = false; //隐藏光标 35 ShowBurnProgressChanged(recorder); 36 recorder.Burn(); //刻录 37 Console.WriteLine(); 38 }
(5)输出刻录进度变化,添加ShowBurnProgressChanged方法
在查找如何输出进度数据的时候,看到了控制台输出进度条的功能.带颜色的还挺漂亮的,看到好的功能就想加到我们的项目里.

1 /// <summary> 2 /// 输出刻录进度通知 3 /// </summary> 4 /// <param name="recorder"></param> 5 static void ShowBurnProgressChanged(Recorder recorder) 6 { 7 Console.Clear(); 8 9 #region 搭建输出显示框架 10 Console.WriteLine(); 11 Console.WriteLine($"**********************刻录中,请稍候**********************"); 12 Console.WriteLine(); 13 Console.WriteLine(" 当前操作:"); //第4行当前操作 14 Console.WriteLine(); 15 16 // 第6行绘制进度条背景 17 Console.Write(" "); 18 Console.BackgroundColor = ConsoleColor.DarkCyan; 19 for (int i = 1; i <= 50; i++) 20 { //设置50*1的为总进度 21 Console.Write(" "); 22 } 23 24 Console.WriteLine(); 25 Console.BackgroundColor = colorBack; 26 27 Console.WriteLine(); //第7行输出空行 28 Console.WriteLine(); //第8行输出进度 29 Console.WriteLine($"*********************************************************"); //第9行 30 Console.WriteLine(); //第10行输出空行 31 #endregion 32 33 //进度变化通知时,更新相关行数据即可. 34 recorder.OnBurnProgressChanged += (burnProgress) => { 35 if (burnProgress.CurrentAction == 6) 36 { //刻录完成 37 Console.SetCursorPosition(0, 1); 38 Console.WriteLine($"*************************刻录完成************************"); 39 } 40 //第4行 当前操作 41 Console.SetCursorPosition(0, 3); 42 Console.Write($" 当前操作:{burnProgress.CurrentActionName}"); 43 Console.Write(" "); //填充空白区域 44 Console.ForegroundColor = colorFore; 45 46 // 第6行 绘制进度条进度(进度条前预留2空格) 47 Console.BackgroundColor = ConsoleColor.Yellow; // 设置进度条颜色 48 Console.SetCursorPosition(2, 5); // 设置光标位置,参数为第几列和第几行 49 for (int i = 0; i <burnProgress.Percent*50; i++) 50 { //每个整数写入1个空格 51 Console.Write(" "); // 移动进度条 52 } 53 Console.BackgroundColor = colorBack; // 恢复输出颜色 54 55 //第8行 已用时间,总时间 56 Console.ForegroundColor = ConsoleColor.Green;// 更新进度百分比,原理同上. 57 Console.SetCursorPosition(0, 7); 58 Console.Write($" 进度:{burnProgress.PercentStr} " + 59 $"已用时间:{FormatTime(0, 0, burnProgress.ElapsedTime)} " + 60 $"剩余时间:{FormatTime(0, 0, burnProgress.TotalTime - burnProgress.ElapsedTime)}"); 61 Console.Write(" "); //填充空白区域 62 Console.ForegroundColor = colorFore; 63 64 Console.SetCursorPosition(0, 9); //光标 定位到第10行 65 }; 66 }
运行结果如下,剩余时间为IMAPI2提供.并不一定准确.
四.BurnCdDemo获取磁盘大小为负数bug
在开始的时候,我们说了使用BurnCdDemo获取光盘大小为负数.在实际开发的过程中,也碰到了.因为我们买的光盘太大了?达到8G,实际模拟刻录时,没那么大.所以没啥问题.
我们看BurnCdDemo里Recorder对象的代码:
1 private long m_nDiskSize = 0; 2 private long m_nUseableSize = 0; 3 4 //可用的 5 m_nUseableSize = msFormat.FreeSectorsOnMedia * 2048; 6 //总大小 7 m_nDiskSize = msFormat.TotalSectorsOnMedia * 2048;
msFormat.FreeSectorsOnMedia和msFormat.TotalSectorsOnMedia类型为int.大家想到原因了吧.int溢出了.所以把后面的2048改为2048L就可以了.看似正常的代码,以后在碰到类型转换时要多注意些.
五.总结
总结写点啥呢.当然是最重要的哈.上源码:https://github.com/279328316/RecorderHelper
如有问题,欢迎留言.