DotNetZip can be used from COM Environments

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.

  1. open a CMD.exe prompt.
  2. Install into the GAC: gacutil -i Ionic.Zip.dll
  3. Register for COM use: regasm Ionic.Zip.dll

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.

Using the COM interface to DotNetZip

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.

IDispatch

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.

Overloaded Methods

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.

For the ZipFile class:

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

For the ZipEntry class:

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.

Destroy the ZipFile object

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.

The usage model for the ZipFile object

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.

For enumerations

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.


Using DotNetZip in PHP

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);
  }

Using DotNetZip in Javascript

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();

Using DotNetZip in VBScript

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