vbAccelerator - Contents of code file: IconEx\frmBatchExtraction.cs

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.IO;
using System.Windows.Forms;

using vbAccelerator.Components.Win32;
using vbAccelerator.Components.Shell;
using vbAccelerator.Controls.TextBox;
using Microsoft.MSDNMag.AsyncUtils;

namespace vbAccelerator.Utilities.IconExtractor
{
   /// <summary>
   /// Summary description for frmBatchExtraction.
   /// </summary>
   public class frmBatchExtraction : System.Windows.Forms.Form
   {
      private enum UIMode : int
      {
         Setup = 1,
         Run = 2
      }
      private UIMode uiMode = UIMode.Setup;
      private AsyncBatchExtractor batchExtractor = null;
      private int totalIconsExtracted = 0;
      private DateTime startTime;

      private System.Windows.Forms.PictureBox pictureBox1;
      private System.Windows.Forms.GroupBox groupBox1;
      private System.Windows.Forms.Button btnCancel;
      private System.Windows.Forms.Button btnNext;
      private System.Windows.Forms.Panel pnlSetup;
      private System.Windows.Forms.Button button1;
      private System.Windows.Forms.Button btnPickSearch;
      private AutoCompleteTextBox txtSearchIn;
      private System.Windows.Forms.Label lblFolderSave;
      private System.Windows.Forms.Label lblFolder;
      private System.Windows.Forms.Label lblInfo;
      private System.Windows.Forms.Label lblCaption;
      private System.Windows.Forms.Panel pnlRun;
      private System.Windows.Forms.Label lblStatus;
      private System.Windows.Forms.Label label2;
      private System.Windows.Forms.Label lblProcessing;
      private AutoCompleteTextBox txtOutputTo;
      private System.Windows.Forms.ListBox lstLog;
      private System.Windows.Forms.CheckBox chkMultiDir;
      /// <summary>
      /// Required designer variable.
      /// </summary>
      private System.ComponentModel.Container components = null;

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

         this.pnlRun.Location = this.pnlSetup.Location;
         this.pnlRun.Size = this.pnlSetup.Size;
         this.pnlRun.Visible = false;

         this.Closing += new CancelEventHandler(frmBatchExtraction_Closing);

         this.txtOutputTo.AutoCompleteFlags =
          AutoCompleteTextBox.SHAutoCompleteFlags.SHACF_FILESYS_DIRS;
         this.txtSearchIn.AutoCompleteFlags =
          AutoCompleteTextBox.SHAutoCompleteFlags.SHACF_FILESYS_DIRS;
         
      }

      /// <summary>
      /// Clean up any resources being used.
      /// </summary>
      protected override void Dispose( bool disposing )
      {
         if( disposing )
         {
            if(components != null)
            {
               components.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(frmBatchExtraction));
         this.pictureBox1 = new System.Windows.Forms.PictureBox();
         this.groupBox1 = new System.Windows.Forms.GroupBox();
         this.btnCancel = new System.Windows.Forms.Button();
         this.btnNext = new System.Windows.Forms.Button();
         this.pnlSetup = new System.Windows.Forms.Panel();
         this.button1 = new System.Windows.Forms.Button();
         this.txtOutputTo = new AutoCompleteTextBox();
         this.btnPickSearch = new System.Windows.Forms.Button();
         this.txtSearchIn = new AutoCompleteTextBox();
         this.lblFolderSave = new System.Windows.Forms.Label();
         this.lblFolder = new System.Windows.Forms.Label();
         this.lblInfo = new System.Windows.Forms.Label();
         this.lblCaption = new System.Windows.Forms.Label();
         this.pnlRun = new System.Windows.Forms.Panel();
         this.lblProcessing = new System.Windows.Forms.Label();
         this.label2 = new System.Windows.Forms.Label();
         this.lblStatus = new System.Windows.Forms.Label();
         this.lstLog = new System.Windows.Forms.ListBox();
         this.chkMultiDir = new System.Windows.Forms.CheckBox();
         this.pnlSetup.SuspendLayout();
         this.pnlRun.SuspendLayout();
         this.SuspendLayout();
         // 
         // pictureBox1
         // 
         this.pictureBox1.Image =
          ((System.Drawing.Bitmap)(resources.GetObject("pictureBox1.Image")));
         this.pictureBox1.Location = new System.Drawing.Point(4, 4);
         this.pictureBox1.Name = "pictureBox1";
         this.pictureBox1.Size = new System.Drawing.Size(92, 296);
         this.pictureBox1.TabIndex = 0;
         this.pictureBox1.TabStop = false;
         // 
         // groupBox1
         // 
         this.groupBox1.Location = new System.Drawing.Point(-36, 280);
         this.groupBox1.Name = "groupBox1";
         this.groupBox1.Size = new System.Drawing.Size(508, 4);
         this.groupBox1.TabIndex = 9;
         this.groupBox1.TabStop = false;
         this.groupBox1.Text = "groupBox1";
         // 
         // btnCancel
         // 
         this.btnCancel.FlatStyle = System.Windows.Forms.FlatStyle.System;
         this.btnCancel.Location = new System.Drawing.Point(348, 288);
         this.btnCancel.Name = "btnCancel";
         this.btnCancel.Size = new System.Drawing.Size(80, 28);
         this.btnCancel.TabIndex = 10;
         this.btnCancel.Text = "Cancel";
         this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
         // 
         // btnNext
         // 
         this.btnNext.FlatStyle = System.Windows.Forms.FlatStyle.System;
         this.btnNext.Location = new System.Drawing.Point(260, 288);
         this.btnNext.Name = "btnNext";
         this.btnNext.Size = new System.Drawing.Size(80, 28);
         this.btnNext.TabIndex = 11;
         this.btnNext.Text = "&Next >";
         this.btnNext.Click += new System.EventHandler(this.btnNext_Click);
         // 
         // pnlSetup
         // 
         this.pnlSetup.Controls.AddRange(new System.Windows.Forms.Control[] {
                                                               this.chkMultiDir,
                                                               this.button1,
                                                               this.txtOutputTo,
                                                              
                                         this.btnPickSearch,
                                                               this.txtSearchIn,
                                                              
                                         this.lblFolderSave,
                                                               this.lblFolder,
                                                               this.lblInfo,
                                                              
                                         this.lblCaption});
         this.pnlSetup.Location = new System.Drawing.Point(96, 4);
         this.pnlSetup.Name = "pnlSetup";
         this.pnlSetup.Size = new System.Drawing.Size(332, 276);
         this.pnlSetup.TabIndex = 12;
         // 
         // button1
         // 
         this.button1.FlatStyle = System.Windows.Forms.FlatStyle.System;
         this.button1.Location = new System.Drawing.Point(276, 196);
         this.button1.Name = "button1";
         this.button1.Size = new System.Drawing.Size(56, 24);
         this.button1.TabIndex = 16;
         this.button1.Text = "Pick...";
         this.button1.Click += new System.EventHandler(this.button1_Click);
         // 
         // txtOutputTo
         // 
         this.txtOutputTo.Location = new System.Drawing.Point(4, 196);
         this.txtOutputTo.Name = "txtOutputTo";
         this.txtOutputTo.Size = new System.Drawing.Size(268, 21);
         this.txtOutputTo.TabIndex = 15;
         this.txtOutputTo.Text = "C:\\";
         // 
         // btnPickSearch
         // 
         this.btnPickSearch.FlatStyle = System.Windows.Forms.FlatStyle.System;
         this.btnPickSearch.Location = new System.Drawing.Point(276, 136);
         this.btnPickSearch.Name = "btnPickSearch";
         this.btnPickSearch.Size = new System.Drawing.Size(56, 24);
         this.btnPickSearch.TabIndex = 14;
         this.btnPickSearch.Text = "Pick...";
         this.btnPickSearch.Click += new
          System.EventHandler(this.btnPickSearch_Click);
         // 
         // txtSearchIn
         // 
         this.txtSearchIn.Location = new System.Drawing.Point(4, 136);
         this.txtSearchIn.Name = "txtSearchIn";
         this.txtSearchIn.Size = new System.Drawing.Size(268, 21);
         this.txtSearchIn.TabIndex = 13;
         this.txtSearchIn.Text = "C:\\";
         // 
         // lblFolderSave
         // 
         this.lblFolderSave.Location = new System.Drawing.Point(4, 176);
         this.lblFolderSave.Name = "lblFolderSave";
         this.lblFolderSave.Size = new System.Drawing.Size(328, 16);
         this.lblFolderSave.TabIndex = 12;
         this.lblFolderSave.Text = "Folder to save icons to:";
         // 
         // lblFolder
         // 
         this.lblFolder.Location = new System.Drawing.Point(4, 120);
         this.lblFolder.Name = "lblFolder";
         this.lblFolder.Size = new System.Drawing.Size(328, 16);
         this.lblFolder.TabIndex = 11;
         this.lblFolder.Text = "Folder or Drive to search in:";
         // 
         // lblInfo
         // 
         this.lblInfo.Location = new System.Drawing.Point(4, 36);
         this.lblInfo.Name = "lblInfo";
         this.lblInfo.Size = new System.Drawing.Size(328, 40);
         this.lblInfo.TabIndex = 10;
         this.lblInfo.Text = "This wizard allows you to automatically extract
          all icons within applications and" +
            " libraries within a drive or folder on your system.";
         // 
         // lblCaption
         // 
         this.lblCaption.BackColor = System.Drawing.SystemColors.ControlDark;
         this.lblCaption.Font = new System.Drawing.Font("Tahoma", 9.75F,
          System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point,
          ((System.Byte)(0)));
         this.lblCaption.ForeColor = System.Drawing.SystemColors.ControlLight;
         this.lblCaption.Name = "lblCaption";
         this.lblCaption.Size = new System.Drawing.Size(332, 23);
         this.lblCaption.TabIndex = 9;
         this.lblCaption.Text = "  Batch Icon Extraction";
         this.lblCaption.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
         // 
         // pnlRun
         // 
         this.pnlRun.Controls.AddRange(new System.Windows.Forms.Control[] {
                                                             this.lstLog,
                                                             this.lblProcessing,
                                                             this.label2,
                                                             this.lblStatus});
         this.pnlRun.Location = new System.Drawing.Point(20, 16);
         this.pnlRun.Name = "pnlRun";
         this.pnlRun.Size = new System.Drawing.Size(332, 276);
         this.pnlRun.TabIndex = 13;
         this.pnlRun.Visible = false;
         // 
         // lblProcessing
         // 
         this.lblProcessing.Location = new System.Drawing.Point(4, 64);
         this.lblProcessing.Name = "lblProcessing";
         this.lblProcessing.Size = new System.Drawing.Size(324, 40);
         this.lblProcessing.TabIndex = 11;
         this.lblProcessing.Text = "Processing: ";
         // 
         // label2
         // 
         this.label2.BackColor = System.Drawing.SystemColors.ControlDark;
         this.label2.Font = new System.Drawing.Font("Tahoma", 9.75F,
          System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point,
          ((System.Byte)(0)));
         this.label2.ForeColor = System.Drawing.SystemColors.ControlLight;
         this.label2.Name = "label2";
         this.label2.Size = new System.Drawing.Size(332, 23);
         this.label2.TabIndex = 10;
         this.label2.Text = "  Batch Icon Extraction";
         this.label2.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
         // 
         // lblStatus
         // 
         this.lblStatus.Location = new System.Drawing.Point(4, 32);
         this.lblStatus.Name = "lblStatus";
         this.lblStatus.Size = new System.Drawing.Size(324, 20);
         this.lblStatus.TabIndex = 0;
         this.lblStatus.Text = "Running for 0s.";
         // 
         // lstLog
         // 
         this.lstLog.Location = new System.Drawing.Point(4, 108);
         this.lstLog.Name = "lstLog";
         this.lstLog.Size = new System.Drawing.Size(324, 160);
         this.lstLog.TabIndex = 12;
         // 
         // chkMultiDir
         // 
         this.chkMultiDir.FlatStyle = System.Windows.Forms.FlatStyle.System;
         this.chkMultiDir.Location = new System.Drawing.Point(4, 244);
         this.chkMultiDir.Name = "chkMultiDir";
         this.chkMultiDir.Size = new System.Drawing.Size(268, 16);
         this.chkMultiDir.TabIndex = 17;
         this.chkMultiDir.Text = "New &Directory for Each Library";
         // 
         // frmBatchExtraction
         // 
         this.AutoScaleBaseSize = new System.Drawing.Size(5, 14);
         this.ClientSize = new System.Drawing.Size(432, 326);
         this.Controls.AddRange(new System.Windows.Forms.Control[] {
                                                        this.pnlSetup,
                                                        this.pnlRun,
                                                        this.btnNext,
                                                        this.btnCancel,
                                                        this.groupBox1,
                                                        this.pictureBox1});
         this.Font = new System.Drawing.Font("Tahoma", 8.25F,
          System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point,
          ((System.Byte)(0)));
         this.FormBorderStyle =
          System.Windows.Forms.FormBorderStyle.FixedDialog;
         this.Name = "frmBatchExtraction";
         this.StartPosition =
          System.Windows.Forms.FormStartPosition.CenterParent;
         this.Text = "frmBatchExtraction";
         this.Load += new System.EventHandler(this.frmBatchExtraction_Load);
         this.pnlSetup.ResumeLayout(false);
         this.pnlRun.ResumeLayout(false);
         this.ResumeLayout(false);

      }
      #endregion

      private void frmBatchExtraction_Load(object sender, System.EventArgs e)
      {
         this.txtOutputTo.Text =
          Environment.GetFolderPath(Environment.SpecialFolder.Personal);
      }

      private void frmBatchExtraction_Closing(object sender, CancelEventArgs e)
      {
         if (batchExtractor != null)
         {
            if (!batchExtractor.IsDone)
            {
               if (DialogResult.Yes == MessageBox.Show(this,
                  "Batch extraction is still running, are you sure you want to
                   cancel?",
                  this.Text,
                  MessageBoxButtons.YesNo,
                  MessageBoxIcon.Question))
               {
                  this.Cursor = Cursors.WaitCursor;
                  batchExtractor.CancelAndWait();
                  this.Cursor = null;
               }
               else
               {
                  e.Cancel = true;
               }
            }
         }
      }

      private void btnNext_Click(object sender, System.EventArgs e)
      {
         // Validate:
         string searchIn = this.txtSearchIn.Text;
         string outputDir = this.txtOutputTo.Text;
         if (Directory.Exists(searchIn))
         {
            bool ok = true;
            if (!Directory.Exists(outputDir))
            {
               ok = false;
               if (DialogResult.OK == MessageBox.Show(this,
                  String.Format(
                     "The output directory {1} does not exist, do you want to
                      create it?",
                     outputDir),
                  this.Text,
                  MessageBoxButtons.OKCancel,
                  MessageBoxIcon.Question))
               {
                  try
                  {
                     Directory.CreateDirectory(outputDir);
                     ok = true;
                  }
                  catch (Exception ex)
                  {
                     MessageBox.Show(this, 
                        String.Format("The output directory {0} could not be
                         created: {1}",
                           outputDir,
                        ex.Message),
                        this.Text,
                        MessageBoxButtons.OK,
                        MessageBoxIcon.Exclamation);
                  }
               }
            }
            if (ok)
            {
               btnNext.Enabled = false;

               pnlRun.Visible = true;
               pnlSetup.Visible = false;

               bool newDirs = this.chkMultiDir.Checked;

               batchExtractor = new AsyncBatchExtractor(this, searchIn,
                outputDir, newDirs );
               batchExtractor.Progress += new
                AsyncBatchExtractor.ProgressEventHandler(extract_Progress);
               batchExtractor.Completed += new EventHandler(extract_Finished);
               
               startTime = DateTime.Now;
               batchExtractor.Start();
            }
         }
         else
         {
            MessageBox.Show(this, 
               String.Format("The search directory {0} does not exist.",
                searchIn),
               this.Text,
               MessageBoxButtons.OK,
               MessageBoxIcon.Information);
            txtSearchIn.Focus();
         }
      }

      private void extract_Progress(string msg, int iconsExtracted)
      {
         logItem(msg, iconsExtracted);
      }

      private void extract_Finished(object sender, EventArgs e)
      {
         logItem("Finished", 0);
         btnCancel.Text = "&Close";
      }

      private void logItem(string msg, int iconsExtracted)
      {
         totalIconsExtracted += iconsExtracted;
         TimeSpan duration = DateTime.Now.Subtract(this.startTime);
         this.lblStatus.Text = String.Format(
            "Running for {0}s, Icons extracted: {1}",
            duration.TotalSeconds,
            totalIconsExtracted);
         this.lblProcessing.Text = msg;
         if (iconsExtracted > 0)
         {
            lstLog.Items.Add(
               String.Format("{0:D6}: {1}", (int)duration.TotalSeconds, msg));
         }
      }

      private void btnCancel_Click(object sender, System.EventArgs e)
      {
         // Closing event used to cancel op if required
         this.Close();
      }

      private void btnPickSearch_Click(object sender, System.EventArgs e)
      {
         using (FolderBrowser f = new FolderBrowser())
         {
            f.NewDialogStyle = true;
            f.NoNewFolderButton = true;
            f.FileSystemAncestorsOnly = true;
            f.InitialPath = txtSearchIn.Text;
            if (f.ShowDialog(this) == DialogResult.OK)
            {
               this.txtSearchIn.Text = f.SelectedPath;
            }
         }
      }

      private void button1_Click(object sender, System.EventArgs e)
      {
         using (FolderBrowser f = new FolderBrowser())
         {
            f.NewDialogStyle = true;
            f.FileSystemAncestorsOnly = true;
            f.InitialPath = txtOutputTo.Text;
            if (f.ShowDialog(this) == DialogResult.OK)
            {
               this.txtOutputTo.Text = f.SelectedPath;
            }
         }      
      }

   
      private class AsyncBatchExtractor : AsyncOperation
      {
         private string startDir = "";
         private string outputDir = "";
         private bool newDirForLibraries = false;

         public delegate void ProgressEventHandler(string item, int
          iconsExtracted);
         public event ProgressEventHandler Progress;

         protected override void DoWork()
         {
            runSearch(startDir);
            if (CancelRequested)
            {
               AcknowledgeCancel();
            }

         }

         private void runSearch(string startDir)
         {
            // stop if canncellation requested:
            if (!CancelRequested)
            {
               OnProgressEvent(startDir, 0);

               // process all the files
               try
               {
                  string[] files = Directory.GetFiles(startDir);
                  foreach (string file in files)
                  {
                     extractIcons(file);               
                  }

                  // recurse for sub directories:
                  if (!CancelRequested)
                  {
                     string[] dirs = Directory.GetDirectories(startDir);
                     foreach (string dir in dirs)
                     {
                        runSearch(dir);
                     }   
                  }
               }
               catch
               {
                  OnProgressEvent(
                     String.Format("Could not read files in {0}", startDir),
                     0);
               }
            }
         }

         private void extractIcons(string file)
         {
            // stop if cancellation requested:
            if (!CancelRequested)
            {
               bool readResources = false;
               int iconsExtracted = 0;
               try
               {
                  GroupIconResources gIR = new GroupIconResources(file);
                  foreach (GroupIconResource gRes in gIR)
                  {
                     // be responsive:
                     if (CancelRequested)
                     {
                        break;
                     }

                     // Extract & save icon:
                     if (gRes.IdIsNumeric)
                     {
                        try
                        {
                           IconEx iEx = new IconEx(file, gRes.Id);
                           saveIcon(file, String.Format("{0:N0}",gRes.Id), iEx);
                           iEx.Dispose();
                           iconsExtracted++;
                        }
                        catch {}
                     }
                     else
                     {
                        try
                        {
                           IconEx iEx = new IconEx(file, gRes.Name);
                           saveIcon(file, gRes.Name, iEx);
                           iEx.Dispose();
                           iconsExtracted++;
                        }
                        catch {}
                     }
                  }
                  readResources = true;
               }
               catch {}

               if (!readResources)
               {
                  try
                  {
                     // Load icon and save if valid:
                     IconEx iEx = new IconEx(file);
                     saveIcon(file, "", iEx);
                     iEx.Dispose();
                     iconsExtracted++;
                  }
                  catch {}
               }
               
               OnProgressEvent(
                  String.Format("Saved {0} icons from {1}", iconsExtracted,
                   file),
                  iconsExtracted
                  );
            }

         }

         private void saveIcon(
            string file,
            string fileName,
            IconEx iEx
            )
         {
            string iconOutputFile = "";
            string iconOutputDir = "";            
            if (fileName.Length == 0)
            {

               // This is an icon file on disk.
               // Write out to /IconFiles/iconName.ico
               // If iconName.ico already exists, then write 
               // to iconName[n].ico where [n] is a unique number
               iconOutputDir = Path.Combine(outputDir, "IconFiles");
               iconOutputFile = Path.GetFileName(file);
            }
            else
            {
               // This is an icon within a resource.
               // Write out to /LibName/iconResName.ico
               // If iconResName.ico already exists, then write
               // to 
               if (this.newDirForLibraries)
               {
                  iconOutputDir = Path.Combine(
                     outputDir, 
                     Path.GetFileName(file));
               }
               else
               {
                  iconOutputDir = Path.Combine(outputDir, "Extracted");
               }
               iconOutputFile = fileName + ".ico";
            }
            
            // Create directory if not there:
            if (!Directory.Exists(iconOutputDir))
            {
               Directory.CreateDirectory(iconOutputDir);
            }            
            // Check if the file name is unique:
            string iconOutputFileTemp =
             Path.GetFileNameWithoutExtension(iconOutputFile);
            string iconExt = Path.GetExtension(iconOutputFile);
            int unique = 0;
            while (File.Exists(Path.Combine(iconOutputDir, iconOutputFile)))
            {
               unique++;
               iconOutputFile = String.Format("{0}_{1:N0}{2}",
                  iconOutputFileTemp,
                  unique,
                  iconExt);
            }
            
            // Write the icon:
            iEx.Save(Path.Combine(iconOutputDir, iconOutputFile));
         }

         private void OnProgressEvent(
            string msg,
            int iconsExtracted
            )
         {
            lock(this)
            {
               FireAsync(Progress, msg, iconsExtracted);
            }
         }


         public AsyncBatchExtractor(
            ISynchronizeInvoke isi,
            string startDir,
            string outputDir,
            bool newDirForLibraries
            ) : base(isi)
         {   
            this.startDir = startDir;
            this.outputDir = outputDir;
            this.newDirForLibraries = newDirForLibraries;
         }
      }

   }

}