This is an old revision of the document!


RedMon

Redirection Port Monitor (RedMon) is a virtual printer port that can redirect output to a file or program which can in turn process the printer data or send it to a physical printer.

Installation
Add Redirected Port (RPT1:)
  • Run cmd as Administrator.
  • Run one of these commands:
    • Add new printer: C:\> rundll32 printui.dll,PrintUIEntry /il
    • Update current printer: C:\> rundll32 printui.dll,PrintUIEntry /n “Printer Name” /p
    • Add Port: Inside the Printer Properties, select Ports (tab) > New Port > Redirected Port > Port Name: “RPT1:”
Configure Redirected Port (RPT1:)

Example Translator

RedMon passes the original print job via STDIN to the program C:\PrinterTranslator.exe. It also passes a command line argument specifying where PrinterTranslator should save the output print job after making its changes. RedMon then takes the file and spools it directly to the selected printer, in this case Zebra TLP 3742.

PrinterTranslator is a basic program which accepts the STDIN input from RedMon, makes a few changes to the formatting and outputs the file. You can see the source code below.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
 
namespace PrinterTranslator
{
  class Program
  {
	  static void Main(string[] args)
	  {
		  // Check if an output filename was provided and close if it wasn't.
		  string Filename = "";
		  if (args.Length == 0)
		  {
			  Console.WriteLine("No file was specified to write the translated data to... closing.");
			  return;
		  }
		  else
		  {
			  Filename = args[0];
		  }
 
		  bool UsingSTDIN = false;
		  string InputFile = "";
		  try
		  {
			  // This function throws an InvalidOperationException when the input is coming from STDIN.
			  UsingSTDIN = System.Console.KeyAvailable;
 
			  if (!UsingSTDIN)
				  return;
		  }
		  catch (InvalidOperationException e)
		  {
			  // Since we got this exception we know we got data from STDIN.
			  InputFile = System.Console.In.ReadToEnd();
		  }
 
		  string[] LinesToProcess = InputFile.Split('\f');
 
		  // Prep the file so we can save the fixed lines as we run through them.
		  StreamWriter OutFile = new StreamWriter(Filename);
 
		  // Fix the file formatting.
		  foreach (string Line in LinesToProcess)
		  {
			  string newLine = Line;
 
			  // Make sure all quotes are ended.
			  if (Line.Contains('"'))
			  {
				  int FirstQuote = Line.IndexOf('"');
 
				  if (FirstQuote != -1)
				  {
					  int LastQuote = Line.LastIndexOf('"');
 
					  if (FirstQuote == LastQuote)
						  newLine += '"';
				  }
			  }
 
			  // Write out the fixed line.
			  // Check if the string already contains a carriage return. 
                          // In that case, we do not want to do a WriteLine as 
                          // we will actually write 2 lines.
			  if (!(newLine == "\r\n"))
			  {
				  OutFile.WriteLine(newLine);
			  }
		  }
		  OutFile.Close();
	  }
  }
}
Example Uploader
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Security;
using System.Web;
 
namespace PrinterUploader
{
    class Program
    {
        const string LABEL_LOG_URL = "http://acme.com/print-log/web/api-raw/create";
 
        static void Main(string[] args)
        {
            bool CreateInputCopy = false;
            string InputFilename = string.Empty;
            string InputFileContent = string.Empty;
            string InputCopyFilename = string.Empty;
 
            #region Process command line parameters
 
            // Check if an output filename was provided and close if it wasn't.
            if (args.Length == 0)
            {
                Console.WriteLine("Usage: PrinterTranslator.exe [/input=<filename>] [/copyinput=<filename>]");
                Console.WriteLine();
                Console.WriteLine("Input takes in a file instead of using stdin input.");
                Console.WriteLine("Copy takes the raw data it receives and writes it out to a file.");
                Console.WriteLine();
                Console.WriteLine("NOTE: ALL FILENAMES MUST BE CONTAINED IN \"QUOTES\".");
                Console.WriteLine();
                Console.WriteLine("Press any key to continue...");
                Console.ReadKey();
                return;
            }
            else
            {
                foreach (string Argument in args)
                {
                    if (Argument.StartsWith("/input="))
                    {
                        InputFilename = Argument.Substring(Argument.IndexOf('=') + 1);
                    }
                    else if (Argument.StartsWith("/copyinput="))
                    {
                        CreateInputCopy = true;
                        InputCopyFilename = Argument.Substring(Argument.IndexOf('=') + 1);
                    }
                }
            }
 
            #endregion
 
            #region Get input from file/stdin
 
            // Try using standard in if an input filename isn't passed in
            if (InputFilename == string.Empty)
            {
                try
                {
                    // This function throws an InvalidOperationException 
                    // when the input is coming from STDIN.
                    bool test = System.Console.KeyAvailable;
                }
                catch (InvalidOperationException)
                {
                    // Since we got this exception we know we got data from STDIN.
                    Console.WriteLine("Using standard in input.");
                    InputFileContent = System.Console.In.ReadToEnd();
                    Console.WriteLine(InputFileContent);
                }
            }
            else
            {
                try
                {
                    Console.WriteLine("Getting input from filename, {0}", InputFilename);
 
                    using (TextReader tr = File.OpenText(InputFilename))
                    {
                        InputFileContent = tr.ReadToEnd();
                    }
                }
                catch (Exception e)
                {
                    if (e is FileNotFoundException || e is DirectoryNotFoundException)
                    {
                        Console.WriteLine("Input file was not found.");
                        System.Threading.Thread.Sleep(5 * 1000);
                    }
 
                    return;
                }
            }
 
            if (InputFileContent == string.Empty)
            {
                Console.WriteLine("No input file content was found.");
                System.Threading.Thread.Sleep(5 * 1000);
            }
 
            #endregion
 
            #region Output copies and handle passthrough
 
            if (CreateInputCopy)
            {
                Console.WriteLine("Creating an input copy, {0}", InputCopyFilename);
 
                try
                {
                    using (StreamWriter CopyFile = new StreamWriter(InputCopyFilename))
                    {
                        CopyFile.Write(InputFileContent);
                        CopyFile.Close();
                    }
                }
                catch
                {
                    Console.WriteLine(string.Format("Copying input to {0} failed.", InputCopyFilename));
                    Console.WriteLine(InputFileContent);
                    System.Threading.Thread.Sleep(5 * 1000);
                }
            }
 
            #endregion
 
            #region Upload the file
 
            // Upload the file
            LogAddressLabel(InputFileContent);
 
            #endregion
        }
 
        public static string LogAddressLabel(string LabelText)
        {
            Dictionary<string, string> postParameters = new Dictionary<string, string>();
 
            postParameters.Add("category", "Address Label");
            postParameters.Add("data", LabelText);
 
            string result = "";
 
            try
            {
                result = HttpPostRequest(LABEL_LOG_URL, postParameters);
            }
            catch (WebException exc)
            {
                // Only ignore errors with: 404 Not Found.
                if (!exc.Message.Contains("(404) Not Found."))
                {
                    throw exc;
                }
            }
 
            return result;
        }
 
        public static string HttpPostRequest(string url, Dictionary<string, string> postParameters, 
            bool mustAuthenticate=false, string aUsername="", string aPassword="")
        {
            string postData = "";
 
            foreach (string key in postParameters.Keys)
            {
                postData += HttpUtility.UrlEncode(key) + "="
                          + HttpUtility.UrlEncode(postParameters[key]) + "&";
            }
 
            HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(url);
            webRequest.Method = "POST";
 
            // authentication
            if (mustAuthenticate)
            {
                webRequest.PreAuthenticate = mustAuthenticate;
                webRequest.AuthenticationLevel = AuthenticationLevel.MutualAuthRequested;
 
                var cache = new CredentialCache();
                cache.Add(new System.Uri(url), 
                    "Basic", 
                    new NetworkCredential(aUsername, aPassword)  // username, password
                );  
                webRequest.Credentials = cache;
                //ServicePointManager.ServerCertificateValidationCallback = new 
                //    RemoteCertificateValidationCallback(AcceptAllCertifications);
            }
 
            byte[] data = System.Text.Encoding.ASCII.GetBytes(postData);
 
            webRequest.ContentType = "application/x-www-form-urlencoded";
            webRequest.ContentLength = data.Length;
 
            Stream requestStream = webRequest.GetRequestStream();
            requestStream.Write(data, 0, data.Length);
            requestStream.Close();
 
            string responseFromServer = "";
            try
            {
                HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse();
                Stream responseStream = webResponse.GetResponseStream();
 
                StreamReader streamReader = new StreamReader(
                    responseStream, System.Text.Encoding.Default
                );
                responseFromServer = streamReader.ReadToEnd();
 
                streamReader.Close();
                responseStream.Close();
                webResponse.Close();
            }
            catch (WebException exc)
            {
                // Do not ignore any web exception
                throw exc;
            }
 
            return responseFromServer;
        }
    }
}