title: How to set up a virtual printer and monitor with UniDrv or XPS driver v3 in Windows
body: <p>I am trying to <strong>create a virtual printer</strong> to capture print outs from applications in my own application.</p>
  
  <p>I have successfully implemented one that uses the Microsoft PostScript driver and produces ps files.  <em>(A lot of code extracted from different open source projects)</em></p>
  
  <p>However, due to licensing issues with GhostScript on production servers, (it is NOT free for business solutions), I want to implement a different <strong>driver that produces XPS files or any other format that I can use to extract text, convert to a PDF, extract images of each page</strong>, etc.</p>
  
  <p>The code that I am using with the postscript driver and <strong>actually works</strong> quite well is as follows:</p>
  
  <pre><code>// Declare the AddPrinterDriver as extern.
  [DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)]
  private static extern bool AddPrinterDriver(String pName, UInt32 Level, ref DRIVER_INFO_3 pDriverInfo);
  
  // Create a function to call it.
  public void AddPrinterDriver(string driverName, string driverPath, string dataPath, string configPath, string helpPath)
  {
      DRIVER_INFO_3 di = new DRIVER_INFO_3();
      di.cVersion = 3;
      di.pName = driverName;
      di.pEnvironment = null;
      di.pDriverPath = driverPath;
      di.pDataFile = dataPath;
      di.pConfigFile = configPath;
      di.pHelpFile = helpPath;
      di.pDependentFiles = "";
      di.pMonitorName = null;
      di.pDefaultDataType = "RAW";
  
      if (!AddPrinterDriver(null, 3, ref di))
      {
           Exception exc = new Win32Exception(Marshal.GetLastWin32Error());
           throw exc;
      }
  }
  </code></pre>
  
  <p>Install Printer method (without proper validation and logging):</p>
  
  <pre><code>public void InstallVirtualPrinter()
  {
      // Declare file names for PostScript printer driver. (Preinstalled in Vista and Up)
      string driverFileName = "PSCRIPT5.DLL";
      string configFileName = "PS5UI.DLL";
      string helpFileName = "PSCRIPT.HLP";
      string dataFileName = "MyCustomConfig.PPD";
  
      string driverPath = null;
      string dataPath = null;
      string configPath = null;
      string helpPath = null;
  
      try
      {
          //Set Printer Driver Path and Files.
          string printerDriverPath = Path.Combine(GetPrinterDirectory(), "3");
  
          // Set the path for the driver files.
          if (!String.IsNullOrWhiteSpace(printerDriverPath))
          {
              driverPath = string.Format("{0}\\{1}", printerDriverPath, driverFileName);
              dataPath = string.Format("{0}\\{1}", printerDriverPath, dataFileName);
              configPath = string.Format("{0}\\{1}", printerDriverPath, configFileName);
              helpPath = string.Format("{0}\\{1}", printerDriverPath, helpFileName);
          }
  
          // Add Printer Monitor
          if (!DoesMonitorExist(PrinterMonitorName))
          {
              AddPrinterMonitor(PrinterMonitorName); 
          }
  
          // Add Printer Port
          if (!DoesPrinterPortExist(PrinterPortName))
          {
              AddPrinterPort(PrinterPortName, PrinterMonitorName);
          }
  
          // Add Printer Driver
          if (!DoesPrinterDriverExist(PrinterDriverName))
          {
              //
              //
              //
              //
              // This references the above method in this SO question.
  
              AddPrinterDriver(PrinterDriverName, driverPath, dataPath, configPath, helpPath);
              //
              // This fails when trying with a driver different than PScript.
              //
          }
  
          // Add Printer
          if (!DoesPrinterExist(PrinterName))
          {
              InstallPrinter(PrinterName, PrinterPortName, PrinterDriverName);
          }
  
          // Configure Virtual Port
          ConfigureVirtualPort(PrinterMonitorName, PrinterPortName);
  
          // Restart Spool Service
          RestartSpoolService();
  
          log.Info("Virtual printer installation completed successfully");
          return;
      }
      catch (Exception exc)
      {
          log.ErrorFormat("An exception has been raise when attempting to install the printer \n{0}", exc);
      }
  }
  </code></pre>
  
  <p>So here is the question:</p>
  
  <p><strong>How can I use a different driver, like UniDrv or XPS to implement the virtual printer/monitor?</strong>.</p>
  
  <p>I have tried with UniDrv by replacing the following lines in the code above:</p>
  
  <pre><code>string driverFileName = "unidrv.dll";
  string dataFileName = "sample.GPD";
  string configFileName = "unidrvui.dll";
  string helpFileName = "unidrv.hlp";
  </code></pre>
  
  <p>When I run the method <code>AddPrinterDriver</code> I get an exception indicating <code>"The system cannot find the file specified"</code>.</p>
  
  <p>It doesn't say what file is missing.  I assume there may be missing some dependencies, or the sample.GPD file that I found is not good.</p>
  
  <p>Any help will be greatly appreciated.</p>