Here is an easy way how you can create PDF files on the server

… or how to use the NotesUI-classes on the server.

First I would like to thank all of you out there. I have been reading this excellent forum for many years and now I like to contribute a nice trick on how to make PDF files. I have been searching for a way to use something like the PDFCreator to print out documents on the server and store them back in a document. The problem is that the ‘print’ is only avaible in the NotesUI-classes and you can’t access them from the server. But this is one way how to do it:

  1. You must have one of the clients installed on the server and using an id-file with full access to your projects.

  2. Download and install the PDFCreator from PDFCreator download | SourceForge.net

Install it and make it the default printer. Create a folder like ‘c:\tmpPDF’.

Open the setting for PDFCreator and turn on autosave. Choose the <REDMON_DOCNAME> for the filename and use the directory you just created. The document title will be the file name and you can control that in your form property.

  1. Create an empty database on the server ‘PDFCreator.nsf’. Add your user in the ACL to access designer

Create a new empty form. Name it ‘frmPDFCreator’ and save it.

Create a document using that form and save it. Yes it is an empty document!

Open the document and bring up the Properties box. In the <+> you find the identifier. Copy the whole string.

Now the magic

  1. In your tmpPDF folder you create a cmdPDF.BAT file. Use your identifier and make the command line like this:

explorer.exe Notes://MYSERVER/C12572AA001F3BCB/A296C48F65435737C12572AA001F3BCD/4A8AE17653B1E5D8C12572AA0020EA3D

(should be one single line)

  1. Create an agent called ‘startPDFCreator’ in PDFCreator.nsf.

Select ‘Agent list selection’ and target ‘none’. On the security tab set runtime security level 3.

            Dim result As Integer

            result = Shell("c:\tmpPDF\cmdPDF.BAT", 1) 

Save it

  1. Open the frmPDFCreator and in the ‘Postopen’ area you write your code. Something like this:

Sub Postopen(Source As Notesuidocument)

Dim ws As New NotesUIWorkspace

Dim view As NotesView

Dim s As New NotesSession

Dim db As NotesDatabase

Dim doc As NotesDocument

Dim uidoc As Notesuidocument

Dim rtitem As NotesRichTextItem

Dim object As NotesEmbeddedObject

Dim objPrinter As Variant	

Set objPrinter = CreateObject( "Pdfcreator.clspdfcreator")



'***************************************************************

' SETTINGS 

'***************************************************************

printerpath = "c:\tmpPDF\"        ' path to PDF files -   end with \

timeout = 10                               ' printer timeout

Fieldname = "PDF"                   ' Where to store the pdf-file



'************************************************************

' Set your document  here 

' 

'  bla bla bla bla

'  doc =   ............................

'************************************************************

startTime! = Timer()

Call ws.EditDocument(False, doc)

Set uidoc =ws.CurrentDocument

filename = uidoc.WindowTitle

Call uidoc.Print(1 )



    Do While objPrinter.Cprogramisrunning = False

	  'wait for the PDFCreator to start	

Loop

Do While objPrinter.Cprogramisrunning = True 

	'Wait for PDFCreator to stop	 

	If Timer() > timeout  + startTime!   Then 

	' Error printing timeout 		

		Print "Timeout printing to PDFCreator"

		Call uidoc.Close

		Call Source.Close

		Exit Sub

	End If

Loop



myFile =  Dir ( printerpath + filename+".pdf")

If myFile <> "" Then

	Print "Time to print :" + Cstr( Timer - startTime!)

	If doc.HasItem(Fieldname ) Then Call doc.RemoveItem(Fieldname)

	Set rtitem = New NotesRichTextItem( doc, Fieldname )

	Set object = rtitem.EmbedObject ( EMBED_ATTACHMENT, "", printerpath + myFile)			

	Call doc.Save(True, False )

	Kill printerpath + myFile

Else

	' No file found   - Check PDFCreator settings

	Print "No PDF file found – check PDFCreator settings"

End If

Call uidoc.Close

Call Source.Close

End Sub

  1. Last thing to do is to call the ‘startPDFCreator’ agent in the ‘Postsave’ in the form of the document that you want to create and attach the PDF file.

Dim s As New NotesSession

Dim db As NotesDatabase

Dim agent As NotesAgent



Set db = s.Getdatabase( myserver , "PDFCreator.nsf")

Set agent = db.GetAgent("startPDFCreator")



If agent.RunOnServer = 0 Then

	Print "Agent Create PDF OK"

Else

	Print "Agent Create PDF did not run"

End If

Source.Close

What happens is that when you save your document it will trigger the client on the server to open an empty document and it will execute the code for your to print out you document and save it back. It works very well and is fast to. The good thing is that the client is starting by itself if not running. You have to share the windows password then so it will not stop waiting at the prompt.

In this way you may use all the NotesUI-classes and run them on the server.

See you !

Subject: Here is an easy way how you can create PDF files on the server

Hello! First of all, thank you for posting this. :slight_smile:

Just a question, can this be used by several users? Does the PDFCreator handle queueing of tasks?

Well actually what I need is an agent that can locally create a copy of a NotesDocument’s PDF equivalent… Also, it would be better if the user can have an option of saving it wherever they want to.

If i’m going to use this procedure, all the documents generated by each of the users will have the same location, that is the location set in the setting of the installed PDFCreator.

Is this possible to implement? Please advise. Thank you!

Subject: RE: Here is an easy way how you can create PDF files on the server

Hi

You only have to install the PDF creator on the server.

The client on the server is running for you and create the file locally on the server.

The settings is only for the server to know where to find the PDF file.

The users don’t even need to have access to your project since you are using a client and an id-file of your choice when running the script.

You can control where the PDF file will end up in the ‘postopen’ code. Maybe store it on a fileshare instead with a filename that you pickup from the author.

There is a limit of characters in file name, about 30 I think. Check that first.

Why not use different agents to call depending on the user choise when saving.

There is no queue for the jobs but you can have a view for documents that needs to be processed and run the agent by schedule if you like.

The PDFCreator can handle a queue but you need a way keep track of the files that comes out.

I was thinking about creating a more generic way to use this technic by using several documents in the PDFCreator.nsf.

In this way you can control the behavor of the script in multiple ways by sending data to the agent.

like this: status=agent.RunOnServer(noteID$)

Time is all you need !!! :slight_smile:

Subject: Here is an easy way how you can create PDF files on the server

Hi Allen, thanks for all your guys work…I just found it because I just need it…and this is the one more thing I want to upgrade in your topic, because I think many people will find your articel

the pdfcreator u used is 1.7., but now it’s 2.…so the script needs some change becuase COM Interface change:

http://docs.pdfforge.org/pdfcreator/2.3/en/pdfcreator/com-interface/user-manual/basics/workflow-comparsion-v1-7-v2/

Set objPrinter = CreateObject( “Pdfcreator.clspdfcreator”)

will need change to

Set PDFCreator = CreateObject(“PDFCreator.PDFCreatorObj”)

at least…if you guys use 2.* version of pdfcreator…

maybe there have some others need to modify…I just find this one…

XD

Subject: RE: Here is an easy way how you can create PDF files on the server

sorry…shoud be PDFCreator.JobQueue

Subject: Here is an easy way how you can create PDF files on the server

Hi,

What would the filename be if the window title contains special characters? Is there any specification followed while extracting the file name from the window title in such cases?

I need to archive existing documents in an application and hence, cannot change what is being displayed as the window title.

Subject: Here is an easy way how you can create PDF files on the server

in your code you wrote: Set your document here

’ bla bla bla bla

’ doc = …

but where i find the doc value?

so how i can initialize the doc variable?

thanks

Subject: RE: Here is an easy way how you can create PDF files on the server

Hi

This is where you pick up the document you want to print out.

You can search you database for document that has no PDF-file yet

Maybe somthing like this:

Dim myDB As NotesDatabase

Dim coll As NotesDocumentCollection

Set myDB = s.getdatabase (“myserver” , “myfolder/mydatabase.nsf”

Set coll = myDB.search ( |form=“invoice” & PDF=“” | , Nothing , 0 )

Set doc = coll.getfirstdocument

’ you may loop here if you have several documents

OR i f you know the ID of the document

Set myDB = s.getdatabase (“myserver” , “myfolder/mydatabase.nsf”)

set doc = myDB.GetDocumentByID( “000021CA” )

OR why not create a view with documents not yet processed.

Start the agent by a timer and see if any new is to be printout

:slight_smile: Allan

Subject: RE: Here is an easy way how you can create PDF files on the server

uhmmm

i want to try to create a manual agent in the mail db (dwa7) in order to convert a mail and, if there is, the attachment in a pdf document

is it possible to do it? can you give me some hints?

Subject: RE: Here is an easy way how you can create PDF files on the server

       *************************************************           *      to do more programming               **

       * not tested - just for bringing you an idea   **

       *************************************************

Create a form in PDFCreator.nsf - ‘printMe’ - and add some fields ‘mydocid’ and ‘myDB’ .

When you saving your first document ( the one that you want to print out ) the Postsave code writes a little document in PDFCreator.nsf and then calls the agent providing the NoteID of that little document.

The agent can pick up this document and reads the values how to find your docid in your database.

        *****

In mydatabase.nsf and the form that you using for printing:

Postsave

Dim s As New NotesSession

Dim db As NotesDatabase

dim mydb as NotesDatabase

Dim agent As NotesAgent

Dim w as New Notesuiworkspace

Dim print as notesdocument

Set db = s.Getdatabase( myserver , “PDFCreator.nsf”)

Set print = New Notesdocument( db)

print.form = “printMe”

print.myDB = w.CurrentDocument.Document.ParentDatabase.FileName

print.mydocid = w.CurrentDocument.Document.NoteID

Call print.save( true, false)

Set agent = db.GetAgent(“startPDFCreator”)

If agent.RunOnServer( print.NoteID ) = 0 Then

Print “Agent Create PDF OK”

Else

Print “Agent Create PDF did not run”

End If

Source.Close

        ******

In the PDFCreator.nsf Postopen you pick up this values:

Dim pdfDB as Notesdatabase

Dim printJob as Notesdocument

'------------------------

’ Set you document here …

set pdfDB = s.currentdatabase

Set printJob = db.GetDocumentByID(agent.ParameterDocID)

Set myDB = s.getdatabase ( “myserver” , printJob.myDB(0) )

set doc = myDB.GetDocumentByID( printJob.mydocid(0) )

’ you may want to delete the printJob document from the database when ready !

'-----------------------------------

You can also trigger the 'startPDFCreator’ agent by a manual agent or button using code as in the Postsave.

as I said - not tested !

:slight_smile: Allan

Subject: RE: Here is an easy way how you can create PDF files on the server

Hey Allan,

I don’t know if you are still monitoring this post, I hope so, because I have a problem and it don’t make sense to me. I have been testing your code and modifying it a bit, and last week it was working well, and today, it is not anymore, and I am not sure what has changed.

Basically I added a part to modify the options in the code, to be able to manipulate them using Set PDFCreatorOptions = CreateObject(“Pdfcreator.clsPDFCreatorOptions”) and I added a line to set the default printer (objPrinter.cDefaultprinter = “PDFCreator”)

Now the problem is when I try to get or set the default printer option, I get a blank only, do yo know why?

Edit:

Nevermind, I have found the answer, Seems that you cannot access or set the cDefaultPrinter option of the object while PDFCreator is not running, I adjusted my script and it works very well! Thanks for the basis here Allan

Subject: Here is an easy way how you can create PDF files on the server

I’ve found that the objPrinter.Cprogramisrunning property always returns False. Other properties of the object don’t have the values that they’re supposed to have either. I think it’s because the printer object that is created in the script is not the one used to actually “print” the document.

So far I haven’t found a good way to know when the printing is done.

Subject: RE: Here is an easy way how you can create PDF files on the server

I found a way. I use the OpenPrinter and EnumJobs calls of winspool.drv to check the number of active jobs for the PDFCreator printer. When the number of jobs is 0 I can continue.

Subject: RE: Here is an easy way how you can create PDF files on the server

Will

can i have the script for that

thanks in advance… Toni

Subject: RE: Here is an easy way how you can create PDF files on the server

NOTE: ProfileDoc.PDFPrinter(0) is a profile document that I use to store the name of the printer. The printer name has to match the Windows printer name.

Declarations

Declare Function OpenPrinter Lib "winspool.drv" Alias "OpenPrinterA" ( _

Byval pPrinterName As String, _

phPrinter As Long, _

pDefault As Any) As Long



Declare Function EnumJobs Lib "winspool.drv" Alias "EnumJobsA" ( _

Byval hPrinter As Long, _

Byval FirstJob As Long, _

Byval NoJobs As Long, _

Byval Level As Long, pJob As Any, _

Byval cdBuf As Long, _

pcbNeeded As Long, _

pcReturned As Long) As Long







Initialize

Dim hPrinter As Long

Dim lNeeded As Long

Dim lReturned As Long

Dim lJobCount As Long



Set UIDoc = Nuiws.EditDocument( False , DocToPrint , True , "" , True , True )

Call UIDoc.Print( 1 ) 'Print the document to the PDF printer

'Now we have to wait until our file is ready

'What we do is examine the job queue for the selected printer

'If there's a job in there then we wait until there are no jobs

lJobCount = 1  'Seems reasonable to set to 1 to start our loop...we just sent one, didn't we?

OpenPrinter ProfileDoc.PDFPrinter(0) , hPrinter, Byval 0&  

Do Until lJobCount = 0

	EnumJobs hPrinter, 0, 99, 1, Byval 0&, 0, lNeeded, lReturned 

	If lNeeded > 0 Then

		Redim byteJobsBuffer( lNeeded - 1 ) As Byte

		EnumJobs hPrinter, 0, 99, 1, byteJobsBuffer( 0 ), lNeeded, lNeeded, lReturned

		If lReturned > 0 Then

			lJobCount = lReturned

		Else

			lJobCount = 0

		End If

	Else

		lJobCount = 0

	End If

Loop

'Okay...print job is done and we can continue

Subject: Thank you Allan and Willy it works OK.

Allan thank you for the nice idea. Willy your print control script is really cool.

Subject: RE: Thank you Allan and Willy it works OK.

Subject: Nice resource Willy

I downloaded it. I found nice the way you wait for the PDFCreator to release de pdf file on disk. I mean the counter and Sleep resource:

’ Wait for print job to complete.

	Counter = 0

	Do Until ( PDFCreator.cCountOfPrintJobs = 0 And Dir( FullPDFFilename ) <> "" ) Or Counter = 30

		Sleep 1

		Counter = Counter + 1

	Loop

	If Counter = 30 Then Error 1002, "CreatePDF - PDF Conversion never completed.  Process halted."

I did something similar but with sleep 0.1 (100 milliseconds) and a bigger counter:


Dim filesys as Variant

Set filesys=CreateObject(“Scripting.FileSystemObject”)

counter = 0	

	Do Until filesys.FileExists(file)  Or Counter >= 2000

		Sleep 0.1

		counter = counter + 1

	Loop

	If Counter >= 2000 Then 

		'error message here

	End If

I’m using Lotus Notes 8. I dont need to set PdfCreator as default printer because the print method allow us to set the printer:

	Call uidoc.Print( 0, 0, 0, False, "PrinterX")	

Thank you again Willy

Subject: -