Without Custom DLL

 

The data stream generated by the Document Converter products can be intercepted for processing other than the default saving to a file or sending by e-mail. The data stream can be sent to a remote location without being saved to the local hard drive, or sent to an application that needs to do some specific processing with the stream before saving it to file.

 

Amyuni PDF Converter allows to intercept directly the data stream using GetAvailableData or GetAvailableDataEx methods, and the StartDocPost, EndPage, EndDocPost, BufferFull and DocCancelled events.

 

Remarks

Using the BatchConvert method in console Application with C#, it requires to use the flag [STAThread].

 

 

Using BatchConverter to print

Imports System.IO

Imports CDIntfEx

 

Module Module1

    Dim printJobs As New Dictionary(Of Integer, BinaryWriter)

    Dim PDF As CDIntfEx.CDIntfEx

 

    Sub Main()

        ' Constants for Activation codes

        Const strLicenseTo As String = "Amyuni Tech. DEMO"

        Const strActivationCode As String =

                  "07EFCDAB010001008037C498F1760CD0526CC963C46CDA42AF3DED36562F3F79DB6D6E670F757ADF1BBBC35F66B21F9A0C0F96D6D079F14672"

        Const AMYUNIPRINTERNAME As String = "Amyuni PDF Converter 650"

 

        ' Declare a new cdintfex object if it does not exist in the form.

        PDF = New CDIntfEx.CDIntfEx

 

        ' Get a reference to the installed printer.

        ' This will fail if the printer name passed to the DriverInit method is 

        ' not found in the printer’s folder

        PDF.DriverInit(AMYUNIPRINTERNAME)

 

        ' The SetDefaultPrinter function sets the system default printer to the one

        ' initialized by the DriverInit functions.

        PDF.SetDefaultPrinter()

 

        ' it needs to have UseGetAvailableData property

        PDF.UseGetAvailableData = True

 

        ' Handlers for PDF's printer events

        AddHandler PDF.StartDocPost, AddressOf PdfStartDocPost

        AddHandler PDF.EndPage, AddressOf PdfEndPage

        AddHandler PDF.EndDocPost, AddressOf PdfEndDocPost

 

        ' Handlers for two new PDF events

        AddHandler PDF.BufferFull, AddressOf PdfBufferFull

        AddHandler PDF.DocCancelled, AddressOf PdfDocCancelled

 

        ' The EnablePrinter() method needs to be called right before each print job. 

        ' Calling the EnablePrinter() method will start a 20 second time-out value

        PDF.EnablePrinter(strLicenseTo, strActivationCode)

 

        'Start Capture of Events (Always after Enabling Printer)

        PDF.CaptureEvents(True)

 

        ' Printing something

        PDF.BatchConvert("c:\temp\Document.rtf")

 

        ' The RestoreDefaultPrinter function resets the system default printer 

        ' to the printer that was the default before the call to SetDefaultPrinter.

        PDF.RestoreDefaultPrinter()

 

        'End Capture of Events

        PDF.CaptureEvents(False)

 

        ' This function will simply detach from an existing printer because the handle was created using DriverInit

        PDF.DriverEnd()

 

        ' Destroy PDF object

        PDF = Nothing

    End Sub

 

 

    ''' <summary>

    '''   Helper that will retrieve all available data from the PDF Converter for the specified print job ID

    ''' </summary>

    ''' <param name="JobID">

    ''' </param>

    Public Sub RetrieveAvailableDataForJob(JobID as Integer)

        While True

            Dim data As Byte() = PDF.GetAvailableDataEx(JobID, 100000)

            Dim size As Integer = data.Length

            If size = 0 Then

                Exit While

            End If

            printJobs(JobID).Write(data, 0, size)

        End While

    End Sub

 

    ''' <summary>

    '''   It is important to handle StartDocPost event and call PDF.GetAvailableDataEx() because 

    '''   the first call sets up a method of communication with the driver for this print job.

    '''   This also enables the driver to notify us when the buffer for this print job is full and 

    '''   needs to be read before printing can resume.

    ''' </summary>

    ''' <param name="JobId">

    ''' </param>

    ''' <param name="hDC">

    ''' </param>

    Public Sub PdfStartDocPost(JobId As Long, hDC As Long) 

 

        ' Open the File

        printJobs(JobID) = new BinaryWriter(File.OpenWrite("C:\Temp\jobID_" + JobID.ToString() + ".pdf"))

 

        ' Retrieve Data

        RetrieveAvailableDataForJob(JobID)

    End Sub

 

    ''' <summary>

    '''   Handling of EndPage event is optional. It can be used to either retrieve any available 

    '''   data after each page is printed or simply to indicate page progress.

    ''' </summary>

    ''' <param name="JobId">

    ''' </param>

    ''' <param name="hDC">

    ''' </param>

    Public Sub PdfEndPage(JobId As Long, hDC As Long)

 

        ' Retrieve Data

        RetrieveAvailableDataForJob(JobID)

    End Sub

 

    ''' <summary>

    '''   In the EndDocPost even we retrieve any remaining data for this print job and we close the associated file we are writing the data to.

    ''' </summary>

    ''' <param name="JobId">The job identifier.</param>

    ''' <param name="hDC">The h dc.</param>

    Public Sub PdfEndDocPost(JobId As Long, hDC As Long) 

 

        ' Retrieve Data last time

        RetrieveAvailableDataForJob(JobID)

 

        'Close the File

        printJobs(JobID).Close()

        printJobs.Remove(JobID)

    End Sub

 

    ''' <summary>

    '''   Handling of the new DocCancelled event is important in case where the printing is in a different process

    '''   and the user cancels the printing from that external application. Without this handler, we cannot know

    '''   if the document finished printing and we will wait indefinitely for that. This is because Windows does not

    '''   send the EndDocPost event when a print job is cancelled.

    ''' </summary>

    ''' <param name="JobId">The job identifier.</param>

    ''' <param name="hDC">The h dc.</param>

    Public Sub PdfDocCancelled(JobId As Long, hDC As Long)

        'Close the File

        printJobs(JobID).Close()

 

        ' might want to delete the file after closing it in this case ?

        printJobs.Remove(JobID)

    End Sub

 

    ''' <summary>

    '''   This even is important to handle for all print jobs because in some cases, the print buffer on the driver side

    '''   might fill before the printer fires any of the other events that we are handling on the PDF side. If we do not handle 

    '''   this even here, it will result in the printer waiting indefinitely for PDF to read the available data before it can re-use

    '''   the space in the buffer. When we handle this event and call PDF.GetAvailableDataEx() we tell the driver that it can go ahead and 

    '''   use the space for writing new data because we read the previous data.

    ''' </summary>

    ''' <param name="JobId">The job identifier.</param>

    ''' <param name="hDC">The h dc.</param>

    Public Sub PdfBufferFull(JobId As Long, hDC As Long)

        ' Retrieve Data

        RetrieveAvailableDataForJob(JobID)

    End Sub

 

End Module

using System;

using System.Collections.Generic;

using System.IO;

 

namespace CDIntfPrintEventsTester

{

    class Program

    {

        static Dictionary<int, BinaryWriter> printJobs = new Dictionary<int, BinaryWriter>();

        static CDIntfEx.CDIntfEx PDF;

 

        [STAThread]

        static void Main(string[] args)

        {

            const string strLicenseTo = "Amyuni Tech. DEMO";

            const string strActivationCode =

                "07EFCDAB010001008037C498F1760CD0526CC963C46CDA42AF3DED36562F3F79DB6D6E670F757ADF1BBBC35F66B21F9A0C0F96D6D079F14672";

            const string AMYUNIPRINTERNAME = "Amyuni PDF Converter 650";

 

            // Declare a new cdintfex object if it does not exist in the form.

            PDF = new CDIntfEx.CDIntfEx();

 

            // Get a reference to the installed printer.

            // This will fail if the printer name passed to the DriverInit method is 

            // not found in the printer’s folder

            PDF.DriverInit(AMYUNIPRINTERNAME);

 

            // The SetDefaultPrinter function sets the system default printer to the one

            // initialized by the DriverInit functions.

            PDF.SetDefaultPrinter();

 

            // it needs to have UseGetAvailableData property

            PDF.UseGetAvailableData = true;

 

            // Handlers for PDF's printer events

            PDF.StartDocPost += PdfStartDocPost;

            PDF.EndPage += PdfEndPage;

            PDF.EndDocPost += PdfEndDocPost;

 

            // Handlers for two new PDF events

            PDF.BufferFull += PdfBufferFull;

            PDF.DocCancelled += PdfDocCancelled;

 

            // The EnablePrinter()method needs to be called right before each print job. 

            // Calling the EnablePrinter()method will start a 20 second time-out value

            PDF.EnablePrinter(strLicenseTo, strActivationCode);

 

            // Start Capture of Events (Always after Enabling Printer)

            PDF.CaptureEvents(true);

 

            // Printing something

            PDF.BatchConvert("c:\\temp\\Document.rtf");

 

            // The RestoreDefaultPrinter function resets the system default printer 

            // to the printer that was the default before the call to SetDefaultPrinter.

            PDF.RestoreDefaultPrinter();

 

            // End Capture of Events

            PDF.CaptureEvents(false);

 

            // This function will simply detach from an existing printer because the handle was created using DriverInit

            PDF.DriverEnd();

 

            // Destroy PDF object

            PDF = null;

        }

 

        /// <summary>

        /// 

        /// Helper that will retrieve all available data from the PDF Converter for the specified print job ID

        /// 

        /// </summary>

        /// <param name="JobID"></param>

        private static void RetrieveAvailableDataForJob(int JobID)

        {

            while (true)

            {

                byte[] data = PDF.GetAvailableDataEx(JobID, 100000);

                int size = data.Length;

                if (size == 0) break;

                printJobs[JobID].Write(data, 0, size);

            }

        }

 

        /// <summary>

        /// 

        /// It is important to handle StartDocPost event and call PDF.GetAvailableDataEx() because 

        /// the first call sets up a method of communication with the driver for this print job.

        /// This also enables the driver to notify us when the buffer for this print job is full and 

        /// needs to be read before printing can resume.

        /// 

        /// </summary>

        /// <param name="JobID"></param>

        /// <param name="hDC"></param>

        private static void PdfStartDocPost(int JobID, int hDC)

        {

            // Open the File

            printJobs[JobID] = new BinaryWriter(File.OpenWrite("C:\\Temp\\jobID_" + JobID.ToString() + ".pdf"));

 

            // Retrieve Data

            RetrieveAvailableDataForJob(JobID);

        }

 

        /// <summary>

        /// 

        /// Handling of EndPage event is optional. It can be used to either retrieve any available 

        /// data after each page is printed or simply to indicate page progress.

        /// 

        /// </summary>

        /// <param name="JobID"></param>

        /// <param name="hDC"></param>

        private static void PdfEndPage(int JobID, int hDC)

        {

            // Retrieve Data

            RetrieveAvailableDataForJob(JobID);

        }

 

        /// <summary>

        /// 

        /// In the EndDocPost even we retrieve any remaining data for this print job and we close the associated file we are writing the data to.

        /// 

        /// </summary>

        /// <param name="JobID"></param>

        /// <param name="hDC"></param>

        private static void PdfEndDocPost(int JobID, int hDC)

        {

            // Retrieve Data last time

            RetrieveAvailableDataForJob(JobID);

 

            // Close the File

            printJobs[JobID].Close();

            printJobs.Remove(JobID);

        }

 

        /// <summary>

        /// 

        /// Handling of the new DocCancelled event is important in case where the printing is in a different process

        /// and the user cancels the printing from that external application. Without this handler, we cannot know

        /// if the document finished printing and we will wait indefinitely for that. This is because Windows does not

        /// send the EndDocPost event when a print job is cancelled.

        /// 

        /// </summary>

        /// <param name="JobID"></param>

        /// <param name="hDC"></param>

        private static void PdfDocCancelled(int JobID, int hDC)

        {

            // Close the File

            printJobs[JobID].Close();

 

            // might want to delete the file after closing it in this case ?

            printJobs.Remove(JobID);

        }

 

        /// <summary>

        /// 

        /// This even is important to handle for all print jobs because in some cases, the print buffer on the driver side

        /// might fill before the printer fires any of the other events that we are handling on the PDF side. If we do not handle 

        /// this even here, it will result in the printer waiting indefinitely for PDF to read the available data before it can re-use

        /// the space in the buffer. When we handle this event and call PDF.GetAvailableDataEx() we tell the driver that it can go ahead and 

        /// use the space for writing new data because we read the previous data.

        /// 

        /// </summary>

        /// <param name="JobID"></param>

        /// <param name="hDC"></param>

        private static void PdfBufferFull(int JobID, int hDC)

        {

            // Retrieve Data

            RetrieveAvailableDataForJob(JobID);

        }

    }

}

 

Using Independent Thread to print

Imports System.Drawing

Imports System.Drawing.Printing

Imports System.IO

Imports CDIntfEx

 

Module Module1

    Dim printJobs As New Dictionary(Of Integer, BinaryWriter)

    Dim PDF As CDIntfEx.CDIntfEx

    Dim page As Integer

    Const AMYUNIPRINTERNAME As String = "Amyuni PDF Converter 650"

 

    Sub Main()

 

        ' Constants for Activation codes

        Const strLicenseTo As String = "Amyuni Tech. DEMO"

        Const strActivationCode As String =

                  "07EFCDAB010001008037C498F1760CD0526CC963C46CDA42AF3DED36562F3F79DB6D6E670F757ADF1BBBC35F66B21F9A0C0F96D6D079F14672"

 

        ' Declare a new cdintfex object if it does not exist in the form.

        PDF = New CDIntfEx.CDIntfEx

 

        ' Get a reference to the installed printer.

        ' This will fail if the printer name passed to the DriverInit method is 

        ' not found in the printer’s folder

        PDF.DriverInit(AMYUNIPRINTERNAME)

 

        ' The SetDefaultPrinter function sets the system default printer to the one

        ' initialized by the DriverInit functions.

        PDF.SetDefaultPrinter()

 

        ' it needs to have UseGetAvailableData property

        PDF.UseGetAvailableData = True

 

        ' Handlers for PDF's printer events

        AddHandler PDF.StartDocPost, AddressOf PdfStartDocPost

        AddHandler PDF.EndPage, AddressOf PdfEndPage

        AddHandler PDF.EndDocPost, AddressOf PdfEndDocPost

 

        ' Handlers for two new PDF events

        AddHandler PDF.BufferFull, AddressOf PdfBufferFull

        AddHandler PDF.DocCancelled, AddressOf PdfDocCancelled

 

        ' The EnablePrinter() method needs to be called right before each print job. 

        ' Calling the EnablePrinter() method will start a 20 second time-out value

        PDF.EnablePrinter(strLicenseTo, strActivationCode)

 

        'Start Capture of Events (Always after Enabling Printer)

        PDF.CaptureEvents(True)

 

        ' Printing something using another thread

        Dim task = new Task(AddressOf DirectPrintingProcess)

        task.Start()

        task.Wait()

 

        ' The RestoreDefaultPrinter function resets the system default printer 

        ' to the printer that was the default before the call to SetDefaultPrinter.

        PDF.RestoreDefaultPrinter()

 

        'End Capture of Events

        PDF.CaptureEvents(False)

 

        ' This function will simply detach from an existing printer because the handle was created using DriverInit

        PDF.DriverEnd()

 

        ' Destroy PDF object

        PDF = Nothing

    End Sub

 

    '''  <summary>

    ''' 

    ''' The document printing function (must be run from a separate thread than the main one in the case of a 32 bit build of this tester.)

    ''' 

    ''' </summary>

    Public Sub DirectPrintingProcess()

        Dim pDoc As PrintDocument = new PrintDocument()

        AddHandler pDoc.PrintPage, AddressOf PrintPage

        pDoc.PrinterSettings.PrinterName = AMYUNIPRINTERNAME

        pDoc.Print()

    End Sub

 

    ''' <summary>

    '''   Helper that will retrieve all available data from the PDF Converter for the specified print job ID

    ''' </summary>

    ''' <param name="JobID">

    ''' </param>

    Public Sub RetrieveAvailableDataForJob(JobID as Integer)

        While True

            Dim data As Byte() = PDF.GetAvailableDataEx(JobID, 100000)

            Dim size As Integer = data.Length

            If size = 0 Then

                Exit While

            End If

            printJobs(JobID).Write(data, 0, size)

        End While

    End Sub

 

    ''' <summary>

    '''   It is important to handle StartDocPost event and call PDF.GetAvailableDataEx() because 

    '''   the first call sets up a method of communication with the driver for this print job.

    '''   This also enables the driver to notify us when the buffer for this print job is full and 

    '''   needs to be read before printing can resume.

    ''' </summary>

    ''' <param name="JobId">

    ''' </param>

    ''' <param name="hDC">

    ''' </param>

    Public Sub PdfStartDocPost(JobId As Long, hDC As Long) 

 

        ' Open the File

        printJobs(JobID) = new BinaryWriter(File.OpenWrite("C:\Temp\jobID_" + JobID.ToString() + ".pdf"))

 

        ' Retrieve Data

        RetrieveAvailableDataForJob(JobID)

    End Sub

 

    ''' <summary>

    '''   Handling of EndPage event is optional. It can be used to either retrieve any available 

    '''   data after each page is printed or simply to indicate page progress.

    ''' </summary>

    ''' <param name="JobId">

    ''' </param>

    ''' <param name="hDC">

    ''' </param>

    Public Sub PdfEndPage(JobId As Long, hDC As Long)

 

        ' Retrieve Data

        RetrieveAvailableDataForJob(JobID)

    End Sub

 

    ''' <summary>

    '''   In the EndDocPost even we retrieve any remaining data for this print job and we close the associated file we are writing the data to.

    ''' </summary>

    ''' <param name="JobId">The job identifier.</param>

    ''' <param name="hDC">The h dc.</param>

    Public Sub PdfEndDocPost(JobId As Long, hDC As Long) 

 

        ' Retrieve Data last time

        RetrieveAvailableDataForJob(JobID)

 

        'Close the File

        printJobs(JobID).Close()

        printJobs.Remove(JobID)

    End Sub

 

    ''' <summary>

    '''   Handling of the new DocCancelled event is important in case where the printing is in a different process

    '''   and the user cancels the printing from that external application. Without this handler, we cannot know

    '''   if the document finished printing and we will wait indefinitely for that. This is because Windows does not

    '''   send the EndDocPost event when a print job is cancelled.

    ''' </summary>

    ''' <param name="JobId">The job identifier.</param>

    ''' <param name="hDC">The h dc.</param>

    Public Sub PdfDocCancelled(JobId As Long, hDC As Long)

        'Close the File

        printJobs(JobID).Close()

 

        ' might want to delete the file after closing it in this case ?

        printJobs.Remove(JobID)

    End Sub

 

    ''' <summary>

    '''   This even is important to handle for all print jobs because in some cases, the print buffer on the driver side

    '''   might fill before the printer fires any of the other events that we are handling on the PDF side. If we do not handle 

    '''   this even here, it will result in the printer waiting indefinitely for PDF to read the available data before it can re-use

    '''   the space in the buffer. When we handle this event and call PDF.GetAvailableDataEx() we tell the driver that it can go ahead and 

    '''   use the space for writing new data because we read the previous data.

    ''' </summary>

    ''' <param name="JobId">The job identifier.</param>

    ''' <param name="hDC">The h dc.</param>

    Public Sub PdfBufferFull(JobId As Long, hDC As Long)

        ' Retrieve Data

        RetrieveAvailableDataForJob(JobID)

    End Sub

 

    ''' <summary>

    ''' 

    ''' The page drawing code used with direct printing

    ''' 

    ''' </summary>

    ''' <param name="sender"></param>

    ''' <param name="e"></param>

    Private Sub PrintPage(sender As Object, e As PrintPageEventArgs)

        Dim g As Graphics = e.Graphics

        Dim font As Font = new Font("Courier", 28)

        Dim brush As SolidBrush = new SolidBrush(Color.FromArgb(255, Color.Blue))

 

        g.FillRectangle(brush, 0, 0, 500, 400)

        g.DrawString("THIS IS A TEST", font, Brushes.White, 100, 100)

 

        page += 1

        e.HasMorePages = page <= 4

    End Sub

End Module

using System;

using System.Collections.Generic;

using System.Diagnostics;

using System.Drawing;

using System.Drawing.Printing;

using System.IO;

using System.Threading;

using System.Threading.Tasks;

 

namespace CDIntfPrintEventsTester

{

    class Program

    {

        static Dictionary<int, BinaryWriter> printJobs = new Dictionary<int, BinaryWriter>();

        static CDIntfEx.CDIntfEx PDF;

        static int page;

        const string AMYUNIPRINTERNAME = "Amyuni PDF Converter 650";

 

        static void Main(string[] args)

        {

            const string strLicenseTo = "Amyuni Tech. DEMO";

            const string strActivationCode =

                "07EFCDAB010001008037C498F1760CD0526CC963C46CDA42AF3DED36562F3F79DB6D6E670F757ADF1BBBC35F66B21F9A0C0F96D6D079F14672";

 

            // Declare a new cdintfex object if it does not exist in the form.

            PDF = new CDIntfEx.CDIntfEx();

 

            // Get a reference to the installed printer.

            // This will fail if the printer name passed to the DriverInit method is 

            // not found in the printer’s folder

            PDF.DriverInit(AMYUNIPRINTERNAME);

 

            // The SetDefaultPrinter function sets the system default printer to the one

            // initialized by the DriverInit functions.

            PDF.SetDefaultPrinter();

 

            // it needs to have UseGetAvailableData property

            PDF.UseGetAvailableData = true;

 

            // Handlers for PDF's printer events

            PDF.StartDocPost += PdfStartDocPost;

            PDF.EndPage += PdfEndPage;

            PDF.EndDocPost += PdfEndDocPost;

 

            // Handlers for two new PDF events

            PDF.BufferFull += PdfBufferFull;

            PDF.DocCancelled += PdfDocCancelled;

 

            // The EnablePrinter()method needs to be called right before each print job. 

            // Calling the EnablePrinter()method will start a 20 second time-out value

            PDF.EnablePrinter(strLicenseTo, strActivationCode);

 

            // Start Capture of Events (Always after Enabling Printer)

            PDF.CaptureEvents(true);

 

            // Printing something using another thread

            Task task = new Task(DirectPrintingProcess);

            task.Start();

            task.Wait();

 

            // The RestoreDefaultPrinter function resets the system default printer 

            // to the printer that was the default before the call to SetDefaultPrinter.

            PDF.RestoreDefaultPrinter();

 

            // End Capture of Events

            PDF.CaptureEvents(false);

 

            // This function will simply detach from an existing printer because the handle was created using DriverInit

            PDF.DriverEnd();

 

            // Destroy PDF object

            PDF = null;

        }

 

        /// <summary>

        /// 

        /// The document printing function (must be run from a separate thread than the main one in the case of a 32 bit build of this tester.)

        /// 

        /// </summary>

        private static void DirectPrintingProcess()

        {

            PrintDocument pDoc = new PrintDocument();

            pDoc.PrintPage += PrintPage;

            pDoc.PrinterSettings.PrinterName = AMYUNIPRINTERNAME;

            pDoc.Print();

        }

 

        /// <summary>

        /// 

        /// Helper that will retrieve all available data from the PDF Converter for the specified print job ID

        /// 

        /// </summary>

        /// <param name="JobID"></param>

        private static void RetrieveAvailableDataForJob(int JobID)

        {

            while (true)

            {

                byte[] data = PDF.GetAvailableDataEx(JobID, 100000);

                int size = data.Length;

                if (size == 0) break;

                printJobs[JobID].Write(data, 0, size);

            }

        }

 

        /// <summary>

        /// 

        /// It is important to handle StartDocPost event and call PDF.GetAvailableDataEx() because 

        /// the first call sets up a method of communication with the driver for this print job.

        /// This also enables the driver to notify us when the buffer for this print job is full and 

        /// needs to be read before printing can resume.

        /// 

        /// </summary>

        /// <param name="JobID"></param>

        /// <param name="hDC"></param>

        private static void PdfStartDocPost(int JobID, int hDC)

        {

            // Open the File

            printJobs[JobID] = new BinaryWriter(File.OpenWrite("C:\\Temp\\jobID_" + JobID.ToString() + ".pdf"));

 

            // Retrieve Data

            RetrieveAvailableDataForJob(JobID);

        }

 

        /// <summary>

        /// 

        /// Handling of EndPage event is optional. It can be used to either retrieve any available 

        /// data after each page is printed or simply to indicate page progress.

        /// 

        /// </summary>

        /// <param name="JobID"></param>

        /// <param name="hDC"></param>

        private static void PdfEndPage(int JobID, int hDC)

        {

            // Retrieve Data

            RetrieveAvailableDataForJob(JobID);

        }

 

        /// <summary>

        /// 

        /// In the EndDocPost even we retrieve any remaining data for this print job and we close the associated file we are writing the data to.

        /// 

        /// </summary>

        /// <param name="JobID"></param>

        /// <param name="hDC"></param>

        private static void PdfEndDocPost(int JobID, int hDC)

        {

            // Retrieve Data last time

            RetrieveAvailableDataForJob(JobID);

 

            // Close the File

            printJobs[JobID].Close();

            printJobs.Remove(JobID);

        }

 

        /// <summary>

        /// 

        /// Handling of the new DocCancelled event is important in case where the printing is in a different process

        /// and the user cancels the printing from that external application. Without this handler, we cannot know

        /// if the document finished printing and we will wait indefinitely for that. This is because Windows does not

        /// send the EndDocPost event when a print job is cancelled.

        /// 

        /// </summary>

        /// <param name="JobID"></param>

        /// <param name="hDC"></param>

        private static void PdfDocCancelled(int JobID, int hDC)

        {

            // Close the File

            printJobs[JobID].Close();

 

            // might want to delete the file after closing it in this case ?

            printJobs.Remove(JobID);

        }

 

        /// <summary>

        /// 

        /// This even is important to handle for all print jobs because in some cases, the print buffer on the driver side

        /// might fill before the printer fires any of the other events that we are handling on the PDF side. If we do not handle 

        /// this even here, it will result in the printer waiting indefinitely for PDF to read the available data before it can re-use

        /// the space in the buffer. When we handle this event and call PDF.GetAvailableDataEx() we tell the driver that it can go ahead and 

        /// use the space for writing new data because we read the previous data.

        /// 

        /// </summary>

        /// <param name="JobID"></param>

        /// <param name="hDC"></param>

        private static void PdfBufferFull(int JobID, int hDC)

        {

            // Retrieve Data

            RetrieveAvailableDataForJob(JobID);

        }

 

 

        /// <summary>

        /// 

        /// The page drawing code used with direct printing

        /// 

        /// </summary>

        /// <param name="sender"></param>

        /// <param name="e"></param>

        private static void PrintPage(object sender, PrintPageEventArgs e)

        {

            Graphics g = e.Graphics;

            Font font = new Font("Courier", 28);

            SolidBrush brush = new SolidBrush(Color.FromArgb(255, Color.Blue));

 

            g.FillRectangle(brush, 0, 0, 500, 400);

            g.DrawString("THIS IS A TEST", font, Brushes.White, 100, 100);

 

            page++;

            e.HasMorePages = page <= 4;

        }

    }

}