Click here to Skip to main content
Click here to Skip to main content

PDF Writer

By , 16 Mar 2006
 

Sample Image - PDFWriter1.jpg

Introduction

The main purpose of this paper is to demonstrate how to create a PDF writer by using the Virtual Printer Method, which gives your applications an ability to generate PDF files through simply "printing". I am pretty sure there are many PDF writers using the same technique, like PrimoPDF. However, you probably wish to create your own PDF writer some day. Here, I give an example to uncover the whole process of creating such a kind of PDF writer.

Background

  • Ghostscript is an interpreter for PDF files, which also has the ability to convert PostScript language files to PDF.
  • RedMon is a port monitor, which redirects a special printer port to Ghostscript.

The main idea is actually simple. What you need to do is install a PostScript printer and let RedMon work as a bridge between the printer and Ghostscript.

Using the code

Before jumping to the demo project

You have to first download Ghostscript. My demo requires AFPL Ghostscript 8.53. Don’t install it at this time. You are encouraged to use WinRAR or WinZip (I didn’t try WinZip) to unzip it to “C:\\UTReportPrerequisite\\gs\\”. You need to copy pdfwrite.rsp (a text file, which can be found in the demo project) to the folder as well.

You may download RedMon from its website, but I suggest you use a replacement that is packed in the demo project. There is a folder “redmon17” in the demo project, please copy this folder to “C:\\UTReportPrerequisite\\”.

The last thing you need is a printer driver. By chance, I chose HP color LaserJet 8550 PostScript driver. Don’t install it at this time. Instead, use WinRAR to unzip all files to “c:\\UTReportPrerequisite\\Driver”.

The final folder structure should be like below:

Sample screenshot

Running the demo project

The demo project is very straightforward. Clicking buttons from "Setp1", "Step2", "Step3" to "Setp4" sequentially, you will have a printer named "UTReport PDF Writer " installed if each step has been done successfully, as shown in the figure below. I want to point out here that "Step3" and "Step4" are a little bit time consuming so more patience should be paid.

Sample screenshot

Now is the right time to test our PDF writer. Open WordPad.exe, type in whatever you want, then print it using "UTReport PDF Writer". Check C:\SampleOut.PDF, which is your output PDF file.

"Step5" to "Setp8" let you have a chance to uninstall the printer you installed just now.

Points of interest

  1. AddPrinterDriver
  2. Based on MSDN: Before an application calls the AddPrinterDriver function, all files required by the driver must be copied to the system's printer-driver directory. An application can retrieve the name of this directory by calling the GetPrinterDriverDirectory function. Therefore, in our demo, we have to copy all the printer driver files from c:\\UTReportPrerequisite\\Driver to the folder returned by GetPrinterDriverDirectory.

    //Install Driver
    
    void CInstallPrinterDlg::OnBnClickedButtonStep3()
    {
        CString msg="Failed";
        if (CopyPrintDriverFiles2System() && AddPrinterDriver())
            msg = "Add Printer Driver Successfully";
        
        AfxMessageBox(msg);
    
        return ;
    }

    The other tricky thing is the pDependentFiles field of DRIVER_INFO_3. From MSDN: pDependentFiles is a pointer to a null-terminated string that specifies the files the driver is dependent on. Each file name in the string is also terminated with a null (for example, "Pscript.dll\0Qms810.PPD\0Pscrptui.dll\0Pspcriptui.hlp\0Pstest.txt\0\0"). How do we assign a value to this field? My answer is:

    DRIVER_INFO_3 di3; 
    ...
    di3.pDependentFiles = TEXT("hpbafd32.dll\0hpbftm32.dll\0HPLJ8550.cfg\" 
                               "0hpcdmc32.dll\0hpbcfgre.dll\0hpdcmon.dll\0\0");
  3. Updating the Registry
  4. In order to let our PDF writer work like a charm, we have to update the registry info for both Ghostscript and RedMon. For RedMon:

    //#define PORT_KEY TEXT("SYSTEM\\ControlSet001\\Control\\"
    //                      "Print\\Monitors\\Redirected Port\\Ports\\UTReportPDFPort:")
    
    if ((rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, PORT_KEY, 0, 
                           KEY_ALL_ACCESS, &hkey)) != ERROR_SUCCESS) 
    {
        /* failed to open key, so try to create it */
        rc = RegCreateKey(HKEY_LOCAL_MACHINE, PORT_KEY, &hkey);
    }
    if (rc == ERROR_SUCCESS) 
    {
        lstrcpy(buffer, "@c:\\UTReportPrerequisite\\gs\\pdfwrite.rsp -");
        RegSetValueEx(hkey, TEXT("Arguments"), 0, REG_SZ, 
                     (CONST BYTE *)buffer, lstrlen(buffer)+1);
    
        lstrcpy(buffer, "C:\\UTReportPrerequisite\\gs\\gs8.53\\bin\\gswin32c.exe");
        RegSetValueEx(hkey, TEXT("Command"), 0, REG_SZ, 
                     (CONST BYTE *)buffer, lstrlen(buffer)+1);
    
        dwValue =2;
        RegSetValueEx(hkey, TEXT("ShowWindow"), 0, 
                                 REG_DWORD,(CONST BYTE *)&dwValue, 4);
    
        dwValue =0;
        RegSetValueEx(hkey, TEXT("RunUser"), 0, REG_DWORD,
                                (CONST BYTE *)&dwValue, 4);
    
        dwValue =300;
        RegSetValueEx(hkey, TEXT("Delay"), 0, REG_DWORD,
                     (CONST BYTE *)&dwValue, 4);
    
        RegCloseKey(hkey);
    }

    For Ghostscript:

    //#define GHOSTSCRIPT_KEY2 TEXT("SOFTWARE\\AFPL Ghostscript\\8.53")
    
    if ((rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, GHOSTSCRIPT_KEY2, 0, 
                           KEY_ALL_ACCESS, &hkey)) != ERROR_SUCCESS) 
    {
        /* failed to open key, so try to create it */
        rc = RegCreateKey(HKEY_LOCAL_MACHINE, GHOSTSCRIPT_KEY2, &hkey);
    }
    
    if (rc == ERROR_SUCCESS) 
    {
        lstrcpy(buffer, TEXT("C:\\UTReportPrerequisite\\gs\\gs8.53\\bin\\gsdll32.dll"));
        RegSetValueEx(hkey, TEXT("GS_DLL"), 0, REG_SZ, 
                     (CONST BYTE *)buffer, lstrlen(buffer)+1);
    
        lstrcpy(buffer, TEXT("C:\\UTReportPrerequisite\\gs\\gs8.53\\lib;C:\\" 
                             "UTReportPrerequisite\\gs\\fonts;C:\\UTReportPrerequisite" 
                             "\\gs\\gs8.53\\Resource"));
        RegSetValueEx(hkey, TEXT("GS_LIB"), 0, REG_SZ, 
                     (CONST BYTE *)buffer, lstrlen(buffer)+1);
    
        RegCloseKey(hkey);
    }
  5. About pdfwrite.rsp
  6. pdfwrite.rsp is actually a parameter file used to control the PDF generation, i.e., page size, resolution etc. -sOutputFile is used to control where the produced PDF file should go. For more details, please read the Ghostscript online help.

    -Ic:\UTReportPrerequisite\gs\gs8.53\lib;c:\UTReportPrerequisite\gs\fonts
     -sDEVICE=pdfwrite
     -r600
     -dNOPAUSE
     -dSAFER
     -sPAPERSIZE=letter
     -sOutputFile="c:\SampleOut.PDF"

Acknowledgement

First of all, thanks to all open source projects. Special thanks should be extended to Ghostscript and RedMon.

History

  • 2006/03/16, First release.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

ben688
Canada Canada
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
Hint: For improved responsiveness ensure Javascript is enabled and choose 'Normal' from the Layout dropdown and hit 'Update'.
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
Questionredirect the postscript data to my own programmemberKong ZhiPeng5 Mar '13 - 22:46 
QuestionI can not download the HPDriver in the given URLmemberzihui062511 Dec '12 - 23:11 
I download annother version of driver,but can not found the dlls with the same name used in the code.
where could I get the same driver? Or if I don,t use version 8550 ,how could I modify the prigram ? please help me
GeneralMy vote of 5memberSunil Apte20 Sep '12 - 23:17 
GeneralIt's actually even easier than the authors project (which is nice work)memberAndy Bantly22 Nov '10 - 5:35 
GeneralRe: It's actually even easier than the authors project (which is nice work)memberMember 421697415 Dec '10 - 6:32 
GeneralRe: It's actually even easier than the authors project (which is nice work)memberAndy Bantly23 Dec '10 - 5:40 
GeneralProblem with Port monitor.membersayon sur7 Sep '09 - 19:44 
QuestionWhy the author's sample printer driver doesn't work for print from PDF document to a destination PDF with this sample driver?memberkingmax5421200831 Aug '09 - 22:31 
AnswerRe: Why the author's sample printer driver doesn't work for print from PDF document to a destination PDF with this sample driver?memberkingmax542120082 Sep '09 - 0:25 
GeneralDtivers for the HP PS printer [modified]memberGideon Rozin10 Mar '09 - 4:35 
GeneralChange the name of the output PDF filemembervbtommy8029 Dec '08 - 5:19 
GeneralRe: Change the name of the output PDF filememberben68829 Dec '08 - 8:26 
GeneralRe: Change the name of the output PDF filemembervbtommy8029 Dec '08 - 9:06 
QuestionCan anyone convert the above code into VB.NET please?memberSimon Williamson10 Nov '08 - 3:13 
AnswerRe: Can anyone convert the above code into VB.NET please?memberMember 338276328 Dec '08 - 15:38 
GeneralRe: Can anyone convert the above code into VB.NET please?memberben68829 Dec '08 - 8:22 
GeneralProblem installing the printermemberfabio.porrino4 Nov '08 - 11:17 
GeneralHelpmembernitin_ion7 May '08 - 23:51 
QuestionOpenPrinter and AddPort Help needed on Win98membercharliewang3 Apr '08 - 4:42 
GeneralAddPrinter failedmemberytfrdfiw28 Jan '08 - 20:29 
QuestionStart a exe after printsussMayo4 Dec '07 - 20:11 
AnswerRe: Start a exe after printmemberJoe.vc31 Mar '09 - 5:27 
Generalport is not addedmembervinayakpict20 Sep '07 - 5:05 
QuestionRe: port is not addedmemberbencohen28 Feb '09 - 16:17 
GeneralPDF Writer .Net VersionmemberIshfaqHussain24 Aug '07 - 2:38 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130516.1 | Last Updated 16 Mar 2006
Article Copyright 2006 by ben688
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid