Parallel port interfacing in Win32, using C/C++

In the newer versions of Windows(R) I was left wondering how, if at all, I could read and write my parallel port. Even Borland had dropped support for direct I/O to the hardware.

But now there's inpout32.dll -- which works on Win98SE, Win2K and WinXP. This DLL provides hardware I/O to your computer's parallel port.

Using Borland's Free C++ Command-line Compiler, I wrote a test program which demonstrates I/O to a printer port using inpout32.DLL -- Now you can do port I/O directly from a C program, and compile everything in a DOS console.

NOTE: Test1.c uses pointer function calls.
To use direct function calls, try leaving the code as it is,
and placing two more small "wrapper" functions with different names,
into the original file, before main(). For example,

     short  Input (short portaddr)
          return (inp32)(i);
     void  Output(short portaddr, short datum)
You can name these functions, 'Input' and 'Output' to whatever you want...
Just make sure you also change the code that calls it, e.g. x=Input(i);
(...See Test2.c for sample implementation.)


Parallel port interfacing in Win32, using Java JNI


"Which one is the best choice?"

It depends on how your application is structured. For a simple application, try Jnpout32pkg_v10 and put everything found in folder 'ioTest_pkg' in a development folder of your choice. Then, replace with your application, and be sure to use the declaration

      import jnpout32.*;

Note that the same effect can be achieved by using Jnpout32reg_v10, and follow a similar procedure as above, putting everything found in folder 'ioTest_reg' in a development folder of your choice. Then, replace with your application, and be sure to use the declaration

     import hardware.jnpout32.*;

For bigger applications with a deeper hierarchy of source code, the solution is to use Jnpout32reg_v10, but this does requires a C compiler to rebuild the DLL with the exact relative path to the 'jnpout32' folder.

I think Jnpout32reg_v10 is more versatile in the way it is done, and fundamentally demonstrates the nature of solving a problem by rebuilding a custom DLL for a particular JNI application. After taking some time to study and understand the mechanism of how this DLL uses the RegisterNatives() JNI method, you will probably agree.

For more detailed explanations, download both of them and look in the README files.

Also, you can refer to an online version of the book I used as a reference during my development of the Jnpout32reg_v10 project:
   (Java Native Interface: Programmer's Guide and Specification)


A Warning about 32-bit data types and Addressing Limitations

Inpout32 and its Jnpout32 derivatives are not meant for 32-bit I/O addressing!
By design the DLL and its wrapper calls deal with 16-bit I/O addresses.
This means addresses 0x0000 through 0xFFFF inclusive, which are the extent of
possible I/O addresses in a legacy PC architecture. These addresses are all properly
represented by a 16-bit data type, such as signed short.

Signed or unsigned really doesn't matter for an I/O address, or for a
short range of addresses which don't cross the 32767 boundary. When doing
arithmetic on an I/O address within a device's address space, it shouldn't
involve anything more than adding an offset of 15 or less (typically
no more than 7) to the I/O base address. And yes a short is a full 16 bits;
all 16 bits are passed in the call. This should present no problem to access
devices at a higher I/O address; for example, ((short) 0x9500).

There have been some questions about using a Java 'int' for convenience,
but the wrapper uses 16-bit 'short' because the DLL uses 16-bit 'short',
and in my assessment I say modifying the DLL is a poor solution.
For those who insist on programming a 16-bit I/O application with 32-bit 'int',
here are some suggestions.

  1. Cast to short when making assignments.
    Port_Base_Addr = (short) 0x9500;
    Note that the compiler will keep the lowest 16 bits only.
    int Port_Addr = 0x10AC00;
    Port_Base_Addr = (short) Port_Addr;
    /* Port_Base_Addr now contains 0xAC00. */
  2. Modify the wrapper to accept 'int' and cast to short within the wrapper; for example:
       // wrap ParallelPort output method
    /*   public void output(short port, short value) */
       public void output(int port, short value)
    /*      pp.Out32(port, value); */
          pp.Out32((short) port, value);
       // wrap ParallelPort input method
    /*   public short input(short port) */
       public short input(int port)
    /*       return pp.Inp32(port); */
           return pp.Inp32((short) port);
Also beware of casting the 'short' datum obtained from an input read,
as the compiler may attempt to sign-extend the number, which may not be
what was intended.

When casting such a (signed) short to a (signed) int, usually a mask
is desirable.

   int X = (int) input(Port_Addr);
   X = (X & 0xFFFF);
or alternatively
   static const int mask = 0xFFFF;
   int X = (mask & (int) input(Port_Addr));

Don't forget to visit My Home Page for other things of interest!