// WinFormsSelfExtractorStub.cs // ------------------------------------------------------------------ // // Copyright (c) 2008, 2009 Dino Chiesa. // All rights reserved. // // This code module is part of DotNetZip, a zipfile class library. // // ------------------------------------------------------------------ // // This code is licensed under the Microsoft Public License. // See the file License.txt for the license details. // More info on: http://dotnetzip.codeplex.com // // ------------------------------------------------------------------ // // last saved (in emacs): // Time-stamp: <2011-July-30 15:48:47> // // ------------------------------------------------------------------ // // Implements the "stub" of a WinForms self-extracting Zip archive. This // code is included in all GUI SFX files. It is included as a resource // into the DotNetZip DLL, and then is compiled at runtime when a SFX is // saved. This code runs when the SFX is run. // // ------------------------------------------------------------------ namespace Ionic.Zip { // The using statements must be inside the namespace scope, because when the SFX is being // generated, this module gets concatenated with other source code and then compiled. using System; using System.Reflection; using System.IO; using System.Collections.Generic; using System.Windows.Forms; using System.Diagnostics; using System.Threading; // ThreadPool, WaitCallback using Ionic.Zip; using Ionic.Zip.Forms; public partial class WinFormsSelfExtractorStub : Form { private const string DllResourceName = "Ionic.Zip.dll"; private int entryCount; private int Overwrite; private bool Interactive; private ManualResetEvent postUpackExeDone; delegate void ExtractEntryProgress(ExtractProgressEventArgs e); void _SetDefaultExtractLocation() { // Design Note: // What follows may look odd. The textbox is set to a particular value. // Then the value is tested, and if the value begins with the first part // of the string and ends with the last part, and if it does, then we // change the value. When would that not get replaced? // // Well, here's the thing. This module has to compile as it is, as a // standalone sample. But then, inside DotNetZip, when generating an SFX, // we do a text.Replace on @@EXTRACTLOCATION and insert a different value. // So the effect is, with a straight compile, the value gets // SpecialFolder.Personal. If you replace @@EXTRACTLOCATION with // something else, it stays and does not get replaced. this.txtExtractDirectory.Text = "@@EXTRACTLOCATION"; this.txtExtractDirectory.Text = ReplaceEnvVars(this.txtExtractDirectory.Text); if (this.txtExtractDirectory.Text.StartsWith("@@") && this.txtExtractDirectory.Text.EndsWith("EXTRACTLOCATION")) { this.txtExtractDirectory.Text = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), ZipName); } } // workitem 8893 private string ReplaceEnvVars(string v) { string s= v; System.Collections.IDictionary envVars = Environment.GetEnvironmentVariables(); foreach (System.Collections.DictionaryEntry de in envVars) { string t = "%" + de.Key + "%"; s= s.Replace(t, de.Value as String); } return s; } private bool SetInteractiveFlag() { bool result = false; Boolean.TryParse("@@QUIET", out result); Interactive = !result; return Interactive; } private int SetOverwriteBehavior() { Int32 result = 0; Int32.TryParse("@@EXTRACT_EXISTING_FILE", out result); Overwrite = result; return result; } private bool PostUnpackCmdLineIsSet() { string s = txtPostUnpackCmdLine.Text; bool result = !(s.StartsWith("@@") && s.EndsWith("POST_UNPACK_CMD_LINE")); return result; } void _SetPostUnpackCmdLine() { // See the design note in _SetDefaultExtractLocation() for // an explanation of what is going on here. this.txtPostUnpackCmdLine.Text = "@@POST_UNPACK_CMD_LINE"; this.txtPostUnpackCmdLine.Text = ReplaceEnvVars(this.txtPostUnpackCmdLine.Text); if (this.txtPostUnpackCmdLine.Text.StartsWith("@@") && this.txtPostUnpackCmdLine.Text.EndsWith("POST_UNPACK_CMD_LINE")) { // If there is nothing set for the CMD to execute after unpack, then // disable all the UI associated to that bit. txtPostUnpackCmdLine.Enabled = txtPostUnpackCmdLine.Visible = false; chk_ExeAfterUnpack.Enabled = chk_ExeAfterUnpack.Visible = false; // workitem 8925 this.chk_Remove.Enabled = this.chk_Remove.Visible = false; // adjust the position of all the remaining UI int delta = this.progressBar1.Location.Y - this.chk_ExeAfterUnpack.Location.Y ; this.MinimumSize = new System.Drawing.Size(this.MinimumSize.Width, this.MinimumSize.Height - (delta -4)); //MoveDown(this.chk_Overwrite, delta); MoveDown(this.comboExistingFileAction, delta); MoveDown(this.label1, delta); MoveDown(this.chk_OpenExplorer, delta); MoveDown(this.btnDirBrowse, delta); MoveDown(this.txtExtractDirectory, delta); MoveDown(this.lblExtractDir, delta); // finally, adjust the size of the form this.Size = new System.Drawing.Size(this.Width, this.Height - (delta-4)); // Add the size to the txtComment, because it is anchored to the bottom. // When we shrink the size of the form, the txtComment shrinks also. // No need for that. this.txtComment.Size = new System.Drawing.Size(this.txtComment.Width, this.txtComment.Height + delta); } else { // workitem 8925 // there is a comment line. Do we also want to remove files after executing it? bool result = false; Boolean.TryParse("@@REMOVE_AFTER_EXECUTE", out result); this.chk_Remove.Checked = result; } } private void MoveDown (System.Windows.Forms.Control c, int delta) { c.Location = new System.Drawing.Point(c.Location.X, c.Location.Y + delta); } private void FixTitle() { string foo = "@@SFX_EXE_WINDOW_TITLE"; if (foo.StartsWith("@@") && foo.EndsWith("SFX_EXE_WINDOW_TITLE")) { this.Text = String.Format("DotNetZip v{0} Self-extractor (www.codeplex.com/DotNetZip)", Ionic.Zip.ZipFile.LibraryVersion.ToString()); } else this.Text = foo; } private void HideComment() { int smallerHeight = this.MinimumSize.Height - (this.txtComment.Height+this.lblComment.Height+5); lblComment.Visible = false; txtComment.Visible = false; this.MinimumSize = new System.Drawing.Size(this.MinimumSize.Width, smallerHeight); this.MaximumSize = new System.Drawing.Size(this.MaximumSize.Width, this.MinimumSize.Height); this.Size = new System.Drawing.Size(this.Width, this.MinimumSize.Height); } private void InitExtractExistingFileList() { List _ExtractActionNames = new List(Enum.GetNames(typeof(Ionic.Zip.ExtractExistingFileAction))); foreach (String name in _ExtractActionNames) { if (!name.StartsWith("Invoke")) { if (name.StartsWith("Throw")) comboExistingFileAction.Items.Add("Stop"); else comboExistingFileAction.Items.Add(name); } } comboExistingFileAction.SelectedIndex = Overwrite; } public WinFormsSelfExtractorStub() { InitializeComponent(); FixTitle(); _setCancel = true; entryCount= 0; _SetDefaultExtractLocation(); _SetPostUnpackCmdLine(); SetInteractiveFlag(); SetOverwriteBehavior(); InitExtractExistingFileList(); try { if (!String.IsNullOrEmpty(zip.Comment)) { txtComment.Text = zip.Comment; } else { HideComment(); } } catch (Exception e1) { // why would this ever fail? Not sure. this.lblStatus.Text = "exception while resetting size: " + e1.ToString(); HideComment(); } } static WinFormsSelfExtractorStub() { // This is important to resolve the Ionic.Zip.dll inside the extractor. AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(Resolver); } static System.Reflection.Assembly Resolver(object sender, ResolveEventArgs args) { // super defensive Assembly a1 = Assembly.GetExecutingAssembly(); if (a1==null) throw new Exception("GetExecutingAssembly returns null."); string[] tokens = args.Name.Split(','); String[] names = a1.GetManifestResourceNames(); if (names==null) throw new Exception("GetManifestResourceNames returns null."); // workitem 7978 Stream s = null; foreach (string n in names) { string root = n.Substring(0,n.Length-4); string ext = n.Substring(n.Length-3); if (root.Equals(tokens[0]) && ext.ToLower().Equals("dll")) { s= a1.GetManifestResourceStream(n); if (s!=null) break; } } if (s==null) throw new Exception(String.Format("GetManifestResourceStream returns null. Available resources: [{0}]", String.Join("|", names))); byte[] block = new byte[s.Length]; if (block==null) throw new Exception(String.Format("Cannot allocated buffer of length({0}).", s.Length)); s.Read(block, 0, block.Length); Assembly a2 = Assembly.Load(block); if (a2==null) throw new Exception("Assembly.Load(block) returns null"); return a2; } private void Form_Shown(object sender, EventArgs e) { if (!Interactive) { RemoveInteractiveComponents(); KickoffExtract(); } } private void RemoveInteractiveComponents() { if (this.btnContents.Visible) { txtPostUnpackCmdLine.Enabled = txtPostUnpackCmdLine.Visible = false; chk_ExeAfterUnpack.Enabled = chk_ExeAfterUnpack.Visible = false; chk_Remove.Enabled = chk_Remove.Visible = false; comboExistingFileAction.Enabled = comboExistingFileAction.Visible = false; label1.Enabled = label1.Visible = false; chk_OpenExplorer.Checked = false; chk_OpenExplorer.Enabled = chk_OpenExplorer.Visible = false; btnDirBrowse.Enabled = btnDirBrowse.Visible = false; btnContents.Enabled = btnContents.Visible = false; btnExtract.Enabled = btnExtract.Visible = false; // adjust the position of all the remaining UI int delta = this.progressBar1.Location.Y - this.chk_OpenExplorer.Location.Y ; this.MinimumSize = new System.Drawing.Size(this.MinimumSize.Width, this.MinimumSize.Height - (delta -4)); MoveDown(this.txtExtractDirectory, delta); MoveDown(this.lblExtractDir, delta); // finally, adjust the size of the form this.Size = new System.Drawing.Size(this.Width, this.Height - (delta-4)); if (txtComment.Visible) this.txtComment.Size = new System.Drawing.Size(this.txtComment.Width, this.txtComment.Height + delta); } } // workitem 8925 private void chk_ExeAfterUnpack_CheckedChanged(object sender, EventArgs e) { this.chk_Remove.Enabled = (this.chk_ExeAfterUnpack.Checked); } private void btnDirBrowse_Click(object sender, EventArgs e) { Ionic.Utils.FolderBrowserDialogEx dlg1 = new Ionic.Utils.FolderBrowserDialogEx(); dlg1.Description = "Select a folder for the extracted files:"; dlg1.ShowNewFolderButton = true; dlg1.ShowEditBox = true; //dlg1.NewStyle = false; if (Directory.Exists(txtExtractDirectory.Text)) dlg1.SelectedPath = txtExtractDirectory.Text; else { string d = txtExtractDirectory.Text; while (d.Length > 2 && !Directory.Exists(d)) { d = Path.GetDirectoryName(d); } if (d.Length < 2) dlg1.SelectedPath = Environment.GetFolderPath(Environment.SpecialFolder.Personal); else dlg1.SelectedPath = d; } dlg1.ShowFullPathInEditBox = true; //dlg1.RootFolder = System.Environment.SpecialFolder.MyComputer; // Show the FolderBrowserDialog. DialogResult result = dlg1.ShowDialog(); if (result == DialogResult.OK) { txtExtractDirectory.Text = dlg1.SelectedPath; } } private void btnExtract_Click(object sender, EventArgs e) { KickoffExtract(); } private void KickoffExtract() { // disable most of the UI: this.btnContents.Enabled = false; this.btnExtract.Enabled = false; this.chk_OpenExplorer.Enabled = false; this.comboExistingFileAction.Enabled = false; this.label1.Enabled = false; this.chk_ExeAfterUnpack.Enabled = false; this.chk_Remove.Enabled = false; // workitem 8925 this.txtExtractDirectory.Enabled = false; this.txtPostUnpackCmdLine.Enabled = false; this.btnDirBrowse.Enabled = false; this.btnExtract.Text = "Extracting..."; ThreadPool.QueueUserWorkItem(new WaitCallback(DoExtract), null); //System.Threading.Thread _workerThread = new System.Threading.Thread(this.DoExtract); //_workerThread.Name = "Zip Extractor thread"; //_workerThread.Start(null); this.Cursor = Cursors.WaitCursor; } private void DoExtract(Object obj) { List itemsExtracted = new List(); string targetDirectory = txtExtractDirectory.Text; global::Ionic.Zip.ExtractExistingFileAction WantOverwrite = (Ionic.Zip.ExtractExistingFileAction) Overwrite; bool extractCancelled = false; System.Collections.Generic.List didNotOverwrite = new System.Collections.Generic.List(); _setCancel = false; string currentPassword = ""; SetProgressBars(); try { // zip has already been set, when opening the exe. zip.ExtractProgress += ExtractProgress; foreach (global::Ionic.Zip.ZipEntry entry in zip) { if (_setCancel) { extractCancelled = true; break; } if (entry.Encryption == global::Ionic.Zip.EncryptionAlgorithm.None) { try { entry.Extract(targetDirectory, WantOverwrite); entryCount++; itemsExtracted.Add(entry.FileName); } catch (Exception ex1) { if (WantOverwrite != global::Ionic.Zip.ExtractExistingFileAction.OverwriteSilently && ex1.Message.Contains("already exists.")) { // The file exists, but the user did not ask for overwrite. didNotOverwrite.Add(" " + entry.FileName); } else if (WantOverwrite == global::Ionic.Zip.ExtractExistingFileAction.OverwriteSilently || ex1.Message.Contains("already exists.")) { DialogResult result = MessageBox.Show(String.Format("Failed to extract entry {0} -- {1}", entry.FileName, ex1.Message), String.Format("Error Extracting {0}", entry.FileName), MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1); if (result == DialogResult.Cancel) { _setCancel = true; break; } } } } else { bool done = false; while (!done) { if (currentPassword == "") { string t = PromptForPassword(entry.FileName); if (t == "") { done = true; // escape ExtractWithPassword loop continue; } currentPassword = t; } if (currentPassword == null) // cancel all { _setCancel = true; currentPassword = ""; break; } try { entry.ExtractWithPassword(targetDirectory, WantOverwrite, currentPassword); entryCount++; itemsExtracted.Add(entry.FileName); done= true; } catch (Exception ex2) { // Retry here in the case of bad password. if (ex2 as Ionic.Zip.BadPasswordException != null) { currentPassword = ""; continue; // loop around, ask for password again } else if (WantOverwrite != global::Ionic.Zip.ExtractExistingFileAction.OverwriteSilently && ex2.Message.Contains("already exists.")) { // The file exists, but the user did not ask for overwrite. didNotOverwrite.Add(" " + entry.FileName); done = true; } else if (WantOverwrite == global::Ionic.Zip.ExtractExistingFileAction.OverwriteSilently && !ex2.Message.Contains("already exists.")) { DialogResult result = MessageBox.Show(String.Format("Failed to extract the password-encrypted entry {0} -- {1}", entry.FileName, ex2.Message.ToString()), String.Format("Error Extracting {0}", entry.FileName), MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1); done= true; if (result == DialogResult.Cancel) { _setCancel = true; break; } } } // catch } // while } // else (encryption) } // foreach } catch (Exception) { MessageBox.Show("The self-extracting zip file is corrupted.", "Error Extracting", MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1); Application.Exit(); } // optionally provide a status report if (didNotOverwrite.Count > 0) { UnzipStatusReport f = new UnzipStatusReport(); if (didNotOverwrite.Count == 1) f.Header = "This file was not extracted because the target file already exists:"; else f.Header = String.Format("These {0} files were not extracted because the target files already exist:", didNotOverwrite.Count); f.Message = String.Join("\r\n", didNotOverwrite.ToArray()); f.ShowDialog(); } SetUiDone(); if (extractCancelled) return; // optionally open explorer if (chk_OpenExplorer.Checked) { string w = System.Environment.GetEnvironmentVariable("WINDIR"); if (w == null) w = "c:\\windows"; try { Process.Start(Path.Combine(w, "explorer.exe"), targetDirectory); } catch { } } // optionally execute a command postUpackExeDone = new ManualResetEvent(false); if (this.chk_ExeAfterUnpack.Checked && PostUnpackCmdLineIsSet()) { try { string[] cmd = SplitCommandLine(txtPostUnpackCmdLine.Text); if (cmd != null && cmd.Length > 0) { object[] args = { cmd, this.chk_Remove.Checked, itemsExtracted, targetDirectory }; ThreadPool.QueueUserWorkItem(new WaitCallback(StartPostUnpackProc), args); } else postUpackExeDone.Set(); // else, nothing. } catch { postUpackExeDone.Set(); } } else postUpackExeDone.Set(); // quit if this is non-interactive if (!Interactive) { postUpackExeDone.WaitOne(); Application.Exit(); } } // workitem 8925 private delegate void StatusProvider(string h, string m); private void ProvideStatus(string header, string message) { if (this.InvokeRequired) { this.Invoke(new StatusProvider(this.ProvideStatus), new object[] { header, message }); } else { UnzipStatusReport f = new UnzipStatusReport(); f.Header= header; f.Message= message; f.ShowDialog(); } } // workitem 8925 private void StartPostUnpackProc(object arg) { Object[] args = (object[]) arg; String[] cmd = (String[]) args[0]; bool removeAfter = (bool) args[1]; List itemsToRemove = (List) args[2]; String basePath = (String) args[3] ; ProcessStartInfo startInfo = new ProcessStartInfo(cmd[0]); startInfo.WorkingDirectory = basePath; startInfo.CreateNoWindow = true; if (cmd.Length > 1) { startInfo.Arguments = cmd[1]; } try { // Process is IDisposable using (Process p = Process.Start(startInfo)) { if (p!=null) { p.WaitForExit(); if (p.ExitCode == 0) { if (removeAfter) { List failedToRemove = new List(); foreach (string s in itemsToRemove) { string fullPath = Path.Combine(basePath,s); try { if (File.Exists(fullPath)) File.Delete(fullPath); else if (Directory.Exists(fullPath)) Directory.Delete(fullPath, true); } catch { failedToRemove.Add(s); } if (failedToRemove.Count > 0) { string header = (failedToRemove.Count == 1) ? "This file was not removed:" : String.Format("These {0} files were not removed:", failedToRemove.Count); string message = String.Join("\r\n", failedToRemove.ToArray()); ProvideStatus(header, message); } } } } else { ProvideStatus("Error Running Post-Unpack command", String.Format("Post-extract command failed, exit code {0}", p.ExitCode)); } } } } catch (Exception exc1) { ProvideStatus("Error Running Post-Unpack command", String.Format("The post-extract command failed: {0}", exc1.Message)); } postUpackExeDone.Set(); } private void SetUiDone() { if (this.btnExtract.InvokeRequired) { this.btnExtract.Invoke(new MethodInvoker(this.SetUiDone)); } else { this.lblStatus.Text = String.Format("Finished extracting {0} entries.", entryCount); btnExtract.Text = "Extracted."; btnExtract.Enabled = false; btnCancel.Text = "Quit"; _setCancel = true; this.Cursor = Cursors.Default; } } private void ExtractProgress(object sender, ExtractProgressEventArgs e) { if (e.EventType == ZipProgressEventType.Extracting_EntryBytesWritten) { StepEntryProgress(e); } else if (e.EventType == ZipProgressEventType.Extracting_AfterExtractEntry) { StepArchiveProgress(e); } if (_setCancel) e.Cancel = true; } private void StepArchiveProgress(ExtractProgressEventArgs e) { if (this.progressBar1.InvokeRequired) { this.progressBar2.Invoke(new ExtractEntryProgress(this.StepArchiveProgress), new object[] { e }); } else { this.progressBar1.PerformStep(); // reset the progress bar for the entry: this.progressBar2.Value = this.progressBar2.Maximum = 1; this.lblStatus.Text = ""; this.Update(); } } private void StepEntryProgress(ExtractProgressEventArgs e) { if (this.progressBar2.InvokeRequired) { this.progressBar2.Invoke(new ExtractEntryProgress(this.StepEntryProgress), new object[] { e }); } else { if (this.progressBar2.Maximum == 1) { // reset Int64 max = e.TotalBytesToTransfer; _progress2MaxFactor = 0; while (max > System.Int32.MaxValue) { max /= 2; _progress2MaxFactor++; } this.progressBar2.Maximum = (int)max; this.lblStatus.Text = String.Format("Extracting {0}/{1}: {2} ...", this.progressBar1.Value, zip.Entries.Count, e.CurrentEntry.FileName); } int xferred = (int)(e.BytesTransferred >> _progress2MaxFactor); this.progressBar2.Value = (xferred >= this.progressBar2.Maximum) ? this.progressBar2.Maximum : xferred; this.Update(); } } private void SetProgressBars() { if (this.progressBar1.InvokeRequired) { this.progressBar1.Invoke(new MethodInvoker(this.SetProgressBars)); } else { this.progressBar1.Value = 0; this.progressBar1.Maximum = zip.Entries.Count; this.progressBar1.Minimum = 0; this.progressBar1.Step = 1; this.progressBar2.Value = 0; this.progressBar2.Minimum = 0; this.progressBar2.Maximum = 1; // will be set later, for each entry. this.progressBar2.Step = 1; } } private String ZipName { get { return Path.GetFileNameWithoutExtension(System.Reflection.Assembly.GetExecutingAssembly().Location); } } private Stream ZipStream { get { if (_s != null) return _s; Assembly a = Assembly.GetExecutingAssembly(); // workitem 7067 _s= File.OpenRead(a.Location); return _s; } } private ZipFile zip { get { if (_zip == null) _zip = global::Ionic.Zip.ZipFile.Read(ZipStream); return _zip; } } private string PromptForPassword(string entryName) { PasswordDialog dlg1 = new PasswordDialog(); dlg1.EntryName = entryName; // ask for password in a loop until user enters a proper one, // or clicks skip or cancel. bool done= false; do { dlg1.ShowDialog(); done = (dlg1.Result != PasswordDialog.PasswordDialogResult.OK || dlg1.Password != ""); } while (!done); if (dlg1.Result == PasswordDialog.PasswordDialogResult.OK) return dlg1.Password; else if (dlg1.Result == PasswordDialog.PasswordDialogResult.Skip) return ""; // cancel return null; } private void btnCancel_Click(object sender, EventArgs e) { if (_setCancel == false) _setCancel = true; else Application.Exit(); } // workitem 6413 private void btnContents_Click(object sender, EventArgs e) { ZipContentsDialog dlg1 = new ZipContentsDialog(); dlg1.ZipFile = zip; dlg1.ShowDialog(); return; } // workitem 8988 private string[] SplitCommandLine(string cmdline) { // if the first char is NOT a double-quote, then just split the line if (cmdline[0]!='"') return cmdline.Split( new char[] {' '}, 2); // the first char is double-quote. Need to verify that there's another one. int ix = cmdline.IndexOf('"', 1); if (ix == -1) return null; // no double-quote - FAIL // if the double-quote is the last char, then just return an array of ONE string if (ix+1 == cmdline.Length) return new string[] { cmdline.Substring(1,ix-1) }; if (cmdline[ix+1]!= ' ') return null; // no space following the double-quote - FAIL // there's definitely another double quote, followed by a space string[] args = new string[2]; args[0] = cmdline.Substring(1,ix-1); while (cmdline[ix+1]==' ') ix++; // go to next non-space char args[1] = cmdline.Substring(ix+1); return args; } private int _progress2MaxFactor; private bool _setCancel; Stream _s; global::Ionic.Zip.ZipFile _zip; } public class UnzipStatusReport : Form { private System.Windows.Forms.Label label1; private System.Windows.Forms.TextBox tbMessage; private System.Windows.Forms.Button btnOK; public UnzipStatusReport() { InitializeComponent(); } private void UnzipStatusReport_Load(object sender, EventArgs e) { this.Text = "DotNetZip: Unzip status report..."; } private void btnOK_Click(object sender, EventArgs e) { DialogResult = DialogResult.OK; this.Close(); } public string Message { set { this.tbMessage.Text = value; this.tbMessage.Select(0,0); } get { return this.tbMessage.Text; } } public string Header { set { this.label1.Text = value; } get { return this.label1.Text; } } /// /// Required designer variable. /// private System.ComponentModel.IContainer components = null; /// /// Clean up any resources being used. /// /// true if managed resources should be disposed; otherwise, false. protected override void Dispose(bool disposing) { if (disposing && (components != null)) { components.Dispose(); } base.Dispose(disposing); } private void InitializeComponent() { this.components = new System.ComponentModel.Container(); this.label1 = new System.Windows.Forms.Label(); this.tbMessage = new System.Windows.Forms.TextBox(); this.btnOK = new System.Windows.Forms.Button(); this.SuspendLayout(); // // label1 // this.label1.AutoSize = true; this.label1.Location = new System.Drawing.Point(12, 12); this.label1.Name = "label1"; this.label1.Size = new System.Drawing.Size(50, 13); this.label1.TabIndex = 2; this.label1.Text = "Status"; // // tbMessage // this.tbMessage.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right) | System.Windows.Forms.AnchorStyles.Bottom))); this.tbMessage.Location = new System.Drawing.Point(20, 31); this.tbMessage.Name = "tbMessage"; this.tbMessage.Multiline = true; this.tbMessage.ScrollBars = ScrollBars.Vertical; this.tbMessage.ReadOnly = true; this.tbMessage.Size = new System.Drawing.Size(340, 110); this.tbMessage.TabIndex = 10; // // btnOK // this.btnOK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.btnOK.Location = new System.Drawing.Point(290, 156); this.btnOK.Name = "btnOK"; this.btnOK.Size = new System.Drawing.Size(82, 24); this.btnOK.TabIndex = 20; this.btnOK.Text = "OK"; this.btnOK.UseVisualStyleBackColor = true; this.btnOK.Click += new System.EventHandler(this.btnOK_Click); // // UnzipStatusReport // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(380, 190); this.Controls.Add(this.label1); this.Controls.Add(this.tbMessage); this.Controls.Add(this.btnOK); this.Name = "UnzipStatusReport"; this.Text = "Not Unzipped"; this.Load += new System.EventHandler(this.UnzipStatusReport_Load); this.ResumeLayout(false); this.PerformLayout(); } } class WinFormsSelfExtractorStubProgram { /// /// The main entry point for the application. /// [STAThread] static void Main() { // For Debugging // if ( !AttachConsole(-1) ) // Attach to a parent process console // AllocConsole(); // Alloc a new console Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new WinFormsSelfExtractorStub()); } [System.Runtime.InteropServices.DllImport("kernel32.dll")] private static extern bool AllocConsole(); [System.Runtime.InteropServices.DllImport("kernel32.dll")] private static extern bool AttachConsole(int pid); } }