C#光盤刻錄


一.背景介紹

最近公司一個老項目需要添加導出數據到光盤的功能.開始對這功能添加有點抵觸的.光盤?都啥年代了.

光盤一種即將淘汰的存儲媒介.就像當年的隨身聽,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         }
View Code

此時,需要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;}
View Code

(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         }
View Code

(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        
View Code

 測試結果:

 

至此,我們完成了對於光驅設備列表的獲取及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; }
View Code

待刻錄媒體對象定義如下

 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     }
View Code

(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         }
View Code

(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                     }
View Code

運行結果:

3.刻錄及刻錄進度通知

 為Recorder對象添加Burn方法.同時,添加刻錄進度通知.

(1)添加BurnProgressChanged委托用於通知刻錄進度

1     /// <summary>
2     /// 刻錄進度delegate
3     /// </summary>
4     public delegate void BurnProgressChanged(BurnProgress burnProgress);
View Code

刻錄進度通知對象定義如下(其屬性為根據需求添加):

 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     }
View Code

(2)為Recorder對象添加委托屬性

1         /// <summary>
2         /// 刻錄進度變化通知
3         /// </summary>
4         public BurnProgressChanged OnBurnProgressChanged { get; set; }
View Code

(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         }
View Code

(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                     }
View Code

(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         }
View Code

運行結果如下,剩余時間為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.FreeSectorsOnMediamsFormat.TotalSectorsOnMedia類型為int.大家想到原因了吧.int溢出了.所以把后面的2048改為2048L就可以了.看似正常的代碼,以后在碰到類型轉換時要多注意些.

五.總結

總結寫點啥呢.當然是最重要的哈.上源碼:https://github.com/279328316/RecorderHelper

如有問題,歡迎留言.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM