vbAccelerator - Contents of code file: DataCDWriterCS\frmDataCDCreator.cs

This file is part of the download Data CD Writer, which is described in the article Writing Data CDs.

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.IO;
using System.Threading;
using vbAccelerator.Components.ImapiWrapper;
using vbAccelerator.Components.Shell;


namespace DataCDWriter
{
   /// <summary>
   /// Summary description for frmDataCDCreator.
   /// </summary>
   public class frmDataCDCreator : System.Windows.Forms.Form
   {

      private DiscMaster discMaster = null;
      private JolietDiscMaster jolietDiscMaster = null;
      private bool cancel = false;
      private bool burnInProgress = false;
      private DataCDCreator creator = null;
      private CreateCDDelegate createCDHandler = null;
      private System.Windows.Forms.StatusBar sbrMain;
      private System.Windows.Forms.Label lblRecorder;
      private System.Windows.Forms.ComboBox cboRecorder;
      private System.Windows.Forms.CheckBox chkEjectWhenComplete;
      private System.Windows.Forms.CheckBox chkSimulate;
      private System.Windows.Forms.Button btnBurn;
      private System.Windows.Forms.CheckBox chkOverwrite;
      private System.Windows.Forms.Label lblFolder;
      private System.Windows.Forms.TextBox txtFolder;
      private System.Windows.Forms.Button btnBrowse;
      private System.Windows.Forms.Label label1;
      /// <summary>
      /// Required designer variable.
      /// </summary>
      private System.ComponentModel.Container components = null;

      public frmDataCDCreator()
      {
         //
         // Required for Windows Form Designer support
         //
         InitializeComponent();

         Application.ThreadException += new
          ThreadExceptionEventHandler(application_ThreadException);

         Show();
         Refresh();

         // Create the disc master object and initialse the recorder list:
         GetRecorders();

         // Attach all of the events:
         discMaster.AddProgress += new
          ProgressEventHandler(discMaster_AddProgress);
         discMaster.BlockProgress += new
          ProgressEventHandler(discMaster_BlockProgress);
         discMaster.BurnComplete += new
          CompletionStatusEventHandler(discMaster_BurnComplete);
         discMaster.ClosingDisc += new
          EstimatedTimeOperationEventHandler(discMaster_ClosingDisc);
         discMaster.EraseComplete += new
          CompletionStatusEventHandler(discMaster_EraseComplete);
         discMaster.PnPActivity += new EventHandler(discMaster_PnPActivity);
         discMaster.PreparingBurn += new
          EstimatedTimeOperationEventHandler(discMaster_PreparingBurn);
         discMaster.QueryCancel += new
          QueryCancelEventHandler(discMaster_QueryCancel);
         discMaster.TrackProgress += new
          ProgressEventHandler(discMaster_TrackProgress);
      }

      /// <summary>
      /// Clean up any resources being used.
      /// </summary>
      protected override void Dispose( bool disposing )
      {
         if( disposing )
         {
            if(components != null)
            {
               components.Dispose();
            }
            jolietDiscMaster.Dispose();
            discMaster.Dispose();
         }
         base.Dispose( disposing );
      }

      #region Windows Form Designer generated code
      /// <summary>
      /// Required method for Designer support - do not modify
      /// the contents of this method with the code editor.
      /// </summary>
      private void InitializeComponent()
      {
         System.Resources.ResourceManager resources = new
          System.Resources.ResourceManager(typeof(frmDataCDCreator));
         this.sbrMain = new System.Windows.Forms.StatusBar();
         this.lblRecorder = new System.Windows.Forms.Label();
         this.cboRecorder = new System.Windows.Forms.ComboBox();
         this.chkEjectWhenComplete = new System.Windows.Forms.CheckBox();
         this.chkSimulate = new System.Windows.Forms.CheckBox();
         this.btnBurn = new System.Windows.Forms.Button();
         this.chkOverwrite = new System.Windows.Forms.CheckBox();
         this.lblFolder = new System.Windows.Forms.Label();
         this.txtFolder = new System.Windows.Forms.TextBox();
         this.btnBrowse = new System.Windows.Forms.Button();
         this.label1 = new System.Windows.Forms.Label();
         this.SuspendLayout();
         // 
         // sbrMain
         // 
         this.sbrMain.Location = new System.Drawing.Point(0, 246);
         this.sbrMain.Name = "sbrMain";
         this.sbrMain.Size = new System.Drawing.Size(500, 20);
         this.sbrMain.TabIndex = 13;
         // 
         // lblRecorder
         // 
         this.lblRecorder.Font = new System.Drawing.Font("Tahoma", 8.25F,
          System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point,
          ((System.Byte)(0)));
         this.lblRecorder.Location = new System.Drawing.Point(8, 12);
         this.lblRecorder.Name = "lblRecorder";
         this.lblRecorder.Size = new System.Drawing.Size(76, 16);
         this.lblRecorder.TabIndex = 14;
         this.lblRecorder.Text = "&Recorder:";
         // 
         // cboRecorder
         // 
         this.cboRecorder.DropDownStyle =
          System.Windows.Forms.ComboBoxStyle.DropDownList;
         this.cboRecorder.Location = new System.Drawing.Point(88, 8);
         this.cboRecorder.Name = "cboRecorder";
         this.cboRecorder.Size = new System.Drawing.Size(404, 21);
         this.cboRecorder.TabIndex = 15;
         this.cboRecorder.SelectedIndexChanged += new
          System.EventHandler(this.cboRecorder_SelectedIndexChanged);
         // 
         // chkEjectWhenComplete
         // 
         this.chkEjectWhenComplete.Checked = true;
         this.chkEjectWhenComplete.CheckState =
          System.Windows.Forms.CheckState.Checked;
         this.chkEjectWhenComplete.FlatStyle =
          System.Windows.Forms.FlatStyle.System;
         this.chkEjectWhenComplete.Location = new System.Drawing.Point(184,
          208);
         this.chkEjectWhenComplete.Name = "chkEjectWhenComplete";
         this.chkEjectWhenComplete.Size = new System.Drawing.Size(236, 16);
         this.chkEjectWhenComplete.TabIndex = 18;
         this.chkEjectWhenComplete.Text = "&Eject When Complete";
         // 
         // chkSimulate
         // 
         this.chkSimulate.Checked = true;
         this.chkSimulate.CheckState = System.Windows.Forms.CheckState.Checked;
         this.chkSimulate.FlatStyle = System.Windows.Forms.FlatStyle.System;
         this.chkSimulate.Location = new System.Drawing.Point(184, 188);
         this.chkSimulate.Name = "chkSimulate";
         this.chkSimulate.Size = new System.Drawing.Size(236, 16);
         this.chkSimulate.TabIndex = 17;
         this.chkSimulate.Text = "&Simulate";
         // 
         // btnBurn
         // 
         this.btnBurn.FlatStyle = System.Windows.Forms.FlatStyle.System;
         this.btnBurn.Location = new System.Drawing.Point(92, 188);
         this.btnBurn.Name = "btnBurn";
         this.btnBurn.Size = new System.Drawing.Size(88, 24);
         this.btnBurn.TabIndex = 16;
         this.btnBurn.Text = "&Burn";
         this.btnBurn.Click += new System.EventHandler(this.btnBurn_Click);
         // 
         // chkOverwrite
         // 
         this.chkOverwrite.Checked = true;
         this.chkOverwrite.CheckState = System.Windows.Forms.CheckState.Checked;
         this.chkOverwrite.FlatStyle = System.Windows.Forms.FlatStyle.System;
         this.chkOverwrite.Location = new System.Drawing.Point(184, 228);
         this.chkOverwrite.Name = "chkOverwrite";
         this.chkOverwrite.Size = new System.Drawing.Size(236, 16);
         this.chkOverwrite.TabIndex = 19;
         this.chkOverwrite.Text = "&Overwrite files on CDRW disc";
         // 
         // lblFolder
         // 
         this.lblFolder.Font = new System.Drawing.Font("Tahoma", 8.25F,
          System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point,
          ((System.Byte)(0)));
         this.lblFolder.Location = new System.Drawing.Point(4, 84);
         this.lblFolder.Name = "lblFolder";
         this.lblFolder.Size = new System.Drawing.Size(76, 16);
         this.lblFolder.TabIndex = 20;
         this.lblFolder.Text = "&Folder:";
         // 
         // txtFolder
         // 
         this.txtFolder.Location = new System.Drawing.Point(84, 80);
         this.txtFolder.Name = "txtFolder";
         this.txtFolder.Size = new System.Drawing.Size(400, 21);
         this.txtFolder.TabIndex = 21;
         this.txtFolder.Text = "";
         // 
         // btnBrowse
         // 
         this.btnBrowse.Location = new System.Drawing.Point(88, 112);
         this.btnBrowse.Name = "btnBrowse";
         this.btnBrowse.Size = new System.Drawing.Size(92, 24);
         this.btnBrowse.TabIndex = 22;
         this.btnBrowse.Text = "&Browse...";
         this.btnBrowse.Click += new System.EventHandler(this.btnBrowse_Click);
         // 
         // label1
         // 
         this.label1.Location = new System.Drawing.Point(88, 36);
         this.label1.Name = "label1";
         this.label1.Size = new System.Drawing.Size(396, 44);
         this.label1.TabIndex = 23;
         this.label1.Text = "Note: this simple demo only allows you to burn a
          single folder (and all subfolder" +
            "s) from disc.  The IMAPI library allows you to burn any source
             file to any desti" +
            "nation on the disc.";
         // 
         // frmDataCDCreator
         // 
         this.AutoScaleBaseSize = new System.Drawing.Size(5, 14);
         this.ClientSize = new System.Drawing.Size(500, 266);
         this.Controls.AddRange(new System.Windows.Forms.Control[] {
                                                        this.label1,
                                                        this.btnBrowse,
                                                        this.txtFolder,
                                                        this.lblFolder,
                                                        this.chkOverwrite,
                                                       
                                         this.chkEjectWhenComplete,
                                                        this.chkSimulate,
                                                        this.btnBurn,
                                                        this.cboRecorder,
                                                        this.lblRecorder,
                                                        this.sbrMain});
         this.Font = new System.Drawing.Font("Tahoma", 8.25F,
          System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point,
          ((System.Byte)(0)));
         this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
         this.Name = "frmDataCDCreator";
         this.Text = "vbAccelerator Data CD Creator";
         this.ResumeLayout(false);

      }
      #endregion


      /// <summary>
      /// The main entry point for the application.
      /// </summary>
      [STAThread]
      static void Main() 
      {
         Application.Run(new frmDataCDCreator());
      }

      private void application_ThreadException(object sender,
       ThreadExceptionEventArgs e)
      {
         MessageBox.Show(this, String.Format("An untrapped exception occurred:
          {0}.  The application will now close.", e.Exception),
            Text, MessageBoxButtons.OK, MessageBoxIcon.Error);
         Close();
      }

      protected override void OnClosing(CancelEventArgs e)
      {   
         // Don't close if burn in progress
         if (burnInProgress)
         {
            e.Cancel = true;

            MessageBox.Show(this, "A CD burn is currently in progress.  Cancel
             the burn before closing this application.", 
               Text, MessageBoxButtons.OK, MessageBoxIcon.Information);
            return;
         }
         
         // Clear up:
         base.OnClosing(e);
         Cursor.Current = Cursors.WaitCursor;
         sbrMain.Text = "Closing IMAPI interface...";
         jolietDiscMaster.Dispose();
         discMaster.Dispose();
         Cursor.Current = Cursors.Default;
      }

      private void GetRecorders()
      {
         try
         {
            discMaster = new DiscMaster();
            jolietDiscMaster = discMaster.JolietDiscMaster();

            foreach (DiscRecorder recorder in discMaster.DiscRecorders)
            {
               cboRecorder.Items.Add(
                  new ComboRecorderWrapper(recorder));            
            }

            if (cboRecorder.Items.Count > 0)
            {
               cboRecorder.SelectedIndex = 0;
            }
         }
         catch (Exception ex)
         {
            MessageBox.Show(this, String.Format("Unable to initialise the IMAPI
             library {0}", ex),
               Text, MessageBoxButtons.OK, MessageBoxIcon.Stop);
            if (discMaster != null)
            {
               discMaster.Dispose();
            }         
         }
      }


      /// <summary>
      /// Raised whilst blocks are added to the stash
      /// </summary>
      /// <param name="sender">Disc master object</param>
      /// <param name="e">Progess information</param>
      private void discMaster_AddProgress(object sender, ProgressEventArgs e)
      {
         sbrMain.Text = String.Format("Adding {0} of {1}", e.Completed,
          e.Total);
      }

      /// <summary>
      /// Raised whilst blocks are burnt to the disc
      /// </summary>
      /// <param name="sender">Disc master object</param>
      /// <param name="e">Progress information</param>
      private void discMaster_BlockProgress(object sender, ProgressEventArgs e)
      {
         sbrMain.Text = String.Format("Block {0} of {1}", e.Completed, e.Total);
      }

      /// <summary>
      /// Raised when CD burning has completed
      /// </summary>
      /// <param name="sender">Disc Master object</param>
      /// <param name="e">Status information</param>
      private void discMaster_BurnComplete(object sender,
       CompletionStatusEventArgs e)
      {
         sbrMain.Text = String.Format("Burn Complete!");
      }

      /// <summary>
      /// Raised as the disc is about to be closed
      /// </summary>
      /// <param name="sender">Disc Master object</param>
      /// <param name="e">Estimated time to close the disc</param>
      private void discMaster_ClosingDisc(object sender,
       EstimatedTimeOperationEventArgs e)
      {
         sbrMain.Text = String.Format("Closing disc (estimated time {0}s)...", 
            e.EstimatedSeconds);
      }

      /// <summary>
      /// Raised when an erase operation completes
      /// </summary>
      /// <param name="sender">Disc master object</param>
      /// <param name="e">Status information</param>
      private void discMaster_EraseComplete(object sender,
       CompletionStatusEventArgs e)
      {
         sbrMain.Text = String.Format("Erase Complete!");
      }

      /// <summary>
      /// Raised when a recorder is changed
      /// </summary>
      /// <param name="sender">Disc master object</param>
      /// <param name="e">Not used</param>
      private void discMaster_PnPActivity(object sender, EventArgs e)
      {
         //
      }

      /// <summary>
      /// Raised before a disc is about to be burnt.
      /// </summary>
      /// <param name="sender">Disc Master object</param>
      /// <param name="e">Estimated time before burning begins</param>
      private void discMaster_PreparingBurn(object sender,
       EstimatedTimeOperationEventArgs e)
      {
         sbrMain.Text = String.Format("Preparing to burn disc (estimated time
          {0}s)...", 
            e.EstimatedSeconds);
      }

      /// <summary>
      /// Raised to request whether to cancel a stash or burn operation
      /// </summary>
      /// <param name="sender">Disc Master object</param>
      /// <param name="e">Whether to cancel or not</param>
      private void discMaster_QueryCancel(object sender, QueryCancelEventArgs e)
      {
         e.Cancel = cancel;
      }

      /// <summary>
      /// Raised as tracks are burnt to disc
      /// </summary>
      /// <param name="sender">Disc Master object</param>
      /// <param name="e">Track progress</param>
      private void discMaster_TrackProgress(object sender, ProgressEventArgs e)
      {
         if (e.Completed < e.Total)
         {
            sbrMain.Text = String.Format("Track {0} of {1}", e.Completed + 1,
             e.Total);
         }
         else
         {
            sbrMain.Text = String.Format("Completed adding last track");
         }
      }


      private void cboRecorder_SelectedIndexChanged(object sender,
       System.EventArgs e)
      {
         if (cboRecorder.SelectedIndex > -1)
         {
            ComboRecorderWrapper wrapper = (ComboRecorderWrapper)
             cboRecorder.SelectedItem;
            discMaster.DiscRecorders.ActiveDiscRecorder = wrapper.DiscRecorder;
         }
      
      }

      private void btnBurn_Click(object sender, System.EventArgs e)
      {
         if (burnInProgress)
         {
            cancel = true;
         }
         else
         {
            BurnCd(chkSimulate.Checked, chkEjectWhenComplete.Checked,
             chkOverwrite.Checked);
         }

      }

      private bool ValidateFolder()
      {
         string folder = txtFolder.Text;
         if (Directory.Exists(folder))
         {
            return true;
         }
         else
         {
            MessageBox.Show(this, "Please choose a valid folder on the file
             system to copy from.", 
               Text, MessageBoxButtons.OK, MessageBoxIcon.Information);
            return false;
         }
      }

      /// <summary>
      /// Burns the CD asynchronously
      /// </summary>
      /// <param name="simulate"><c>true</c> to simulate, <c>false</c> to
       really burn</param>
      /// <param name="ejectWhenComplete"><c>true</c> if the tray should be
       ejected once
      /// burn has finished.</param>
      /// <param name="overwrite"><c>true</c> to overwrite existing files on
       the disc.</param>
      private void BurnCd(bool simulate, bool ejectWhenComplete, bool overwrite)
      {
         // If the folder is good
         if (ValidateFolder())
         {
            // Check that we have media:
            if (CheckMedia())
            {
               // Asynchronously invoke the creator
               creator = new DataCDCreator(discMaster, jolietDiscMaster);
               creator.AddDirectory(txtFolder.Text, true);
               
               createCDHandler = new CreateCDDelegate(creator.CreateCD);
               AsyncCallback callback = new AsyncCallback(createCD_Complete);
               IAsyncResult ar = createCDHandler.BeginInvoke(
                  simulate, ejectWhenComplete, overwrite, callback, null);

               SetApplicationMode(true);
            }
         }
      }

      /// <summary>
      /// Called when CD creation completes
      /// </summary>
      /// <param name="ar">Result of method call (none)</param>
      private void createCD_Complete(IAsyncResult ar)
      {
         SetApplicationMode(false);
         createCDHandler.EndInvoke(ar);
      }

      /// <summary>
      /// Sets the application's mode
      /// </summary>
      /// <param name="burning"><c>true</c> if a burn is in progress</param>
      private void SetApplicationMode(bool burning)
      {
         if (burning)
         {
            burnInProgress = true;
            cancel = false;
            btnBurn.Text = "Cancel";

            cboRecorder.Enabled = false;
         }
         else
         {
            burnInProgress = false;
            btnBurn.Text = "&Burn";

            cboRecorder.Enabled = true;
         }
      }

      /// <summary>
      /// Checks the media in the drive.
      /// </summary>
      /// <returns></returns>
      private bool CheckMedia()
      {
         bool mediaOk = false;

         sbrMain.Text = "Checking media in recorder...";
         Cursor.Current = Cursors.WaitCursor;
         DiscRecorder recorder = ((ComboRecorderWrapper)
          cboRecorder.SelectedItem).DiscRecorder;
         recorder.OpenExclusive();
         MediaDetails media = recorder.GetMediaDetails();
         recorder.CloseExclusive();
         Cursor.Current = Cursors.Default;
         if (media.MediaPresent)
         {
            if ((media.MediaFlags & MEDIA_FLAGS.MEDIA_WRITABLE) ==
             MEDIA_FLAGS.MEDIA_WRITABLE)
            {
               sbrMain.Text = "Preparing to burn CD.";
               mediaOk = true;
            }
            else
            {
               sbrMain.Text = "Media cannot be written to.";
               MessageBox.Show(this, 
                  String.Format("The disc in drive {0} ({1}) is either not
                   blank or cannot be written to.", recorder.DriveLetter,
                   recorder.PnPID),
                  Text, MessageBoxButtons.OK, MessageBoxIcon.Information);
               
            }
         }
         else
         {
            sbrMain.Text = "No media in drive.";
            MessageBox.Show(this, 
               String.Format("Please insert blank, writable media into drive
                {0} ({1})", recorder.DriveLetter, recorder.PnPID),
               Text, MessageBoxButtons.OK, MessageBoxIcon.Information);

         }
         return mediaOk;
      }

      private void btnBrowse_Click(object sender, System.EventArgs e)
      {
         using (FolderBrowser f = new FolderBrowser())
         {
            f.Title = "Choose folder to copy to CD";
            f.NewDialogStyle = true;
            f.ShowEditBox = true;
            f.NoNewFolderButton = true;
            if (Directory.Exists(txtFolder.Text))
            {
               f.InitialPath = txtFolder.Text;
            }
            f.FileSystemDirectoriesOnly = true;
            if (DialogResult.OK == f.ShowDialog(this))
            {
               txtFolder.Text = f.SelectedPath;
            }
         }
      }


      /// <summary>
      /// Slight class to wrap a DiscRecorder allowing it to be associated
      /// with a combo box.
      /// </summary>
      class ComboRecorderWrapper
      {
         private readonly DiscRecorder recorder;

         public ComboRecorderWrapper(DiscRecorder recorder)
         {
            this.recorder = recorder;
         }

         public DiscRecorder DiscRecorder
         {
            get
            {
               return recorder;
            }
         }

         public override string ToString()
         {
            return String.Format("{0} ({1} {2} {3})", 
               recorder.DriveLetter, recorder.Vendor, recorder.Product,
                recorder.Revision);
         }
      }

   }

}