jprintmonitor.dll : The c++ part of the java printer port monitor.

  1. What is a Windows Port Monitor.
    A piece of code that receives data from a printer driver and sends it to an output port. Usually this port is a hardware port like a com, lpt, irda or ... whatever port. As it is in the moment this code here only transforms the data stream into a raw byte stream file or a tif file.
  2. What happens during installation of the port monitor.
    The windows installation consists of:
    1. copying the jprintmonitor.dll and the uk.co.mmscomputing.device.printmonitor.jar file into the windows\systems32 folder.
    2. creating "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Print\Monitors\MMSC Port Monitor"
    3. creating "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Print\Monitors\Local Directory Port\Driver" = "jprintmonitor.dll"
    4. restart print spooler.
    5. creating an oem?.inf file in windows\inf folder, where ? is some number.

    You can do this manually as well. Just follow steps 1..4. No need for the oem?.inf file.
    To restart the spooler. Open a 'command prompt' and type:
    net stop spooler RETURN
    net start spooler RETURN
  3. How to uninstall the port monitor.
    I know only the manual way:
    1. Stop spooler: net stop spooler RETURN
    2. Delete registry key "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Print\Monitors\MMSC Port Monitor"
    3. Delete above mentioned files.
    4. Start spooler: net start spooler RETURN
  4. How to update the port monitor.
    1. Stop spooler: net stop spooler RETURN
    2. Copy new jprintmonitor.dll and the uk.co.mmscomputing.device.printmonitor.jar into the windows\systems32 folder.
    3. Start spooler: net start spooler RETURN
  5. How does it work.
    1. When the spooler starts it loads all the monitor libraries listed in the "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Print\Monitors" key. In our case: The spooler loads jprintmonitor.dll and calls DllMain. Nothing happens here.
    2. When you try to print or access the Printers and Faxes folder the spooler calls the jprintmonitors.dll's InitializePrintMonitor function. Here we create a java virtual machine with the class path set to uk.co.mmscomputing.device.printmonitor.jar and initialise a MONITOREX struct. This struct tells the spooler what functions to call. All those functions can be found in monitor.cpp. These functions only call their java counterparts. The functions dealing with enumerating,adding,configuring,deleting and opening ports call static methods in jprintmonitor.java. The other functions dealing with sending the actual data, call functions in Port.java.
      The parameter HANDLE port in these functions is a pointer to a java Port object, created in the Monitor_OpenPort function.
      One other bit we do: In Monitor_EndDocPort we tell the spooler and/or printer that we have finished the job.

      The function Monitor_EnumPorts is probably the most peculiar one. You have to follow certain rules here laid out by Microsoft. You might want to google for an explanation what to do here :) Just one hint: It seems that you must put the strings, as shown in the ddk examples, at the end of the buffer.

      The cpp-part can be compiled like this:
      bcc32 -w-par -tWD -I"c:\borland\bcc55\include" -L"c:\Borland\Bcc55\lib" -e"J:\uk\co\mmscomputing\device\printmonitor\win32\jprintmonitor.dll" "J:\uk\co\mmscomputing\device\printmonitor\win32\*.cpp"
      What you need to get is a copy of the winsplp.h header file which is part of the DDK and which is of course copyrighted by Microsoft.
      With minor changes this code can be compiled as well with Microsofts Visual Studio .NET and the DDK compiler. The DDK compiler produces the smallest file.

    3. When the jvm is created it calls the static part of jprintmonitor.java. This code creates the C:\WINDOWS\system32\uk.co.mmscomputing folder and redirects the System.out stream to log.txt and System.err to err.txt. It tries to load as well its configuration from uk.co.mmscomputing.device.printmonitor.properties.txt
    4. The jprintmonitor.openPort method is called once the spooler connects a printer driver to a port.
      The Port.close method is called when the spooler is stopped or the printer driver is connected to another port.
    5. Port.start is called before the spooler starts sending data with calls to Port.write. After the spooler has send all the data it calls Port.end.
    6. All the other flow control is done via the data the printer driver sends and is handled in PMOutputStream and it's sub classes.
    7. The mmsc fax printer driver sends either commands like cmd[=value]; or data. Data is send line by line. Before it sends data we receive a SendBlockData; command and afterwards we get an EndBlockData; command. Before the SendBlockData; command the driver will send an NumOfDataBytes which tells us how much bytes it is going to send.
      Have a look at the mmscfax.gpd file and PMOutputStream.
      The important point here is that due to the fact that we set *RasterSendAllData?:TRUE,*OutputDataFormat: H_BYTE and *OptimizeLeftBound?: FALSE (a few default settings play an important part here as well) we get essentially the whole bitmap line by line as black/white bits.

      A port can be connected to any printer driver if you configure it with a RAW output stream. What you get is the data the printer driver sends.
      If you connect a printer driver other then mmsc fax printer to a tif outputstream you will probably crash the spooler!

      if jvm 1.6 need to find msvcr71.dll ourselves, otherwise jvm.dll will not load!
      http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6509291