You can use DotNetZip from COM environments, via an IDispatch (late bound) interface. This means you can call into the DotNetZip library (the Ionic.Zip.dll assembly) from programming environments like PHP, Perl, Javascript, and VBScript (including old-school ASP pages), among others.
If you download and install the DotNetZip Runtime MSI package, it will set up DotNetZip for use with COM.
If for some reason you prefer to not use the MSI package, then you will need to perform some manual steps to enable DotNetZip for COM usage.
Notes: You will need to be local administrator in order to perform these steps. You need to perform those steps just once, on each computer where COM applications will run that use DotNetZip. The gacutil and regasm tools are included in the .NET Framework SDK.
Via the COM exposure, applications written in COM-capable environments like old-school ASP using VBScript or Javascript, VBScript or Javascript running in Windows Script Host, PHP, Perl, and others, can create instances of the ZipFile class, add entries, and save archives, as any .NET application could. Most of DotNetZip's advanced features are available to these COM environments, including ZIP64 support, self-extracting archives, password-protected zip files, AES Encryption, spanned Zip files, and Unicode support. Beyond creating zips, COM environments can also read zips, modify them, or extract files from zip files.
Some of the advanced features of DotNetZip are not available through COM, including eventing, and streaming.
The key classes in DotNetZip that are exposed to COM are: ZipFile, ZipEntry, and the various ZipExceptions. These are all exposed via IDispatch interfaces - late binding only. (For those familiar with .NET, DotNetZip is decorated with ClassInterfaceType.AutoDispatch.) There is no explicit typelib exposed by DotNetZip.
COM supports calling instance methods and properties on .NET classes; COM does not support calling static methods on .NET objects via interop. To allow the various static methods on the ZipFile class, such as ZipFile.CheckZip() and ZipFile.IsZipFile(), to be called from COM, DotNetZip includes a ComHelper class. Instead of calling ZipFile.IsZipFile(), which is inaccessible to COM clients because it is a static method, COM clients should call Ionic.Zip.ComHelper.IsZipFile(). Use ComHelper as you would, any other class. The methods on the class are documented as with all the other classes in DotNetZip. If you are not programming DotNetZip from COM, you don't need the ComHelper class.
COM does not directly support calling overloaded methods. In a .NET assembbly exposed to COM via interop, only the simplest method in a method group is directly available to COM callers. For example, consider ZipFile.AddFile. There are two overloads. Only the overload that accepts a single string will be accessible via the name "AddFile" to COM clients.
In most cases the thing you need to accomplish is achievable anyway. In the AddFile() case, setting the FileName on the entry after calling AddFile() will do the trick.
Also, the overloaded methods are available, via "mangled" names: each successive overload gets a numeric suffix. Consider the ZipFile.ExtractSelectedEntries method group; there are 5 overloads. The first, simplest, is available via the name ExtractSelectedEntries. Then, additional overloads are available via ExtractSelectedEntries_2, ExtractSelectedEntries_3, and so on. The same is true for other overloaded methods on the ZipFile and ZipEntry classes.
Method Overload | IDispatch name |
AddItem(string) | AddItem |
AddItem(string, string) | AddItem_2 |
AddFile(string) | AddFile |
AddFile(string, string) | AddFile_2 |
UpdateFile(string) | UpdateFile |
UpdateFile(string, string) | UpdateFile_2 |
UpdateDirectory(string) | UpdateDirectory |
UpdateDirectory(string, string) | UpdateDirectory_2 |
UpdateItem(string) | UpdateItem |
UpdateItem(string, string) | UpdateItem_2 |
AddEntry(string,string) | AddEntry |
AddEntry(string,string,Encoding) | AddEntry_2 |
AddEntry(string,Stream) | AddEntry_3 |
AddEntry(string,byte[]) | AddEntry_4 |
UpdateEntry(string,string) | UpdateEntry |
UpdateEntry(string,string,Encoding) | UpdateEntry_2 |
UpdateEntry(string,Stream) | UpdateEntry_3 |
UpdateEntry(string,byte[]) | UpdateEntry_4 |
AddDirectory(string) | AddDirectory |
AddDirectory(string,string) | AddDirectory_2 |
RemoveEntry(ZipEntry) | RemoveEntry |
RemoveEntry(string) | RemoveEntry_2 |
ExtractAll(string) | ExtractAll |
ExtractAll(string, bool) | ExtractAll_2 |
ExtractAll(string, ExtractExistingFileAction) | ExtractAll_3 |
Save() | Save |
Save(string) | Save_2 |
Save(Stream) | Save_3 |
AddSelectedFiles(string) | AddSelectedFiles |
AddSelectedFiles(string, bool) | AddSelectedFiles_2 |
AddSelectedFiles(string, string) | AddSelectedFiles_3 |
AddSelectedFiles(string, string, bool) | AddSelectedFiles_4 |
AddSelectedFiles(string, string, string) | AddSelectedFiles_5 |
AddSelectedFiles(string, string, string, bool) | AddSelectedFiles_6 |
RemoveSelectedEntries(string) | RemoveSelectedEntries |
AddSelectedFiles(string, string) | RemoveSelectedEntries_2 |
ExtractSelectedEntries(string) | ExtractSelectedEntries |
ExtractSelectedEntries(string, ExtractExistingFileAction) | ExtractSelectedEntries_2 |
ExtractSelectedEntries(string, string) | ExtractSelectedEntries_3 |
ExtractSelectedEntries(string, string, string) | ExtractSelectedEntries_4 |
ExtractSelectedEntries(string, string, string, ExtractExistingFileAction) | ExtractSelectedEntries_5 |
SaveSelfExtractor(string, SelfExtractorFlavor) | SaveSelfExtractor |
SaveSelfExtractor(string, SelfExtractorFlavor, string) | SaveSelfExtractor_2 |
SaveSelfExtractor(string, SelfExtractorFlavor, string, string) | SaveSelfExtractor_3 |
Method Overload | IDispatch name |
Extract() | Extract |
Extract(ExtractExistingFileAction) | Extract_2 |
Extract(Stream) | Extract_3 |
Extract(string) | Extract_4 |
Extract(string, ExtractExistingFileAction) | Extract_5 |
ExtractWithPassword(string) | ExtractWithPassword |
ExtractWithPassword(string,string) | ExtractWithPassword_2 |
ExtractWithPassword(ExtractExistingFileAction,string) | ExtractWithPassword_3 |
ExtractWithPassword(string, ExtractExistingFileAction, string) | ExtractWithPassword_4 |
ExtractWithPassword(Stream, string) | ExtractWithPassword_5 |
The bad news is that the mappings between names and actual methods will change over releases of DotNetZip. This means depending on these names is a bit fragile, but it will work.
After you call .Dispose() on the ZipFile object, you should destroy it completely. In VBSCript, this is done by setting the object reference to Nothing.
After you initialize a ZipFile object, you can't reuse the same object instance for another zip file. If for example, you have a set of 6 zip files, and you want to read and extract them in a loop, then you'll need to instantiate a new ZipFile object to read each one. You should call Dispose() on each one when you're finished, and then set it to null/Nothing.
DotNetZip exposes various enumerations to specify behavior in the interface - for example, the Ionic.Zlib.CompressionLevel enum, and the Ionic.Zip.ExtractExistingFileAction enum. Enums are not available to IDispatch clients. COM applications that need to use enum values can simply use the integer equivalent for those enums. In most cases those integer values are specified in the documentation for the enum. For example, for Ionic.Zip.ExtractExistingFileAction, the value of Throw is 0, while OverwriteSilently is 1.
Some examples follow.
This is a PHP script that dynamically creates a ZIP file on the server, then downloads it to the requesting client. The Zip archive will use 256-bit AES encryption.
$fname = "zip-generated-from-php-" . date('Y-m-d-His') . ".zip";
$zipOutput = "c:\\temp\\" . $fname;
$zip = new COM("Ionic.Zip.ZipFile");
$zip->Name = $zipOutput;
$dirToZip= "c:\\temp\\psh";
$zip->Encryption = 3;
$zip->Password = "AES-Encryption-Is-Secure";
$zip->AddDirectory($dirToZip);
$zip->Save();
$zip->Dispose();
if (file_exists($zipOutput))
{
header('Cache-Control: no-cache, must-revalidate');
header('Content-Type: application/x-zip');
header('Content-Disposition: attachment; filename=' . $fname);
header('Content-Length: ' . filesize($zipOutput));
readfile($zipOutput);
unlink($zipOutput);
}
This example dynamically creates a zipfile, using AES 256-bit encryption.
var filename = "C:\\temp\\ZipFile-created-from-javascript-" + generateTimestamp() + ".zip";
try
{
WScript.echo("Instantiating a ZipFile object...");
var zip = new ActiveXObject("Ionic.Zip.ZipFile");
WScript.echo("setting the encryption...");
// 3 = AES256, 2 = AES128, 1 = PKZIP, 0 = none
zip.Encryption = 3;
WScript.echo("setting the password...");
zip.Password = "This is the Password.";
WScript.echo("adding a selection of files...");
zip.AddSelectedFiles("*.js");
zip.AddSelectedFiles("*.vbs");
WScript.echo("setting the save name...");
zip.Name = filename;
WScript.echo("Saving...");
zip.Save();
WScript.echo("Disposing...");
zip.Dispose();
WScript.echo("Done.");
}
catch (e2)
{
WScript.echo(e2.number + ": " + e2.name);
WScript.echo(e2.message);
}
This example lists the entries in a zipfile.
var filename = "C:\\temp\\CompressedData.zip";
try
{
WScript.echo("Instantiating a ZipFile object...");
var zip = new ActiveXObject("Ionic.Zip.ZipFile");
WScript.echo("Initialize (Read)...(" + filename + ")");
zip.Initialize(filename);
WScript.echo("listing entries...");
var e = new Enumerator(zip);
for (; !e.atEnd(); e.moveNext())
{
var entry= e.item();
WScript.Echo (" " + entry.FileName);
}
WScript.echo("Disposing...")
zip.Dispose();
WScript.echo("Done.");
}
catch (e2)
{
WScript.echo(e2.number + ": " + e2.name);
WScript.echo(e2.message);
}
This example checks a ZipFile using the ComHelper class.
function checkZip(filename)
{
var obj = new ActiveXObject("Ionic.Zip.ComHelper");
return obj.IsZipFile(filename);
}
function checkZipWithExtract(filename)
{
var obj = new ActiveXObject("Ionic.Zip.ComHelper");
return obj.IsZipFileWithExtract(filename);
}
function main()
{
var result;
var args = WScript.Arguments;
if (args.Length == 1)
{
result = checkZip(args(0));
}
else if (args.Length == 2 && args(0) == "-x")
{
result = checkZipWithExtract(args(1));
}
else
{
WScript.Echo("TestCheckZip.js - check a zipfile using Javascript.");
WScript.Echo(" usage: TestCheckZip.js [-x] ");
WScript.Quit(1);
}
WScript.Echo((result==0)?"That zip is not OK":"That zip is OK");
WScript.Quit(0);
}
main();
This example creates a zipfile, using AES 256-bit encryption.
dim filename
filename = "C:\temp\ZipFile-created-from-VBScript.zip"
WScript.echo("Instantiating a ZipFile object...")
dim zip
set zip = CreateObject("Ionic.Zip.ZipFile")
WScript.echo("Setting the encryption...")
' 3=AES256, 2=AES128, 1=PKZIP, 0=none
zip.Encryption = 3
WScript.echo("setting the password...")
zip.Password = "This is the Password."
WScript.echo("adding a selection of files...")
zip.AddSelectedFiles "*.js"
zip.AddSelectedFiles "*.vbs"
WScript.echo("setting the save name...")
zip.Name = filename
WScript.echo("Saving...")
zip.Save
WScript.echo("Disposing...")
zip.Dispose
zip = Nothing
WScript.echo("Done.")
This example extracts all entries from a zipfile.
WScript.echo("Instantiating a ZipFile object...")
dim zip
set zip = CreateObject("Ionic.Zip.ZipFile")
WScript.echo("Initialize (Read)...")
zip.Initialize("CompressedData.zip")
WScript.echo("setting the password for extraction...")
zip.Password = "This is the Password."
WScript.echo("extracting all files...")
zip.ExtractAll "DotNetZip-extract"
WScript.echo("Disposing...")
zip.Dispose
WScript.echo("Done.")
This example lists the entries in a zipfile, and extracts some of them.
WScript.echo("")
Dim zip
WScript.echo("Instantiating a ZipFile object...")
Set zip = CreateObject("Ionic.Zip.ZipFile")
WScript.echo("Initialize (Read)...")
zip.Initialize filename
Set fso = CreateObject("Scripting.FileSystemObject")
If Not fso.FolderExists("unpack") Then
fso.CreateFolder("unpack")
End If
' Any call to ZipEntry.Extract() will put files into the
' current working directory. So set it here:
Set objShell = CreateObject("Wscript.Shell")
objShell.CurrentDirectory = "unpack"
WScript.echo("listing...")
For Each entry in zip
WScript.echo(" " & entry.FileName)
ext = Right(entry.FileName,4)
If (ext = ".vbs") Then
' set password for extraction if necessary
entry.Password = "This is the Password."
entry.Extract
End If
Next
WScript.echo("Disposing...")
zip.Dispose
WScript.echo("Done.")
This example extracts selected entries from a zip archive, via the ExtractSelectedEntries overload. It uses the mangled name to access the method, as described above.
Sub extractZip()
If Not (extractLocation = "") Then
Dim OverwriteSilently
OverwriteSilently = 1
Dim zip
Set zip = CreateObject("Ionic.Zip.ZipFile")
zip.Initialize filename
If password <> "" Then
zip.Password = password
End If
zip.ExtractSelectedEntries_5 "name = *.xml", Null, extractLocation, OverwriteSilently
zip.Dispose
zip = Nothing
End If
End Sub