Merging Java and Win32: A new way to develop Windows applications

Learn how to write Win32 applications in Java instead of C++ -- and save yourself some time and effort!

1 2 Page 2
Page 2 of 2
// ========
// zip.java
// ========
import java.io.*;
import java.util.Enumeration;
import java.util.zip.*;
public class zip
{
   // ==================================================================
   // dump_zip
   //
   // Dump the contents of the zip file (the file names of zipped files)
   // to the standard output device.
   //
   // Arguments:
   //
   // zip_name - name of zip archive
   //
   // Return:
   //
   // none
   // ==================================================================
   public static void dump_zip (String zip_name)
   {
      Enumeration list = null;
      ZipEntry ze = null;
      ZipFile zf = null;
      // Check to see if zip_name has an extension.
      // If not (no period character detected) then
      // attach ".zip" to the file name.
      if (zip_name.indexOf ('.') == -1)
          zip_name = zip_name + ".zip";
      try
      {
          zf = new ZipFile (zip_name);
      }
      catch (ZipException e1)
      {
         System.err.println ("ZIP exception: " + e1);
      }
      catch (IOException e2)
      {
         System.err.println ("IO exception: " + e2);
      }
      list = zf.entries ();
      while (list.hasMoreElements ())
      {
         ze = (ZipEntry) list.nextElement ();
         System.out.println (ze.getName ());
      }
   }
   // ===================================
   // extract_zip
   //
   // Extract file from zip archive.  
   //
   // Arguments:
   //
   // zip_name  - name of zip archive
   // file_name - name of file to extract
   //
   // Return:
   //
   // none
   // ===================================
   public static void extract_zip (String zip_name, String file_name)
   {
      BufferedInputStream bis = null;
      byte buf [] = new byte [1024];
      Enumeration list = null;
      FileOutputStream fos = null;
      int ln = 0;
      int sz = 0;
      ZipEntry ze = null;
      ZipFile zf = null;
      // Check to see if zip_name has an extension.
      // If not (no period character detected) then
      // attach ".zip" to the file name.
      if (zip_name.indexOf ('.') == -1)
          zip_name = zip_name + ".zip";
      try
      {
          zf = new ZipFile (zip_name);
      }
      catch (ZipException e1)
      {
         System.err.println ("ZIP exception: " + e1);
      }
      catch (IOException e2)
      {
         System.err.println ("IO exception: " + e2);
      }
      list = zf.entries ();
      while (list.hasMoreElements ())
      {
         ze = (ZipEntry) list.nextElement ();
         sz = (int) ze.getSize ();
         // Compare archive file with file name argument
         // in a case-insensitive manner.
         if (ze.getName ().toUpperCase ().endsWith (file_name.toUpperCase ()))
         {
             try
             {
                bis = new BufferedInputStream (zf.getInputStream (ze));
                fos = new FileOutputStream (new File (file_name));
                while (sz > 0 &&  // workaround for bug
                       (ln = bis.read (buf, 0, Math.min (1024, sz))) != -1)
                {
                   fos.write (buf, 0, ln);
                   sz -= ln;
                }
                bis.close ();
                fos.flush ();
             }
             catch (IOException e3)
             {
                System.err.println ("IO exception: " + e3);
                return;
             }
             System.out.println ("File: " + file_name + " extracted");   
             return;
         }
      }
      System.out.println ("Not found");
   }
   // =============================================
   //
   // main
   //
   // Program entry point.
   //
   // Arguments:
   //
   // args - array of command line argument strings
   //
   // Return:
   //
   // none
   // =============================================
   public static void main (String [] args)
   {
      System.out.println ("zip v1.0\n");
      if (args.length == 1)
          dump_zip (args [0]);
      else
      if (args.length == 3 && args [0].equals ("-x"))
          extract_zip (args [2], args [1]);
      else
      {
          System.err.println ("usage: zip [-x file] zip");
          System.exit (1);
      }
   }
}

Putting it together

Follow these steps to build the ZIP application.

Step 0: The following assumptions have been made:

  • The ZIP application is built using JDK 1.1.5 and Visual C++ 5.0
  • JDK 1.1.5 is installed in the c:\jdk1.1.5 directory
  • The following project settings are in place
    • A release version is being built
    • The Project Settings dialog box includes the line:

      /I "c:\jdk1.1.5\include" /I "c:\jdk1.1.5\include\win32"

      in the Project Options list box

    • javai.lib has been included in the workspace

Step 1: Identify all required files

C++:

  • zip.cpp zip executable driver source file
  • zip.dsp zip executable driver project file
  • zip.dsw zip executable driver workspace file
  • zip.exe zip executable driver deployment file
  • javai.lib import library for JVM

Java:

  • zip.class zip application deployment file
  • zip.java zip application source file

Miscellaneous

  • classes.zip necessary Java classes
  • javai.dll Java Interpreter (JVM)
  • zip.ini support file containing path information

Step 2: Create zip.ini and copy this file into the Windows directory

The zip.ini file contains a single section called CONFIG. There is one entry in this section, PATH. The PATH entry contains the path (without a trailing backslash character) where the ZIP application has been installed. This is shown in the following listing.

[CONFIG]
PATH=c:\zip

Step 3: Create a directory for the ZIP application (ex: c:\zip)

Step 4: Copy the following files into this new directory:

  • classes.zip
  • javai.dll
  • zip.class
  • zip.exe

Step 5: Test the application

Change to the zip directory and type: zip. The following should appear on the screen:

c:\zip>zip
zip v1.0
usage: zip [-x file] zip

If you get to this point, then you've just executed your first dedicated Java/Win32 application. Congratulations!

Beyond ZIP

What comes next? The ZIP example illustrates a console user interface (CUI) Windows application, but Windows can also run graphical user interface (GUI) applications. A next step could be the creation of a standalone Windows GUI application written in Java. If you decide to go this route, however, you'll need some knowledge of various support DLLs that are distributed with the JVM.

The names of the following DLLs are pretty much self-explanatory. The Java Interpreter (or JVM) is stored in the javai.dll file. If you want to create a GUI-style application, you will also need to deploy the winawt.dll file. This file contains awt peer class support code as well as code to handle printing chores.

  • agent.dll
  • javai.dll
  • JdbcOdbc.dll
  • jpeg.dll
  • math.dll
  • mmedia.dll
  • net.dll
  • sysresource.dll
  • winawt.dll
  • zip.dll

If you get into the habit of creating lots of Java/Win32 applications, you may find that you are distributing multiple copies of classes.zip, one per application directory. At eight megabytes a pop, this gets rather expensive in terms of disk space usage. A better solution would be to modify the driver C++ file to obtain two separate paths: one from the initialization (ini) file (or even Windows registry) for the application classes, and another for classes.zip. You could then store classes.zip in a common directory.

A warning

Sun has made it clear through its JDK license agreements that all runtime files are to be distributed without modification. The ZIP example application required no changes to any runtime files, and it is doubtful that any application would need to have these files modified. However, this does not mean that all of these runtime files need to be distributed with any given application. I hope that Sun will relax this restriction.

Wrapping it up

When companies like Microsoft and Sun Microsystems release innovative products like Java and Win32, the computer industry benefits. I believe that the combination of these two technologies will usher in a new era of Windows software that is more robust than equivalent software written purely in C++. The ZIP application, introduced in this article, provides a bare glimpse of what is possible. I think this is exciting -- the potential is great. And who knows, maybe Sun and Microsoft will merge after all!

Jeff is a software engineer employed by EDS (Electronic Data Systems), a consulting firm founded by Ross Perot in the 1960s. He specializes in developing security applications for use with smart cards. He also writes his own Win32 and Java applications, which he sells as shareware.

Learn more about this topic

  • The zip archive contains all of the necessary C++/Java source and deployment files used by this article http://www.javaworld.com/jw-07-1998/java-win32/zip.zip
  • I've found the following resources beneficial when I'm writing applications that use the Java native Interface (JNI).
  • Essential JNI Java Native Interface, by Rob Gordon. PublisherPrentice Hall, Copyright1998. This book dives into JNI, and covers many techniques for calling C++ code with Java and calling Java with C++ code. One chapter focuses on the Invocation API and how to construct a C++ application which embeds the Java Virtual Machine -- in other words, how to create your own AppletViewer.exe program.
  • The JavaWorld article Use native methods to expand the Java environment provides an introductory look at the Java Native Interface http://www.javaworld.com/javaworld/jw-07-1997/jw-07-javadev.html

1 2 Page 2
Page 2 of 2