To make it easy to implement N2PDF in my applications/agents, I created a simple class, which I put in a script library called Class.PDF. Most of the code for teh actual PDF generation was taken straight from the example provided with the product.
In addition to the actual PDF creation, I also added functions to send the PDF file to a physical printer, and to send the PDF file to our internal document imaging system. I have removed the code for the latter, as it is very specialized code, calling a custom COM object we built, etc.
To send the PDF file to the printer, Acrobat Reader 9.0 is installed on the server (or client, depending on where the code is being executed). Due to limitations in AcroRD32.exe (it is not closing after it finish printing), I am using Acrobat Wrapper (AcroWrap.exe) from bioPDF.
You may also notice that I check two environment variables, this is to detect if the code is running on a 32-bit or 64-bit version of Windows.
I can not take credit for the ShellAndWait() function, I downloaded the code long ago from somewhere. It is used instead of the LotusScript Shell() function, and it will sit and wait until the called program finished executing before it continues.
Option Public
Option Declare
%INCLUDE "N2PDFDEF.SCR"
' *** Used for ShellAndWait()
Type STARTUPINFO
cb As Long
lpReserved As String
lpDesktop As String
lpTitle As String
dwX As Long
dwY As Long
dwXSize As Long
dwYSize As Long
dwXCountChars As Long
dwYCountChars As Long
dwFillAttribute As Long
dwFlags As Long
wShowWindow As Integer
cbReserved2 As Integer
lpReserved2 As Long
hStdInput As Long
hStdOutput As Long
hStdError As Long
End Type
' *** Used for ShellAndWait()
Type PROCESS_INFORMATION
hProcess As Long
hThread As Long
dwProcessID As Long
dwThreadID As Long
End Type
' *** Used for ShellAndWait()
Declare Function WaitForSingleObject Lib "kernel32" _
(Byval hHandle As Long, Byval dwMilliseconds As Long) As Long
Declare Function CreateProcessA Lib "kernel32" _
(Byval lpApplicationName As Long, Byval lpCommandLine As String, _
Byval lpProcessAttributes As Long, Byval lpThreadAttributes As Long, _
Byval bInheritHandles As Long, Byval dwCreationFlags As Long, _
Byval lpEnvironment As Long, Byval lpCurrentDirectory As Long, _
lpStartupInfo As STARTUPINFO, _
lpProcessInformation As PROCESS_INFORMATION) As Long
Declare Function CloseHandle Lib "kernel32" _
(Byval hObject As Long) As Long
Const NORMAL_PRIORITY_CLASS = &H20&
Const INFINITE = -1&
Const tmpPath = "C:\N2PDF\" ' Directory to store files in
' *** Main class to create and print PDF files
Class PDF
Private JobID As Long
Private IsOnServer As Integer
Public PrinterName As String
Public testmode As Integer
Public Sub New()
Dim session As New NotesSession
Dim txtrow As String
Dim cmd As String
Dim res As Integer
' *** Fix registry settings for Acrobat 9.0 to not shrink/fit page
Open tmpPath & "AcrobatSettings.reg" For Output As #1
Print #1, "Windows Registry Editor Version 5.00"
Print #1, ""
Print #1, "[HKEY_CURRENT_USER\Software\Adobe\Acrobat Reader\9.0\AVGeneral]"
Print #1, |"bprintExpandToFit"=dword:00000000|
Print #1, |"iprintScaling"=dword:00000001|
Close #1
cmd = |regedit /s | & tmpPath & |AcrobatSettings.reg|
res = ShellAndWaitFunc(cmd)
Kill tmpPath & "AcrobatSettings.reg"
Me.IsOnServer = session.IsOnServer() ' True if code is running on server
If InitN2PDF() = False Then
Call printmsg( "Failed to initialize N2PDF. Exiting.")
Exit Sub
End If
testmode = False
End Sub
Sub Delete
' *** Destructor
End Sub
' *** This function print to console on server but display message box if running in client
Private Sub PrintMsg(text As String)
If Me.IsOnServer Then
Print text
Else
Msgbox text,,"Class.PDF:" & Getthreadinfo(LSI_THREAD_CALLPROC)
End If
End Sub
Private Function InitN2PDF() As Integer
Me.JobID = N2PDFInit (0)
If ( Me.JobID < 0 ) Then ' Make sure N2PDF was initialized successfully
InitN2PDF = False
Exit Function
End If
' *** Set N2PDF options
Call N2PDFSetGlobalOption( N2PDFGLOBALOPTION_SHOW_MESSAGES, _
N2PDFVALUE_False,"" )
Call N2PDFSetOption ( Me.JobID, _
N2PDFOPTION_SYSTEM_LAUNCH_VIEWER, N2PDFVALUE_FALSE, "" )
Call N2PDFSetOption ( Me.JobID, _
N2PDFOPTION_NOTES_LINK_DOC_MODE, N2PDFVALUE_NOTES_LINK_MODE_IMAGE_LINK, "" )
Call N2PDFSetOption ( Me.JobID, _
N2PDFOPTION_PDF_COMPRESSION_MODE, N2PDFVALUE_COMPRESSION_DEFLATE, "" )
Call N2PDFSetOption ( Me.JobID, _
N2PDFOPTION_PARAGRAPH_FONT_NAME, "Arial", N2PDFVALUE_DEFAULT_PARAGRAPH_NAME )
Call N2PDFSetOption ( Me.JobID, _
N2PDFOPTION_PARAGRAPH_FONT_SIZE, "8", N2PDFVALUE_DEFAULT_PARAGRAPH_NAME )
Call N2PDFSetOption ( Me.JobID, _
N2PDFOPTION_PARAGRAPH_FONT_COLOR, N2PDFVALUE_COLOR_BLACK, _
N2PDFVALUE_DEFAULT_PARAGRAPH_NAME )
Call N2PDFSetOption ( Me.JobID, _
N2PDFOPTION_FORMAT_DELETE_TRAILING_SPACE, N2PDFVALUE_True, "" )
Call N2PDFSetOption ( Me.JobID, _
N2PDFOPTION_PAGE_FORMAT_STANDARD,N2PDFVALUE_PAGEFORMAT_LETTER, "" )
Call N2PDFSetOption ( Me.JobID, N2PDFOPTION_EXPORT_TABLE_GAP, "1", "" )
InitN2PDF = True
End Function
Public Function AddDocToPDF(doc As NotesDocument)
' *** Add doc to the PDF we are processing.
' *** Use trailing CRLF to avoid blank page at the end
Call N2PDFAddRTContent ( JobID, N2PDFVALUE_CONTENT_BODY, _
N2PDFVALUE_CRLF_AFTER, doc.ParentDatabase.Server, _
doc.ParentDatabase.FilePath, doc.UniversalID, "")
End Function
Public Sub AddPageBreak()
Call N2PDFAddContent( Me.JobID, N2PDFVALUE_CONTENT_BODY, _
N2PDFVALUE_PAGEBREAK_AFTER," " )
End Sub
Public Sub AddLineBreak()
Call N2PDFAddContent( Me.JobID, N2PDFVALUE_CONTENT_BODY, _
N2PDFVALUE_CRLF_AFTER," " )
End Sub
Public Function CreatePDF(outfile As String)
If Fulltrim(outfile) = "" Then
Call PrintMsg("No filename provided provided for [outfile].")
Exit Function
End If
Call N2PDFProcess ( Me.JobID, outfile, 0 )
End Function
Public Sub SetPrinter(printername As String)
Me.PrinterName = printername
End Sub
Public Function PrintPDF(Byval filename As String) As Integer
Dim printer As String
Dim prg As String
Dim cmd As String
Dim success As Long
Dim dirtemp As String
Dim path As String
If Environ$("ProgramFiles(x86)") <> "" Then
path = Environ$("ProgramFiles(x86)")
Elseif Environ$("ProgramFiles") <> "" Then
path = Environ$("ProgramFiles")
Else
path = "c:\Program Files"
End If
dirtemp = path & "\bioPDF\Acrobat Wrapper\"
prg = dirtemp & "acrowrap.exe"
If Dir$(prg) = "" Then
' *** File was not found, we can't print to printer without it.
Print "Failed to locate acrowrap.exe (bioPDF Acrobat Wrapper)."
PrintPDF = -1
Exit Function
End If
prg = |"| & prg & |"| ' Add double quotes around file name
If Me.PrinterName<>"" Then
printer = " " & Me.PrinterName
Else
printer = "" ' This will use default printer
End If
filename = |"| & filename & |"|
cmd = prg & | /t | & filename & printer
success = ShellAndWaitFunc(cmd)
PrintPDF = Cint(success)
End Function
Private Function ShellAndWaitFunc(Byval RunProg As String) As Long
Dim RetVal As Long
Dim RetvalClose As Long
Dim proc As PROCESS_INFORMATION
Dim StartInf As STARTUPINFO
StartInf.cb = Len(StartInf)
' Execute the given path
RetVal = CreateProcessA(0&, RunProg, 0&, 0&, 1&, _
NORMAL_PRIORITY_CLASS, 0&, 0&, StartInf, proc)
' Disable this app until the shelled one is done
RetVal = WaitForSingleObject(proc.hProcess, INFINITE)
RetValClose = CloseHandle(proc.hProcess)
ShellAndWaitFunc = RetValClose
End Function
End Class
Here is a small code snippet showing how to call the class. Enjoy!
Option Public Option Declare Use "Class.PDF" Dim pdf As PDF Dim success As Integer dim PDFfile As String ...set doc here PDFfile = doc.UniversalID & ".pdf" ' Create file name based on document UNID Set pdf = New PDF() ' Initialize PDF object pdf.TestMode = False ' Set PDF object to test mode if desired pdf.PrinterName ="CRP_Accounting_Color" ' Set the printer name for printouts Call pdf.AddDocToPDF( doc ) Call pdf.CreatePDF( PDFfile ) success= pdf.PrintPDF( PDFfile ) If success = 1 Then MsgBox "Successfully printed " & PDFfile & "." End If
