Getting right to the point, here is the scenario I face:
I have an application coded in VB.net that I added DotNetZip's functionality to by including the .DLL in the output directory of my executable. While it isn't a big deal, I would like someway to compile the source of the DotNetZip Library with my application
and not have to output the .DLL to the same directory as my executable. In other words: I would like to only have one file (the executable) when my application has finished compiling, and not ever have to extract or create a second file to use the functionality
of the Library.
I can compile the Library without any problems, but implementing it in my existing project is proving difficult for me.
If anyone can offer up some advice, I'd definitely appreciate it!
Jan 15, 2009 at 6:30 PM
Edited Jan 15, 2009 at 6:33 PM
There are several ways I can think of that can help you do this.
#1 (this is described briefly in the FAQ on the front page of this site) Use ILMerge to merge your application's assembly with the DotNetZip DLL. ILMerge is a tool available from Microsoft, http://www.microsoft.com/downloads/details.aspx?FamilyID=22914587-b4ad-4eae-87cf-b14ae6a939b0&DisplayLang=en .
It allows you merge distinct assemblies into a single common aggregate. A typical example is the situation you have described: An EXE that references a third-party DLL, and the publisher of the EXE wishes to have a single image, a single file install. Check
it out, this may fit your bill. To implement this at build time, you can add an appropriate post-build event in Visual Studio, or you can add an additional project in your Visual Studio solution that only does the ILMerge step. The new project should have
as a dependency, the project that produces your original, unmerged EXE.
#2: Use "linked" source. What I mean is this: for all .cs files in the source for all the DotNetZip code, in visual studio right click your project, select "Add Existing Item" , and then use the drop-down box that by default is labelled
"Add", and select "Add as link". I think this only works if you have a project that uses C#. So in your case (VB) it won't work.
#3. Embed the DLL as a resource in your app. Then, at runtime, when your app starts up, you add an AssemblyResolver to the AppDomain that extracts the resource into a block of raw bytes, and loads the assembly from the resulting bytestream. It's a bit of
boilerplate code you would add to your app. Everything else about your app stays the same. A self-extracting archive created by DotNetZip works this way. You can look in the Examples\CommandLineSelfExtractorStub.cs file in the source distribution for how
to do this. Of course you would need use VB for the boilerplate, but it is not rocket science to translate. Here's the C# code:
static System.Reflection.Assembly Resolver(object sender, ResolveEventArgs args)
Assembly a1 = Assembly.GetExecutingAssembly();
Assembly a2 = null;
// get the embedded resource
Stream s = a1.GetManifestResourceStream("Ionic.Zip.dll");
int n = 0;
int totalBytesRead = 0;
byte bytes = new byte;
n = s.Read(bytes, 0, bytes.Length);
totalBytesRead += n;
while (n > 0);
byte block = new byte[totalBytesRead];
s.Read(block, 0, block.Length);
a2 = Assembly.Load(block);
To make this last option work, at build time when you construct your app, in Visual Studio, you would have to include Ionic.Zip.dll as an embedded resource to your app, and also include a reference to Ionic.Zip.dll in the project. But then, when you deploy
the app, you would need only to deploy the .exe image, not the DLL.
I think this is probably a question of broad interest, so I will write something up and insert it into the wiki for DotNetZip.
ILMerge worked pretty slick once I figured out the command line syntax. I'm sure either of your other ideas would have worked equally well, but for now, I think I'll stick with this. Thanks for your speedy reply!