1 | // ZipFile.saveSelfExtractor.cs
|
---|
2 | // ------------------------------------------------------------------
|
---|
3 | //
|
---|
4 | // Copyright (c) 2008-2011 Dino Chiesa.
|
---|
5 | // All rights reserved.
|
---|
6 | //
|
---|
7 | // This code module is part of DotNetZip, a zipfile class library.
|
---|
8 | //
|
---|
9 | // ------------------------------------------------------------------
|
---|
10 | //
|
---|
11 | // This code is licensed under the Microsoft Public License.
|
---|
12 | // See the file License.txt for the license details.
|
---|
13 | // More info on: http://dotnetzip.codeplex.com
|
---|
14 | //
|
---|
15 | // ------------------------------------------------------------------
|
---|
16 | //
|
---|
17 | // last saved (in emacs):
|
---|
18 | // Time-stamp: <2011-August-10 19:22:46>
|
---|
19 | //
|
---|
20 | // ------------------------------------------------------------------
|
---|
21 | //
|
---|
22 | // This is a the source module that implements the stuff for saving to a
|
---|
23 | // self-extracting Zip archive.
|
---|
24 | //
|
---|
25 | // ZipFile is set up as a "partial class" - defined in multiple .cs source modules.
|
---|
26 | // This is one of the source modules for the ZipFile class.
|
---|
27 | //
|
---|
28 | // Here's the design: The self-extracting zip file is just a regular managed EXE
|
---|
29 | // file, with embedded resources. The managed code logic instantiates a ZipFile, and
|
---|
30 | // then extracts each entry. The embedded resources include the zip archive content,
|
---|
31 | // as well as the Zip library itself. The latter is required so that self-extracting
|
---|
32 | // can work on any machine, whether or not it has the DotNetZip library installed on
|
---|
33 | // it.
|
---|
34 | //
|
---|
35 | // What we need to do is create the animal I just described, within a method on the
|
---|
36 | // ZipFile class. This source module provides that capability. The method is
|
---|
37 | // SaveSelfExtractor().
|
---|
38 | //
|
---|
39 | // The way the method works: it uses the programmatic interface to the csc.exe
|
---|
40 | // compiler, Microsoft.CSharp.CSharpCodeProvider, to compile "boilerplate"
|
---|
41 | // extraction logic into a new assembly. As part of that compile, we embed within
|
---|
42 | // that assembly the zip archive itself, as well as the Zip library.
|
---|
43 | //
|
---|
44 | // Therefore we need to first save to a temporary zip file, then produce the exe.
|
---|
45 | //
|
---|
46 | // There are a few twists.
|
---|
47 | //
|
---|
48 | // The Visual Studio Project structure is a little weird. There are code files
|
---|
49 | // that ARE NOT compiled during a normal build of the VS Solution. They are
|
---|
50 | // marked as embedded resources. These are the various "boilerplate" modules that
|
---|
51 | // are used in the self-extractor. These modules are: WinFormsSelfExtractorStub.cs
|
---|
52 | // WinFormsSelfExtractorStub.Designer.cs CommandLineSelfExtractorStub.cs
|
---|
53 | // PasswordDialog.cs PasswordDialog.Designer.cs
|
---|
54 | //
|
---|
55 | // At design time, if you want to modify the way the GUI looks, you have to
|
---|
56 | // mark those modules to have a "compile" build action. Then tweak em, test,
|
---|
57 | // etc. Then again mark them as "Embedded resource".
|
---|
58 | //
|
---|
59 | // ------------------------------------------------------------------
|
---|
60 |
|
---|
61 | using System;
|
---|
62 | using System.Reflection;
|
---|
63 | using System.IO;
|
---|
64 | using System.Collections.Generic;
|
---|
65 |
|
---|
66 |
|
---|
67 | namespace OfficeOpenXml.Packaging.Ionic.Zip
|
---|
68 | {
|
---|
69 | #if !NO_SFX
|
---|
70 | /// <summary>
|
---|
71 | /// An enum that provides the different self-extractor flavors
|
---|
72 | /// </summary>
|
---|
73 | internal enum SelfExtractorFlavor
|
---|
74 | {
|
---|
75 | /// <summary>
|
---|
76 | /// A self-extracting zip archive that runs from the console or
|
---|
77 | /// command line.
|
---|
78 | /// </summary>
|
---|
79 | ConsoleApplication = 0,
|
---|
80 |
|
---|
81 | /// <summary>
|
---|
82 | /// A self-extracting zip archive that presents a graphical user
|
---|
83 | /// interface when it is executed.
|
---|
84 | /// </summary>
|
---|
85 | WinFormsApplication,
|
---|
86 | }
|
---|
87 |
|
---|
88 | /// <summary>
|
---|
89 | /// The options for generating a self-extracting archive.
|
---|
90 | /// </summary>
|
---|
91 | internal class SelfExtractorSaveOptions
|
---|
92 | {
|
---|
93 | /// <summary>
|
---|
94 | /// The type of SFX to create.
|
---|
95 | /// </summary>
|
---|
96 | public SelfExtractorFlavor Flavor
|
---|
97 | {
|
---|
98 | get;
|
---|
99 | set;
|
---|
100 | }
|
---|
101 |
|
---|
102 | /// <summary>
|
---|
103 | /// The command to run after extraction.
|
---|
104 | /// </summary>
|
---|
105 | ///
|
---|
106 | /// <remarks>
|
---|
107 | /// <para>
|
---|
108 | /// This is optional. Leave it empty (<c>null</c> in C# or <c>Nothing</c> in
|
---|
109 | /// VB) to run no command after extraction.
|
---|
110 | /// </para>
|
---|
111 | ///
|
---|
112 | /// <para>
|
---|
113 | /// If it is non-empty, the SFX will execute the command specified in this
|
---|
114 | /// string on the user's machine, and using the extract directory as the
|
---|
115 | /// working directory for the process, after unpacking the archive. The
|
---|
116 | /// program to execute can include a path, if you like. If you want to execute
|
---|
117 | /// a program that accepts arguments, specify the program name, followed by a
|
---|
118 | /// space, and then the arguments for the program, each separated by a space,
|
---|
119 | /// just as you would on a normal command line. Example: <c>program.exe arg1
|
---|
120 | /// arg2</c>. The string prior to the first space will be taken as the
|
---|
121 | /// program name, and the string following the first space specifies the
|
---|
122 | /// arguments to the program.
|
---|
123 | /// </para>
|
---|
124 | ///
|
---|
125 | /// <para>
|
---|
126 | /// If you want to execute a program that has a space in the name or path of
|
---|
127 | /// the file, surround the program name in double-quotes. The first character
|
---|
128 | /// of the command line should be a double-quote character, and there must be
|
---|
129 | /// a matching double-quote following the end of the program file name. Any
|
---|
130 | /// optional arguments to the program follow that, separated by
|
---|
131 | /// spaces. Example: <c>"c:\project files\program name.exe" arg1 arg2</c>.
|
---|
132 | /// </para>
|
---|
133 | ///
|
---|
134 | /// <para>
|
---|
135 | /// If the flavor of the SFX is <c>SelfExtractorFlavor.ConsoleApplication</c>,
|
---|
136 | /// then the SFX starts a new process, using this string as the post-extract
|
---|
137 | /// command line. The SFX waits for the process to exit. The exit code of
|
---|
138 | /// the post-extract command line is returned as the exit code of the
|
---|
139 | /// command-line self-extractor exe. A non-zero exit code is typically used to
|
---|
140 | /// indicated a failure by the program. In the case of an SFX, a non-zero exit
|
---|
141 | /// code may indicate a failure during extraction, OR, it may indicate a
|
---|
142 | /// failure of the run-after-extract program if specified, OR, it may indicate
|
---|
143 | /// the run-after-extract program could not be fuond. There is no way to
|
---|
144 | /// distinguish these conditions from the calling shell, aside from parsing
|
---|
145 | /// the output of the SFX. If you have Quiet set to <c>true</c>, you may not
|
---|
146 | /// see error messages, if a problem occurs.
|
---|
147 | /// </para>
|
---|
148 | ///
|
---|
149 | /// <para>
|
---|
150 | /// If the flavor of the SFX is
|
---|
151 | /// <c>SelfExtractorFlavor.WinFormsApplication</c>, then the SFX starts a new
|
---|
152 | /// process, using this string as the post-extract command line, and using the
|
---|
153 | /// extract directory as the working directory for the process. The SFX does
|
---|
154 | /// not wait for the command to complete, and does not check the exit code of
|
---|
155 | /// the program. If the run-after-extract program cannot be fuond, a message
|
---|
156 | /// box is displayed indicating that fact.
|
---|
157 | /// </para>
|
---|
158 | ///
|
---|
159 | /// <para>
|
---|
160 | /// You can specify environment variables within this string, with a format like
|
---|
161 | /// <c>%NAME%</c>. The value of these variables will be expanded at the time
|
---|
162 | /// the SFX is run. Example: <c>%WINDIR%\system32\xcopy.exe</c> may expand at
|
---|
163 | /// runtime to <c>c:\Windows\System32\xcopy.exe</c>.
|
---|
164 | /// </para>
|
---|
165 | ///
|
---|
166 | /// <para>
|
---|
167 | /// By combining this with the <c>RemoveUnpackedFilesAfterExecute</c>
|
---|
168 | /// flag, you can create an SFX that extracts itself, runs a file that
|
---|
169 | /// was extracted, then deletes all the files that were extracted. If
|
---|
170 | /// you want it to run "invisibly" then set <c>Flavor</c> to
|
---|
171 | /// <c>SelfExtractorFlavor.ConsoleApplication</c>, and set <c>Quiet</c>
|
---|
172 | /// to true. The user running such an EXE will see a console window
|
---|
173 | /// appear, then disappear quickly. You may also want to specify the
|
---|
174 | /// default extract location, with <c>DefaultExtractDirectory</c>.
|
---|
175 | /// </para>
|
---|
176 | ///
|
---|
177 | /// <para>
|
---|
178 | /// If you set <c>Flavor</c> to
|
---|
179 | /// <c>SelfExtractorFlavor.WinFormsApplication</c>, and set <c>Quiet</c> to
|
---|
180 | /// true, then a GUI with progressbars is displayed, but it is
|
---|
181 | /// "non-interactive" - it accepts no input from the user. Instead the SFX
|
---|
182 | /// just automatically unpacks and exits.
|
---|
183 | /// </para>
|
---|
184 | ///
|
---|
185 | /// </remarks>
|
---|
186 | public String PostExtractCommandLine
|
---|
187 | {
|
---|
188 | get;
|
---|
189 | set;
|
---|
190 | }
|
---|
191 |
|
---|
192 | /// <summary>
|
---|
193 | /// The default extract directory the user will see when
|
---|
194 | /// running the self-extracting archive.
|
---|
195 | /// </summary>
|
---|
196 | ///
|
---|
197 | /// <remarks>
|
---|
198 | /// <para>
|
---|
199 | /// Passing null (or Nothing in VB) here will cause the Self Extractor to use
|
---|
200 | /// the the user's personal directory (<see
|
---|
201 | /// cref="Environment.SpecialFolder.Personal"/>) for the default extract
|
---|
202 | /// location.
|
---|
203 | /// </para>
|
---|
204 | ///
|
---|
205 | /// <para>
|
---|
206 | /// This is only a default location. The actual extract location will be
|
---|
207 | /// settable on the command line when the SFX is executed.
|
---|
208 | /// </para>
|
---|
209 | ///
|
---|
210 | /// <para>
|
---|
211 | /// You can specify environment variables within this string,
|
---|
212 | /// with <c>%NAME%</c>. The value of these variables will be
|
---|
213 | /// expanded at the time the SFX is run. Example:
|
---|
214 | /// <c>%USERPROFILE%\Documents\unpack</c> may expand at runtime to
|
---|
215 | /// <c>c:\users\melvin\Documents\unpack</c>.
|
---|
216 | /// </para>
|
---|
217 | /// </remarks>
|
---|
218 | public String DefaultExtractDirectory
|
---|
219 | {
|
---|
220 | get;
|
---|
221 | set;
|
---|
222 | }
|
---|
223 |
|
---|
224 | /// <summary>
|
---|
225 | /// The name of an .ico file in the filesystem to use for the application icon
|
---|
226 | /// for the generated SFX.
|
---|
227 | /// </summary>
|
---|
228 | ///
|
---|
229 | /// <remarks>
|
---|
230 | /// <para>
|
---|
231 | /// Normally, DotNetZip will embed an "zipped folder" icon into the generated
|
---|
232 | /// SFX. If you prefer to use a different icon, you can specify it here. It
|
---|
233 | /// should be a .ico file. This file is passed as the <c>/win32icon</c>
|
---|
234 | /// option to the csc.exe compiler when constructing the SFX file.
|
---|
235 | /// </para>
|
---|
236 | /// </remarks>
|
---|
237 | ///
|
---|
238 | public string IconFile
|
---|
239 | {
|
---|
240 | get;
|
---|
241 | set;
|
---|
242 | }
|
---|
243 |
|
---|
244 | /// <summary>
|
---|
245 | /// Whether the ConsoleApplication SFX will be quiet during extraction.
|
---|
246 | /// </summary>
|
---|
247 | ///
|
---|
248 | /// <remarks>
|
---|
249 | /// <para>
|
---|
250 | /// This option affects the way the generated SFX runs. By default it is
|
---|
251 | /// false. When you set it to true,...
|
---|
252 | /// </para>
|
---|
253 | ///
|
---|
254 | /// <list type="table">
|
---|
255 | /// <listheader>
|
---|
256 | /// <term>Flavor</term>
|
---|
257 | /// <description>Behavior</description>
|
---|
258 | /// </listheader>
|
---|
259 | ///
|
---|
260 | /// <item>
|
---|
261 | /// <term><c>ConsoleApplication</c></term>
|
---|
262 | /// <description><para>no messages will be emitted during successful
|
---|
263 | /// operation.</para> <para> Double-clicking the SFX in Windows
|
---|
264 | /// Explorer or as an attachment in an email will cause a console
|
---|
265 | /// window to appear briefly, before it disappears. If you run the
|
---|
266 | /// ConsoleApplication SFX from the cmd.exe prompt, it runs as a
|
---|
267 | /// normal console app; by default, because it is quiet, it displays
|
---|
268 | /// no messages to the console. If you pass the -v+ command line
|
---|
269 | /// argument to the Console SFX when you run it, you will get verbose
|
---|
270 | /// messages to the console. </para>
|
---|
271 | /// </description>
|
---|
272 | /// </item>
|
---|
273 | ///
|
---|
274 | /// <item>
|
---|
275 | /// <term><c>WinFormsApplication</c></term>
|
---|
276 | /// <description>the SFX extracts automatically when the application
|
---|
277 | /// is launched, with no additional user input.
|
---|
278 | /// </description>
|
---|
279 | /// </item>
|
---|
280 | ///
|
---|
281 | /// </list>
|
---|
282 | ///
|
---|
283 | /// <para>
|
---|
284 | /// When you set it to false,...
|
---|
285 | /// </para>
|
---|
286 | ///
|
---|
287 | /// <list type="table">
|
---|
288 | /// <listheader>
|
---|
289 | /// <term>Flavor</term>
|
---|
290 | /// <description>Behavior</description>
|
---|
291 | /// </listheader>
|
---|
292 | ///
|
---|
293 | /// <item>
|
---|
294 | /// <term><c>ConsoleApplication</c></term>
|
---|
295 | /// <description><para>the extractor will emit a
|
---|
296 | /// message to the console for each entry extracted.</para>
|
---|
297 | /// <para>
|
---|
298 | /// When double-clicking to launch the SFX, the console window will
|
---|
299 | /// remain, and the SFX will emit a message for each file as it
|
---|
300 | /// extracts. The messages fly by quickly, they won't be easily
|
---|
301 | /// readable, unless the extracted files are fairly large.
|
---|
302 | /// </para>
|
---|
303 | /// </description>
|
---|
304 | /// </item>
|
---|
305 | ///
|
---|
306 | /// <item>
|
---|
307 | /// <term><c>WinFormsApplication</c></term>
|
---|
308 | /// <description>the SFX presents a forms UI and allows the user to select
|
---|
309 | /// options before extracting.
|
---|
310 | /// </description>
|
---|
311 | /// </item>
|
---|
312 | ///
|
---|
313 | /// </list>
|
---|
314 | ///
|
---|
315 | /// </remarks>
|
---|
316 | public bool Quiet
|
---|
317 | {
|
---|
318 | get;
|
---|
319 | set;
|
---|
320 | }
|
---|
321 |
|
---|
322 |
|
---|
323 | /// <summary>
|
---|
324 | /// Specify what the self-extractor will do when extracting an entry
|
---|
325 | /// would overwrite an existing file.
|
---|
326 | /// </summary>
|
---|
327 | /// <remarks>
|
---|
328 | /// <para>
|
---|
329 | /// The default behavvior is to Throw.
|
---|
330 | /// </para>
|
---|
331 | /// </remarks>
|
---|
332 | public Ionic.Zip.ExtractExistingFileAction ExtractExistingFile
|
---|
333 | {
|
---|
334 | get;
|
---|
335 | set;
|
---|
336 | }
|
---|
337 |
|
---|
338 |
|
---|
339 | /// <summary>
|
---|
340 | /// Whether to remove the files that have been unpacked, after executing the
|
---|
341 | /// PostExtractCommandLine.
|
---|
342 | /// </summary>
|
---|
343 | ///
|
---|
344 | /// <remarks>
|
---|
345 | /// <para>
|
---|
346 | /// If true, and if there is a <see
|
---|
347 | /// cref="SelfExtractorSaveOptions.PostExtractCommandLine">
|
---|
348 | /// PostExtractCommandLine</see>, and if the command runs successfully,
|
---|
349 | /// then the files that the SFX unpacked will be removed, afterwards. If
|
---|
350 | /// the command does not complete successfully (non-zero return code),
|
---|
351 | /// that is interpreted as a failure, and the extracted files will not be
|
---|
352 | /// removed.
|
---|
353 | /// </para>
|
---|
354 | ///
|
---|
355 | /// <para>
|
---|
356 | /// Setting this flag, and setting <c>Flavor</c> to
|
---|
357 | /// <c>SelfExtractorFlavor.ConsoleApplication</c>, and setting <c>Quiet</c> to
|
---|
358 | /// true, results in an SFX that extracts itself, runs a file that was
|
---|
359 | /// extracted, then deletes all the files that were extracted, with no
|
---|
360 | /// intervention by the user. You may also want to specify the default
|
---|
361 | /// extract location, with <c>DefaultExtractDirectory</c>.
|
---|
362 | /// </para>
|
---|
363 | ///
|
---|
364 | /// </remarks>
|
---|
365 | public bool RemoveUnpackedFilesAfterExecute
|
---|
366 | {
|
---|
367 | get;
|
---|
368 | set;
|
---|
369 | }
|
---|
370 |
|
---|
371 |
|
---|
372 | /// <summary>
|
---|
373 | /// The file version number to embed into the generated EXE. It will show up, for
|
---|
374 | /// example, during a mouseover in Windows Explorer.
|
---|
375 | /// </summary>
|
---|
376 | ///
|
---|
377 | public Version FileVersion
|
---|
378 | {
|
---|
379 | get;
|
---|
380 | set;
|
---|
381 | }
|
---|
382 |
|
---|
383 | /// <summary>
|
---|
384 | /// The product version to embed into the generated EXE. It will show up, for
|
---|
385 | /// example, during a mouseover in Windows Explorer.
|
---|
386 | /// </summary>
|
---|
387 | ///
|
---|
388 | /// <remarks>
|
---|
389 | /// You can use any arbitrary string, but a human-readable version number is
|
---|
390 | /// recommended. For example "v1.2 alpha" or "v4.2 RC2". If you specify nothing,
|
---|
391 | /// then there is no product version embedded into the EXE.
|
---|
392 | /// </remarks>
|
---|
393 | ///
|
---|
394 | public String ProductVersion
|
---|
395 | {
|
---|
396 | get;
|
---|
397 | set;
|
---|
398 | }
|
---|
399 |
|
---|
400 | /// <summary>
|
---|
401 | /// The copyright notice, if any, to embed into the generated EXE.
|
---|
402 | /// </summary>
|
---|
403 | ///
|
---|
404 | /// <remarks>
|
---|
405 | /// It will show up, for example, while viewing properties of the file in
|
---|
406 | /// Windows Explorer. You can use any arbitrary string, but typically you
|
---|
407 | /// want something like "Copyright ᅵ Dino Chiesa 2011".
|
---|
408 | /// </remarks>
|
---|
409 | ///
|
---|
410 | public String Copyright
|
---|
411 | {
|
---|
412 | get;
|
---|
413 | set;
|
---|
414 | }
|
---|
415 |
|
---|
416 |
|
---|
417 | /// <summary>
|
---|
418 | /// The description to embed into the generated EXE.
|
---|
419 | /// </summary>
|
---|
420 | ///
|
---|
421 | /// <remarks>
|
---|
422 | /// Use any arbitrary string. This text will be displayed during a
|
---|
423 | /// mouseover in Windows Explorer. If you specify nothing, then the string
|
---|
424 | /// "DotNetZip SFX Archive" is embedded into the EXE as the description.
|
---|
425 | /// </remarks>
|
---|
426 | ///
|
---|
427 | public String Description
|
---|
428 | {
|
---|
429 | get;
|
---|
430 | set;
|
---|
431 | }
|
---|
432 |
|
---|
433 | /// <summary>
|
---|
434 | /// The product name to embed into the generated EXE.
|
---|
435 | /// </summary>
|
---|
436 | ///
|
---|
437 | /// <remarks>
|
---|
438 | /// Use any arbitrary string. This text will be displayed
|
---|
439 | /// while viewing properties of the EXE file in
|
---|
440 | /// Windows Explorer.
|
---|
441 | /// </remarks>
|
---|
442 | ///
|
---|
443 | public String ProductName
|
---|
444 | {
|
---|
445 | get;
|
---|
446 | set;
|
---|
447 | }
|
---|
448 |
|
---|
449 | /// <summary>
|
---|
450 | /// The title to display in the Window of a GUI SFX, while it extracts.
|
---|
451 | /// </summary>
|
---|
452 | ///
|
---|
453 | /// <remarks>
|
---|
454 | /// <para>
|
---|
455 | /// By default the title show in the GUI window of a self-extractor
|
---|
456 | /// is "DotNetZip Self-extractor (http://DotNetZip.codeplex.com/)".
|
---|
457 | /// You can change that by setting this property before saving the SFX.
|
---|
458 | /// </para>
|
---|
459 | ///
|
---|
460 | /// <para>
|
---|
461 | /// This property has an effect only when producing a Self-extractor
|
---|
462 | /// of flavor <c>SelfExtractorFlavor.WinFormsApplication</c>.
|
---|
463 | /// </para>
|
---|
464 | /// </remarks>
|
---|
465 | ///
|
---|
466 | public String SfxExeWindowTitle
|
---|
467 | {
|
---|
468 | // workitem 12608
|
---|
469 | get;
|
---|
470 | set;
|
---|
471 | }
|
---|
472 |
|
---|
473 | /// <summary>
|
---|
474 | /// Additional options for the csc.exe compiler, when producing the SFX
|
---|
475 | /// EXE.
|
---|
476 | /// </summary>
|
---|
477 | /// <exclude/>
|
---|
478 | public string AdditionalCompilerSwitches
|
---|
479 | {
|
---|
480 | get; set;
|
---|
481 | }
|
---|
482 | }
|
---|
483 |
|
---|
484 |
|
---|
485 |
|
---|
486 |
|
---|
487 | partial class ZipFile
|
---|
488 | {
|
---|
489 | class ExtractorSettings
|
---|
490 | {
|
---|
491 | public SelfExtractorFlavor Flavor;
|
---|
492 | public List<string> ReferencedAssemblies;
|
---|
493 | public List<string> CopyThroughResources;
|
---|
494 | public List<string> ResourcesToCompile;
|
---|
495 | }
|
---|
496 |
|
---|
497 |
|
---|
498 | private static ExtractorSettings[] SettingsList = {
|
---|
499 | new ExtractorSettings() {
|
---|
500 | Flavor = SelfExtractorFlavor.WinFormsApplication,
|
---|
501 | ReferencedAssemblies= new List<string>{
|
---|
502 | "System.dll", "System.Windows.Forms.dll", "System.Drawing.dll"},
|
---|
503 | CopyThroughResources = new List<string>{
|
---|
504 | "Ionic.Zip.WinFormsSelfExtractorStub.resources",
|
---|
505 | "Ionic.Zip.Forms.PasswordDialog.resources",
|
---|
506 | "Ionic.Zip.Forms.ZipContentsDialog.resources"},
|
---|
507 | ResourcesToCompile = new List<string>{
|
---|
508 | "WinFormsSelfExtractorStub.cs",
|
---|
509 | "WinFormsSelfExtractorStub.Designer.cs", // .Designer.cs?
|
---|
510 | "PasswordDialog.cs",
|
---|
511 | "PasswordDialog.Designer.cs", //.Designer.cs"
|
---|
512 | "ZipContentsDialog.cs",
|
---|
513 | "ZipContentsDialog.Designer.cs", //.Designer.cs"
|
---|
514 | "FolderBrowserDialogEx.cs",
|
---|
515 | }
|
---|
516 | },
|
---|
517 | new ExtractorSettings() {
|
---|
518 | Flavor = SelfExtractorFlavor.ConsoleApplication,
|
---|
519 | ReferencedAssemblies= new List<string> { "System.dll", },
|
---|
520 | CopyThroughResources = null,
|
---|
521 | ResourcesToCompile = new List<string>{"CommandLineSelfExtractorStub.cs"}
|
---|
522 | }
|
---|
523 | };
|
---|
524 |
|
---|
525 |
|
---|
526 |
|
---|
527 | //string _defaultExtractLocation;
|
---|
528 | //string _postExtractCmdLine;
|
---|
529 | // string _SetDefaultLocationCode =
|
---|
530 | // "namespace OfficeOpenXml.Packaging.Ionic.Zip { internal partial class WinFormsSelfExtractorStub { partial void _SetDefaultExtractLocation() {" +
|
---|
531 | // " txtExtractDirectory.Text = \"@@VALUE\"; } }}";
|
---|
532 |
|
---|
533 |
|
---|
534 |
|
---|
535 | /// <summary>
|
---|
536 | /// Saves the ZipFile instance to a self-extracting zip archive.
|
---|
537 | /// </summary>
|
---|
538 | ///
|
---|
539 | /// <remarks>
|
---|
540 | ///
|
---|
541 | /// <para>
|
---|
542 | /// The generated exe image will execute on any machine that has the .NET
|
---|
543 | /// Framework 2.0 installed on it. The generated exe image is also a
|
---|
544 | /// valid ZIP file, readable with DotNetZip or another Zip library or tool
|
---|
545 | /// such as WinZip.
|
---|
546 | /// </para>
|
---|
547 | ///
|
---|
548 | /// <para>
|
---|
549 | /// There are two "flavors" of self-extracting archive. The
|
---|
550 | /// <c>WinFormsApplication</c> version will pop up a GUI and allow the
|
---|
551 | /// user to select a target directory into which to extract. There's also
|
---|
552 | /// a checkbox allowing the user to specify to overwrite existing files,
|
---|
553 | /// and another checkbox to allow the user to request that Explorer be
|
---|
554 | /// opened to see the extracted files after extraction. The other flavor
|
---|
555 | /// is <c>ConsoleApplication</c>. A self-extractor generated with that
|
---|
556 | /// flavor setting will run from the command line. It accepts command-line
|
---|
557 | /// options to set the overwrite behavior, and to specify the target
|
---|
558 | /// extraction directory.
|
---|
559 | /// </para>
|
---|
560 | ///
|
---|
561 | /// <para>
|
---|
562 | /// There are a few temporary files created during the saving to a
|
---|
563 | /// self-extracting zip. These files are created in the directory pointed
|
---|
564 | /// to by <see cref="ZipFile.TempFileFolder"/>, which defaults to <see
|
---|
565 | /// cref="System.IO.Path.GetTempPath"/>. These temporary files are
|
---|
566 | /// removed upon successful completion of this method.
|
---|
567 | /// </para>
|
---|
568 | ///
|
---|
569 | /// <para>
|
---|
570 | /// When a user runs the WinForms SFX, the user's personal directory (<see
|
---|
571 | /// cref="Environment.SpecialFolder.Personal">Environment.SpecialFolder.Personal</see>)
|
---|
572 | /// will be used as the default extract location. If you want to set the
|
---|
573 | /// default extract location, you should use the other overload of
|
---|
574 | /// <c>SaveSelfExtractor()</c>/ The user who runs the SFX will have the
|
---|
575 | /// opportunity to change the extract directory before extracting. When
|
---|
576 | /// the user runs the Command-Line SFX, the user must explicitly specify
|
---|
577 | /// the directory to which to extract. The .NET Framework 2.0 is required
|
---|
578 | /// on the computer when the self-extracting archive is run.
|
---|
579 | /// </para>
|
---|
580 | ///
|
---|
581 | /// <para>
|
---|
582 | /// NB: This method is not available in the version of DotNetZip build for
|
---|
583 | /// the .NET Compact Framework, nor in the "Reduced" DotNetZip library.
|
---|
584 | /// </para>
|
---|
585 | ///
|
---|
586 | /// </remarks>
|
---|
587 | ///
|
---|
588 | /// <example>
|
---|
589 | /// <code>
|
---|
590 | /// string DirectoryPath = "c:\\Documents\\Project7";
|
---|
591 | /// using (ZipFile zip = new ZipFile())
|
---|
592 | /// {
|
---|
593 | /// zip.AddDirectory(DirectoryPath, System.IO.Path.GetFileName(DirectoryPath));
|
---|
594 | /// zip.Comment = "This will be embedded into a self-extracting console-based exe";
|
---|
595 | /// zip.SaveSelfExtractor("archive.exe", SelfExtractorFlavor.ConsoleApplication);
|
---|
596 | /// }
|
---|
597 | /// </code>
|
---|
598 | /// <code lang="VB">
|
---|
599 | /// Dim DirectoryPath As String = "c:\Documents\Project7"
|
---|
600 | /// Using zip As New ZipFile()
|
---|
601 | /// zip.AddDirectory(DirectoryPath, System.IO.Path.GetFileName(DirectoryPath))
|
---|
602 | /// zip.Comment = "This will be embedded into a self-extracting console-based exe"
|
---|
603 | /// zip.SaveSelfExtractor("archive.exe", SelfExtractorFlavor.ConsoleApplication)
|
---|
604 | /// End Using
|
---|
605 | /// </code>
|
---|
606 | /// </example>
|
---|
607 | ///
|
---|
608 | /// <param name="exeToGenerate">
|
---|
609 | /// a pathname, possibly fully qualified, to be created. Typically it
|
---|
610 | /// will end in an .exe extension.</param>
|
---|
611 | /// <param name="flavor">
|
---|
612 | /// Indicates whether a Winforms or Console self-extractor is
|
---|
613 | /// desired. </param>
|
---|
614 | internal void SaveSelfExtractor(string exeToGenerate, SelfExtractorFlavor flavor)
|
---|
615 | {
|
---|
616 | SelfExtractorSaveOptions options = new SelfExtractorSaveOptions();
|
---|
617 | options.Flavor = flavor;
|
---|
618 | SaveSelfExtractor(exeToGenerate, options);
|
---|
619 | }
|
---|
620 |
|
---|
621 |
|
---|
622 |
|
---|
623 | /// <summary>
|
---|
624 | /// Saves the ZipFile instance to a self-extracting zip archive, using
|
---|
625 | /// the specified save options.
|
---|
626 | /// </summary>
|
---|
627 | ///
|
---|
628 | /// <remarks>
|
---|
629 | /// <para>
|
---|
630 | /// This method saves a self extracting archive, using the specified save
|
---|
631 | /// options. These options include the flavor of the SFX, the default extract
|
---|
632 | /// directory, the icon file, and so on. See the documentation
|
---|
633 | /// for <see cref="SaveSelfExtractor(string , SelfExtractorFlavor)"/> for more
|
---|
634 | /// details.
|
---|
635 | /// </para>
|
---|
636 | ///
|
---|
637 | /// <para>
|
---|
638 | /// The user who runs the SFX will have the opportunity to change the extract
|
---|
639 | /// directory before extracting. If at the time of extraction, the specified
|
---|
640 | /// directory does not exist, the SFX will create the directory before
|
---|
641 | /// extracting the files.
|
---|
642 | /// </para>
|
---|
643 | ///
|
---|
644 | /// </remarks>
|
---|
645 | ///
|
---|
646 | /// <example>
|
---|
647 | /// This example saves a WinForms-based self-extracting archive EXE that
|
---|
648 | /// will use c:\ExtractHere as the default extract location. The C# code
|
---|
649 | /// shows syntax for .NET 3.0, which uses an object initializer for
|
---|
650 | /// the SelfExtractorOptions object.
|
---|
651 | /// <code>
|
---|
652 | /// string DirectoryPath = "c:\\Documents\\Project7";
|
---|
653 | /// using (ZipFile zip = new ZipFile())
|
---|
654 | /// {
|
---|
655 | /// zip.AddDirectory(DirectoryPath, System.IO.Path.GetFileName(DirectoryPath));
|
---|
656 | /// zip.Comment = "This will be embedded into a self-extracting WinForms-based exe";
|
---|
657 | /// var options = new SelfExtractorOptions
|
---|
658 | /// {
|
---|
659 | /// Flavor = SelfExtractorFlavor.WinFormsApplication,
|
---|
660 | /// DefaultExtractDirectory = "%USERPROFILE%\\ExtractHere",
|
---|
661 | /// PostExtractCommandLine = ExeToRunAfterExtract,
|
---|
662 | /// SfxExeWindowTitle = "My Custom Window Title",
|
---|
663 | /// RemoveUnpackedFilesAfterExecute = true
|
---|
664 | /// };
|
---|
665 | /// zip.SaveSelfExtractor("archive.exe", options);
|
---|
666 | /// }
|
---|
667 | /// </code>
|
---|
668 | /// <code lang="VB">
|
---|
669 | /// Dim DirectoryPath As String = "c:\Documents\Project7"
|
---|
670 | /// Using zip As New ZipFile()
|
---|
671 | /// zip.AddDirectory(DirectoryPath, System.IO.Path.GetFileName(DirectoryPath))
|
---|
672 | /// zip.Comment = "This will be embedded into a self-extracting console-based exe"
|
---|
673 | /// Dim options As New SelfExtractorOptions()
|
---|
674 | /// options.Flavor = SelfExtractorFlavor.WinFormsApplication
|
---|
675 | /// options.DefaultExtractDirectory = "%USERPROFILE%\\ExtractHere"
|
---|
676 | /// options.PostExtractCommandLine = ExeToRunAfterExtract
|
---|
677 | /// options.SfxExeWindowTitle = "My Custom Window Title"
|
---|
678 | /// options.RemoveUnpackedFilesAfterExecute = True
|
---|
679 | /// zip.SaveSelfExtractor("archive.exe", options)
|
---|
680 | /// End Using
|
---|
681 | /// </code>
|
---|
682 | /// </example>
|
---|
683 | ///
|
---|
684 | /// <param name="exeToGenerate">The name of the EXE to generate.</param>
|
---|
685 | /// <param name="options">provides the options for creating the
|
---|
686 | /// Self-extracting archive.</param>
|
---|
687 | internal void SaveSelfExtractor(string exeToGenerate, SelfExtractorSaveOptions options)
|
---|
688 | {
|
---|
689 | // Save an SFX that is both an EXE and a ZIP.
|
---|
690 |
|
---|
691 | // Check for the case where we are re-saving a zip archive
|
---|
692 | // that was originally instantiated with a stream. In that case,
|
---|
693 | // the _name will be null. If so, we set _writestream to null,
|
---|
694 | // which insures that we'll cons up a new WriteStream (with a filesystem
|
---|
695 | // file backing it) in the Save() method.
|
---|
696 | if (_name == null)
|
---|
697 | _writestream = null;
|
---|
698 |
|
---|
699 | _SavingSfx = true;
|
---|
700 | _name = exeToGenerate;
|
---|
701 | if (Directory.Exists(_name))
|
---|
702 | throw new ZipException("Bad Directory", new System.ArgumentException("That name specifies an existing directory. Please specify a filename.", "exeToGenerate"));
|
---|
703 | _contentsChanged = true;
|
---|
704 | _fileAlreadyExists = File.Exists(_name);
|
---|
705 |
|
---|
706 | _SaveSfxStub(exeToGenerate, options);
|
---|
707 |
|
---|
708 | Save();
|
---|
709 | _SavingSfx = false;
|
---|
710 | }
|
---|
711 |
|
---|
712 |
|
---|
713 |
|
---|
714 |
|
---|
715 | private static void ExtractResourceToFile(Assembly a, string resourceName, string filename)
|
---|
716 | {
|
---|
717 | int n = 0;
|
---|
718 | byte[] bytes = new byte[1024];
|
---|
719 | using (Stream instream = a.GetManifestResourceStream(resourceName))
|
---|
720 | {
|
---|
721 | if (instream == null)
|
---|
722 | throw new ZipException(String.Format("missing resource '{0}'", resourceName));
|
---|
723 |
|
---|
724 | using (FileStream outstream = File.OpenWrite(filename))
|
---|
725 | {
|
---|
726 | do
|
---|
727 | {
|
---|
728 | n = instream.Read(bytes, 0, bytes.Length);
|
---|
729 | outstream.Write(bytes, 0, n);
|
---|
730 | } while (n > 0);
|
---|
731 | }
|
---|
732 | }
|
---|
733 | }
|
---|
734 |
|
---|
735 |
|
---|
736 | private void _SaveSfxStub(string exeToGenerate, SelfExtractorSaveOptions options)
|
---|
737 | {
|
---|
738 | string nameOfIconFile = null;
|
---|
739 | string stubExe = null;
|
---|
740 | string unpackedResourceDir = null;
|
---|
741 | string tmpDir = null;
|
---|
742 | try
|
---|
743 | {
|
---|
744 | if (File.Exists(exeToGenerate))
|
---|
745 | {
|
---|
746 | if (Verbose) StatusMessageTextWriter.WriteLine("The existing file ({0}) will be overwritten.", exeToGenerate);
|
---|
747 | }
|
---|
748 | if (!exeToGenerate.EndsWith(".exe"))
|
---|
749 | {
|
---|
750 | if (Verbose) StatusMessageTextWriter.WriteLine("Warning: The generated self-extracting file will not have an .exe extension.");
|
---|
751 | }
|
---|
752 |
|
---|
753 | // workitem 10553
|
---|
754 | tmpDir = TempFileFolder ?? Path.GetDirectoryName(exeToGenerate);
|
---|
755 | stubExe = GenerateTempPathname(tmpDir, "exe");
|
---|
756 |
|
---|
757 | // get the Ionic.Zip assembly
|
---|
758 | Assembly a1 = typeof(ZipFile).Assembly;
|
---|
759 |
|
---|
760 | using (var csharp = new Microsoft.CSharp.CSharpCodeProvider
|
---|
761 | (new Dictionary<string,string>() { { "CompilerVersion", "v2.0" } })) {
|
---|
762 |
|
---|
763 | // The following is a perfect opportunity for a linq query, but
|
---|
764 | // I cannot use it. DotNetZip needs to run on .NET 2.0,
|
---|
765 | // and using LINQ would break that. Here's what it would look
|
---|
766 | // like:
|
---|
767 | //
|
---|
768 | // var settings = (from x in SettingsList
|
---|
769 | // where x.Flavor == flavor
|
---|
770 | // select x).First();
|
---|
771 |
|
---|
772 | ExtractorSettings settings = null;
|
---|
773 | foreach (var x in SettingsList)
|
---|
774 | {
|
---|
775 | if (x.Flavor == options.Flavor)
|
---|
776 | {
|
---|
777 | settings = x;
|
---|
778 | break;
|
---|
779 | }
|
---|
780 | }
|
---|
781 |
|
---|
782 | // sanity check; should never happen
|
---|
783 | if (settings == null)
|
---|
784 | throw new BadStateException(String.Format("While saving a Self-Extracting Zip, Cannot find that flavor ({0})?", options.Flavor));
|
---|
785 |
|
---|
786 | // This is the list of referenced assemblies. Ionic.Zip is
|
---|
787 | // needed here. Also if it is the winforms (gui) extractor, we
|
---|
788 | // need other referenced assemblies, like
|
---|
789 | // System.Windows.Forms.dll, etc.
|
---|
790 | var cp = new System.CodeDom.Compiler.CompilerParameters();
|
---|
791 | cp.ReferencedAssemblies.Add(a1.Location);
|
---|
792 | if (settings.ReferencedAssemblies != null)
|
---|
793 | foreach (string ra in settings.ReferencedAssemblies)
|
---|
794 | cp.ReferencedAssemblies.Add(ra);
|
---|
795 |
|
---|
796 | cp.GenerateInMemory = false;
|
---|
797 | cp.GenerateExecutable = true;
|
---|
798 | cp.IncludeDebugInformation = false;
|
---|
799 | cp.CompilerOptions = "";
|
---|
800 |
|
---|
801 | Assembly a2 = Assembly.GetExecutingAssembly();
|
---|
802 |
|
---|
803 | // Use this to concatenate all the source code resources into a
|
---|
804 | // single module.
|
---|
805 | var sb = new System.Text.StringBuilder();
|
---|
806 |
|
---|
807 | // In case there are compiler errors later, we allocate a source
|
---|
808 | // file name now. If errors are detected, we'll spool the source
|
---|
809 | // code as well as the errors (in comments) into that filename,
|
---|
810 | // and throw an exception with the filename. Makes it easier to
|
---|
811 | // diagnose. This should be rare; most errors happen only
|
---|
812 | // during devlpmt of DotNetZip itself, but there are rare
|
---|
813 | // occasions when they occur in other cases.
|
---|
814 | string sourceFile = GenerateTempPathname(tmpDir, "cs");
|
---|
815 |
|
---|
816 |
|
---|
817 | // // debugging: enumerate the resources in this assembly
|
---|
818 | // Console.WriteLine("Resources in this assembly:");
|
---|
819 | // foreach (string rsrc in a2.GetManifestResourceNames())
|
---|
820 | // {
|
---|
821 | // Console.WriteLine(rsrc);
|
---|
822 | // }
|
---|
823 | // Console.WriteLine();
|
---|
824 |
|
---|
825 |
|
---|
826 | // all the source code is embedded in the DLL as a zip file.
|
---|
827 | using (ZipFile zip = ZipFile.Read(a2.GetManifestResourceStream("Ionic.Zip.Resources.ZippedResources.zip")))
|
---|
828 | {
|
---|
829 | // // debugging: enumerate the files in the embedded zip
|
---|
830 | // Console.WriteLine("Entries in the embbedded zip:");
|
---|
831 | // foreach (ZipEntry entry in zip)
|
---|
832 | // {
|
---|
833 | // Console.WriteLine(entry.FileName);
|
---|
834 | // }
|
---|
835 | // Console.WriteLine();
|
---|
836 |
|
---|
837 | unpackedResourceDir = GenerateTempPathname(tmpDir, "tmp");
|
---|
838 |
|
---|
839 | if (String.IsNullOrEmpty(options.IconFile))
|
---|
840 | {
|
---|
841 | // Use the ico file that is embedded into the Ionic.Zip
|
---|
842 | // DLL itself. To do this we must unpack the icon to
|
---|
843 | // the filesystem, in order to specify it on the cmdline
|
---|
844 | // of csc.exe. This method will remove the unpacked
|
---|
845 | // file later.
|
---|
846 | System.IO.Directory.CreateDirectory(unpackedResourceDir);
|
---|
847 | ZipEntry e = zip["zippedFile.ico"];
|
---|
848 | // Must not extract a readonly file - it will be impossible to
|
---|
849 | // delete later.
|
---|
850 | if ((e.Attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)
|
---|
851 | e.Attributes ^= FileAttributes.ReadOnly;
|
---|
852 | e.Extract(unpackedResourceDir);
|
---|
853 | nameOfIconFile = Path.Combine(unpackedResourceDir, "zippedFile.ico");
|
---|
854 | cp.CompilerOptions += String.Format("/win32icon:\"{0}\"", nameOfIconFile);
|
---|
855 | }
|
---|
856 | else
|
---|
857 | cp.CompilerOptions += String.Format("/win32icon:\"{0}\"", options.IconFile);
|
---|
858 |
|
---|
859 | cp.OutputAssembly = stubExe;
|
---|
860 |
|
---|
861 | if (options.Flavor == SelfExtractorFlavor.WinFormsApplication)
|
---|
862 | cp.CompilerOptions += " /target:winexe";
|
---|
863 |
|
---|
864 | if (!String.IsNullOrEmpty(options.AdditionalCompilerSwitches))
|
---|
865 | cp.CompilerOptions += " " + options.AdditionalCompilerSwitches;
|
---|
866 |
|
---|
867 | if (String.IsNullOrEmpty(cp.CompilerOptions))
|
---|
868 | cp.CompilerOptions = null;
|
---|
869 |
|
---|
870 | if ((settings.CopyThroughResources != null) && (settings.CopyThroughResources.Count != 0))
|
---|
871 | {
|
---|
872 | if (!Directory.Exists(unpackedResourceDir)) System.IO.Directory.CreateDirectory(unpackedResourceDir);
|
---|
873 | foreach (string re in settings.CopyThroughResources)
|
---|
874 | {
|
---|
875 | string filename = Path.Combine(unpackedResourceDir, re);
|
---|
876 |
|
---|
877 | ExtractResourceToFile(a2, re, filename);
|
---|
878 | // add the file into the target assembly as an embedded resource
|
---|
879 | cp.EmbeddedResources.Add(filename);
|
---|
880 | }
|
---|
881 | }
|
---|
882 |
|
---|
883 | // add the Ionic.Utils.Zip DLL as an embedded resource
|
---|
884 | cp.EmbeddedResources.Add(a1.Location);
|
---|
885 |
|
---|
886 | // file header
|
---|
887 | sb.Append("// " + Path.GetFileName(sourceFile) + "\n")
|
---|
888 | .Append("// --------------------------------------------\n//\n")
|
---|
889 | .Append("// This SFX source file was generated by DotNetZip ")
|
---|
890 | .Append(ZipFile.LibraryVersion.ToString())
|
---|
891 | .Append("\n// at ")
|
---|
892 | .Append(System.DateTime.Now.ToString("yyyy MMMM dd HH:mm:ss"))
|
---|
893 | .Append("\n//\n// --------------------------------------------\n\n\n");
|
---|
894 |
|
---|
895 | // assembly attributes
|
---|
896 | if (!String.IsNullOrEmpty(options.Description))
|
---|
897 | sb.Append("[assembly: System.Reflection.AssemblyTitle(\""
|
---|
898 | + options.Description.Replace("\"", "")
|
---|
899 | + "\")]\n");
|
---|
900 | else
|
---|
901 | sb.Append("[assembly: System.Reflection.AssemblyTitle(\"DotNetZip SFX Archive\")]\n");
|
---|
902 |
|
---|
903 | if (!String.IsNullOrEmpty(options.ProductVersion))
|
---|
904 | sb.Append("[assembly: System.Reflection.AssemblyInformationalVersion(\""
|
---|
905 | + options.ProductVersion.Replace("\"", "")
|
---|
906 | + "\")]\n");
|
---|
907 |
|
---|
908 | // workitem
|
---|
909 | string copyright =
|
---|
910 | (String.IsNullOrEmpty(options.Copyright))
|
---|
911 | ? "Extractor: Copyright ᅵ Dino Chiesa 2008-2011"
|
---|
912 | : options.Copyright.Replace("\"", "");
|
---|
913 |
|
---|
914 | if (!String.IsNullOrEmpty(options.ProductName))
|
---|
915 | sb.Append("[assembly: System.Reflection.AssemblyProduct(\"")
|
---|
916 | .Append(options.ProductName.Replace("\"", ""))
|
---|
917 | .Append("\")]\n");
|
---|
918 | else
|
---|
919 | sb.Append("[assembly: System.Reflection.AssemblyProduct(\"DotNetZip\")]\n");
|
---|
920 |
|
---|
921 |
|
---|
922 | sb.Append("[assembly: System.Reflection.AssemblyCopyright(\"" + copyright + "\")]\n")
|
---|
923 | .Append(String.Format("[assembly: System.Reflection.AssemblyVersion(\"{0}\")]\n", ZipFile.LibraryVersion.ToString()));
|
---|
924 | if (options.FileVersion != null)
|
---|
925 | sb.Append(String.Format("[assembly: System.Reflection.AssemblyFileVersion(\"{0}\")]\n",
|
---|
926 | options.FileVersion.ToString()));
|
---|
927 |
|
---|
928 | sb.Append("\n\n\n");
|
---|
929 |
|
---|
930 | // Set the default extract location if it is available
|
---|
931 | string extractLoc = options.DefaultExtractDirectory;
|
---|
932 | if (extractLoc != null)
|
---|
933 | {
|
---|
934 | // remove double-quotes and replace slash with double-slash.
|
---|
935 | // This, because the value is going to be embedded into a
|
---|
936 | // cs file as a quoted string, and it needs to be escaped.
|
---|
937 | extractLoc = extractLoc.Replace("\"", "").Replace("\\", "\\\\");
|
---|
938 | }
|
---|
939 |
|
---|
940 | string postExCmdLine = options.PostExtractCommandLine;
|
---|
941 | if (postExCmdLine != null)
|
---|
942 | {
|
---|
943 | postExCmdLine = postExCmdLine.Replace("\\", "\\\\");
|
---|
944 | postExCmdLine = postExCmdLine.Replace("\"", "\\\"");
|
---|
945 | }
|
---|
946 |
|
---|
947 |
|
---|
948 | foreach (string rc in settings.ResourcesToCompile)
|
---|
949 | {
|
---|
950 | using (Stream s = zip[rc].OpenReader())
|
---|
951 | {
|
---|
952 | if (s == null)
|
---|
953 | throw new ZipException(String.Format("missing resource '{0}'", rc));
|
---|
954 | using (StreamReader sr = new StreamReader(s))
|
---|
955 | {
|
---|
956 | while (sr.Peek() >= 0)
|
---|
957 | {
|
---|
958 | string line = sr.ReadLine();
|
---|
959 | if (extractLoc != null)
|
---|
960 | line = line.Replace("@@EXTRACTLOCATION", extractLoc);
|
---|
961 |
|
---|
962 | line = line.Replace("@@REMOVE_AFTER_EXECUTE", options.RemoveUnpackedFilesAfterExecute.ToString());
|
---|
963 | line = line.Replace("@@QUIET", options.Quiet.ToString());
|
---|
964 | if (!String.IsNullOrEmpty(options.SfxExeWindowTitle))
|
---|
965 |
|
---|
966 | line = line.Replace("@@SFX_EXE_WINDOW_TITLE", options.SfxExeWindowTitle);
|
---|
967 |
|
---|
968 | line = line.Replace("@@EXTRACT_EXISTING_FILE", ((int)options.ExtractExistingFile).ToString());
|
---|
969 |
|
---|
970 | if (postExCmdLine != null)
|
---|
971 | line = line.Replace("@@POST_UNPACK_CMD_LINE", postExCmdLine);
|
---|
972 |
|
---|
973 | sb.Append(line).Append("\n");
|
---|
974 | }
|
---|
975 | }
|
---|
976 | sb.Append("\n\n");
|
---|
977 | }
|
---|
978 | }
|
---|
979 | }
|
---|
980 |
|
---|
981 | string LiteralSource = sb.ToString();
|
---|
982 |
|
---|
983 | #if DEBUGSFX
|
---|
984 | // for debugging only
|
---|
985 | string sourceModule = GenerateTempPathname(tmpDir, "cs");
|
---|
986 | using (StreamWriter sw = File.CreateText(sourceModule))
|
---|
987 | {
|
---|
988 | sw.Write(LiteralSource);
|
---|
989 | }
|
---|
990 | Console.WriteLine("source: {0}", sourceModule);
|
---|
991 | #endif
|
---|
992 |
|
---|
993 | var cr = csharp.CompileAssemblyFromSource(cp, LiteralSource);
|
---|
994 |
|
---|
995 |
|
---|
996 | if (cr == null)
|
---|
997 | throw new SfxGenerationException("Cannot compile the extraction logic!");
|
---|
998 |
|
---|
999 | if (Verbose)
|
---|
1000 | foreach (string output in cr.Output)
|
---|
1001 | StatusMessageTextWriter.WriteLine(output);
|
---|
1002 |
|
---|
1003 | if (cr.Errors.Count != 0)
|
---|
1004 | {
|
---|
1005 | using (TextWriter tw = new StreamWriter(sourceFile))
|
---|
1006 | {
|
---|
1007 | // first, the source we compiled
|
---|
1008 | tw.Write(LiteralSource);
|
---|
1009 |
|
---|
1010 | // now, append the compile errors
|
---|
1011 | tw.Write("\n\n\n// ------------------------------------------------------------------\n");
|
---|
1012 | tw.Write("// Errors during compilation: \n//\n");
|
---|
1013 | string p = Path.GetFileName(sourceFile);
|
---|
1014 |
|
---|
1015 | foreach (System.CodeDom.Compiler.CompilerError error in cr.Errors)
|
---|
1016 | {
|
---|
1017 | tw.Write(String.Format("// {0}({1},{2}): {3} {4}: {5}\n//\n",
|
---|
1018 | p, // 0
|
---|
1019 | error.Line, // 1
|
---|
1020 | error.Column, // 2
|
---|
1021 | error.IsWarning ? "Warning" : "error", // 3
|
---|
1022 | error.ErrorNumber, // 4
|
---|
1023 | error.ErrorText)); // 5
|
---|
1024 | }
|
---|
1025 | }
|
---|
1026 | throw new SfxGenerationException(String.Format("Errors compiling the extraction logic! {0}", sourceFile));
|
---|
1027 | }
|
---|
1028 |
|
---|
1029 | OnSaveEvent(ZipProgressEventType.Saving_AfterCompileSelfExtractor);
|
---|
1030 |
|
---|
1031 | // Now, copy the resulting EXE image to the _writestream.
|
---|
1032 | // Because this stub exe is being saved first, the effect will be to
|
---|
1033 | // concatenate the exe and the zip data together.
|
---|
1034 | using (System.IO.Stream input = System.IO.File.OpenRead(stubExe))
|
---|
1035 | {
|
---|
1036 | byte[] buffer = new byte[4000];
|
---|
1037 | int n = 1;
|
---|
1038 | while (n != 0)
|
---|
1039 | {
|
---|
1040 | n = input.Read(buffer, 0, buffer.Length);
|
---|
1041 | if (n != 0)
|
---|
1042 | WriteStream.Write(buffer, 0, n);
|
---|
1043 | }
|
---|
1044 | }
|
---|
1045 | }
|
---|
1046 |
|
---|
1047 | OnSaveEvent(ZipProgressEventType.Saving_AfterSaveTempArchive);
|
---|
1048 | }
|
---|
1049 | finally
|
---|
1050 | {
|
---|
1051 | try
|
---|
1052 | {
|
---|
1053 | if (Directory.Exists(unpackedResourceDir))
|
---|
1054 | {
|
---|
1055 | try { Directory.Delete(unpackedResourceDir, true); }
|
---|
1056 | catch (System.IO.IOException exc1)
|
---|
1057 | {
|
---|
1058 | StatusMessageTextWriter.WriteLine("Warning: Exception: {0}", exc1);
|
---|
1059 | }
|
---|
1060 | }
|
---|
1061 | if (File.Exists(stubExe))
|
---|
1062 | {
|
---|
1063 | try { File.Delete(stubExe); }
|
---|
1064 | catch (System.IO.IOException exc1)
|
---|
1065 | {
|
---|
1066 | StatusMessageTextWriter.WriteLine("Warning: Exception: {0}", exc1);
|
---|
1067 | }
|
---|
1068 | }
|
---|
1069 | }
|
---|
1070 | catch (System.IO.IOException) { }
|
---|
1071 | }
|
---|
1072 |
|
---|
1073 | return;
|
---|
1074 |
|
---|
1075 | }
|
---|
1076 |
|
---|
1077 |
|
---|
1078 |
|
---|
1079 | internal static string GenerateTempPathname(string dir, string extension)
|
---|
1080 | {
|
---|
1081 | string candidate = null;
|
---|
1082 | String AppName = System.Reflection.Assembly.GetExecutingAssembly().GetName().Name;
|
---|
1083 | do
|
---|
1084 | {
|
---|
1085 | // workitem 13475
|
---|
1086 | string uuid = System.Guid.NewGuid().ToString();
|
---|
1087 |
|
---|
1088 | string Name = String.Format("{0}-{1}-{2}.{3}",
|
---|
1089 | AppName, System.DateTime.Now.ToString("yyyyMMMdd-HHmmss"),
|
---|
1090 | uuid, extension);
|
---|
1091 | candidate = System.IO.Path.Combine(dir, Name);
|
---|
1092 | } while (System.IO.File.Exists(candidate) || System.IO.Directory.Exists(candidate));
|
---|
1093 |
|
---|
1094 | // The candidate path does not exist as a file or directory.
|
---|
1095 | // It can now be created, as a file or directory.
|
---|
1096 | return candidate;
|
---|
1097 | }
|
---|
1098 |
|
---|
1099 | }
|
---|
1100 | #endif
|
---|
1101 | }
|
---|