
OpenNTF Code Bin
About This Code
Brief Description:
Print attachments with OLE Automation or a WindowsAPI
Contributor:
Andrew Jones
Last Modified:
17 Jun 2002
OpenNTF Disclaimer
All of the program code and information presented in the OpenNTF.org Code Bin are provided "as-is", and should be used at your own risk. OpenNTF.org make no express or implied warranty about anything in the Code Bin, and OpenNTF.org will not be responsible or liable for any damage caused by the use or misuse of anything from this site. OpenNTF.org makes no guarantees about anything. Please thoroughly test all of the knowledge and code you find here before you attempt to use them in your production environment.
Code / Description
'PrintingUtilities:
Option Explicit
%REM
Lotus Professional Services, July 2001
This library provides printing of attachments from Notes
Tested for Notes/Domino 5.0.3 Intl with MS Office 97 and 2000
%END REM
' Customized error messages
Const MSG_AutomationError = "Unable to find application "
Const MSG_UnableToPrint = "Unable to print file "
Const MSG_Continue = "Click OK to Continue printing supported file types"
Const MSG_NoExtension = "No file extension"
Const MSG_UnknownExtension = "Extension not recognized"
'ShellExecute
Declare Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" (Byval hwnd As Long, Byval lpszOp As String, Byval lpszFile As String, Byval lpszParams As String, _
Byval LpszDir As String, Byval FsShowCmd As Long) As Long
%REM
Parameter Description
----------------------------------------------------------------------------
hwnd Identifies the parent window. This window receives any message boxes an application produces (for example, for error reporting).
lpszOp Points to a null-terminated string specifying the operation to perform. This string can be "open" or "print." If this parameter is NULL, "open" is the default value.
lpszFile Points to a null-terminated string specifying the file to open.
lpszParams Points to a null-terminated string specifying parameters passed to the application when the lpszFile parameter specifies an executable file. If lpszFile points to a string specifying a document file, this parameter is NULL.
LpszDir Points to a null-terminated string specifying the default directory.
FsShowCmd Specifies whether the application window is to be shown when the application is opened.
%END REM
' Error codes for ShellExecute
Const ERROR_FILE_NOT_FOUND = 2 ' File not found
Const ERROR_PATH_NOT_FOUND = 3 ' Path not found
Const SE_ERR_ACCESSDENIED = 5 ' Access denied
Const SE_ERR_OOM = 8 ' Not enough memory to complete the operation
Const ERROR_BAD_FORMAT = 11 ' EXE file invalid
Const SE_ERR_SHARE = 26
Const SE_ERR_ASSOCINCOMPLETE = 27 ' Filename association invalid or incomplete
Const SE_ERR_DDETIMEOUT = 28 ' DDE timeout
Const SE_ERR_DDEFAIL = 29 ' DDE failed
Const SE_ERR_DDEBUSY = 30 ' DDE already busy
Const SE_ERR_NOASSOC = 31 ' No application associated with this extension
Const SE_ERR_DLLNOTFOUND = 32
Public Sub PrintAllAttachments (doc As NotesDocument)
%REM
Prints out attachments in the document
IN
doc, the Notes document
OUT
nothing
%END REM
Dim rtitem As notesrichtextitem
If doc Is Nothing Then Exit Sub
If doc.HasItem ("Body") = False Then Exit Sub
Set rtitem = doc.GetFirstItem( "Body" )
If ( rtitem.Type = RICHTEXT ) = False Then Exit Sub
If Isempty(rtitem.EmbeddedObjects) Then Exit Sub
Forall o In rtitem.EmbeddedObjects ' loops through all attachments
If ( o.Type = EMBED_ATTACHMENT ) Then
Call PrintAttachment (o)
End If
End Forall
End Sub
Private Sub PrintAttachment ( o As Variant)
%REM
Prints out the attachment.
If the extension is not supported or the application is not installed, messagebox to the user.
Notes:
1) We used OLE for Excel because ShellExecute only prints the first Worksheet.
With the OLE method, we print all worksheets.
2) We did not use OLE for Word and PowerPoint because these apps support several file extensions,
which we would have to hard-code. If needed, these methods can be used, they were tested.
IN
o, the NotesEmbeddedObject to print
OUT
nothing
%END REM
Dim fname As String
Dim Period As String
Dim FileExtension As String
Dim ret As Integer
On Error Goto errHandle
fname = GetTmpDir + o.Source
Call o.ExtractFile ( fname )
Period = Instr(1, fname, ".")
If Period = 0 Then
FileExtension = ""
Else
FileExtension = Mid$(fname, Period, 4)
End If
Select Case Lcase$(FileExtension)
Case ""
Msgbox MSG_NoExtension, 16, MSG_UnableToPrint + fname
' Case ".doc"
' Call PrintMSWord (fname)
Case ".xls"
Call PrintMSExcel (fname)
' Case ".ppt"
' Call PrintMSPowerPoint (fname)
Case Else
PrintDefault (fname)
End Select
Exit Sub
errHandle:
Msgbox "Error " + Cstr(Err) + ": " + Error$ + Chr$(13) + MSG_Continue, 16, MSG_UnableToPrint + fname
Print("Could not print attachment: " & o.source)
Exit Sub
End Sub
Private Function GetTmpDir As String
%REM
Gets (if exists) or creates a temporary directory temp in the Notes data directory
IN
Nothing.
OUT
Nothing.
RETURN
The temporary directory, terminated by ""
%END REM
On Error Goto TmpDirError
Dim s As New NotesSession
Dim TmpDir As String
'Directory is the Notes data Directory
TmpDir = s.GetEnvironmentString ("Directory", True)
TmpDir = TmpDir & "temp"
If Dir$ (TmpDir , 16)="" Then
Mkdir TmpDir
End If
TmpDir = TmpDir & ""
GetTmpDir = TmpDir
Exit Function
TmpDirError:
On Error Goto 0
GetTmpDir = "c:temp"
Exit Function
End Function
Private Sub PrintMSWord (fname As String)
Dim app As Variant
Dim docToPrint As Variant
Dim PrintBackground As Integer
On Error 208 Goto err208
Set app = createobject("Word.application")
Set docToPrint = app.documents.open(fname)
' Turn off background printing to avoid error message cf. Microsoft Technote #Q170393
PrintBackground = app.Options.PrintBackground()
If PrintBackground = True Then app.Options.PrintBackground = False
Call docToPrint.PrintOut()
app.Options.PrintBackground = PrintBackground 'Restore PrintBackground option
Call app.Quit(0)
Set app = Nothing
Exit Sub
err208: 'Cannot create automation object
Msgbox MSG_AutomationError + "MS Word", 16, "Error " + Cstr(Err) + ": " + Error$
Exit Sub
End Sub
Private Sub PrintMSExcel (fname As String)
Dim app As Variant
Dim docToPrint As Variant
On Error 208 Goto err208
Set app = createobject("Excel.application")
Set docToPrint = app.workbooks.open(fname)
' No background printing option available for Excel, no need for special handling
Call docToPrint.PrintOut()
Call app.workbooks.close
Call app.Quit()
Set app = Nothing
Exit Sub
err208: 'Cannot create automation object
Msgbox MSG_AutomationError + "MS Excel", 16, "Error " + Cstr(Err) + ": " + Error$
Exit Sub
End Sub
Private Sub PrintMSPowerPoint (fname As String)
Dim app As Variant
Dim docToPrint As Variant
Dim PrintBackground As Integer
Dim NewInstance As Integer
' Because PowerPoint, unlike Word and Excel, only allows one instance cf. MS Technote #Q222783
On Error 208 Goto createObject
Set app = GetObject (, "PowerPoint.Application")
NewInstance = False
Goto objectCreated
createObject:
NewInstance = True
On Error 208 Goto err208
Set app = createobject("PowerPoint.application")
objectCreated:
app.visible = True ' app has to be visible, error message otherwise
Call app.presentations.open(fname)
' Turn off background printing to avoid error message
Set docToPrint = app.ActivePresentation
PrintBackground = docToPrint.PrintOptions.PrintInBackground
If PrintBackground = True Then app.ActivePresentation.PrintOptions.PrintInBackground = False
Call docToPrint.PrintOut()
docToPrint.PrintOptions.PrintInBackground = PrintBackground 'Restore PrintBackground option
docToPrint.Close
If NewInstance = True Then Call app.Quit() ' Close application only if WE launched it
Set app = Nothing
Exit Sub
err208: 'Cannot create automation object
Msgbox MSG_AutomationError + "MS PowerPoint", 16, "Error " + Cstr(Err) + ": " + Error$
Exit Sub
End Sub
Private Sub PrintDefault (fname As String)
'Ref: Microsoft article Q170918
Dim hwnd As Long
Dim ret As Long
Dim msg As String
ret = ShellExecute(hwnd, "Print", fname, "", "", 0)
If ret<32 Then ' Error
Select Case ret
Case ERROR_FILE_NOT_FOUND
msg = "File not found"
Case ERROR_PATH_NOT_FOUND
msg = "Path not found"
Case SE_ERR_ACCESSDENIED
msg = "Access denied"
Case SE_ERR_OOM
msg = "Out of memory"
Case SE_ERR_DLLNOTFOUND
msg = "DLL not found"
Case SE_ERR_SHARE
msg = "A sharing violation occurred"
Case SE_ERR_ASSOCINCOMPLETE
msg = "Incomplete or invalid file association"
Case SE_ERR_DDETIMEOUT
msg = "DDE Time out"
Case SE_ERR_DDEFAIL
msg = "DDE transaction failed"
Case SE_ERR_DDEBUSY
msg = "DDE busy"
Case SE_ERR_NOASSOC
msg = "No association for file extension"
Case ERROR_BAD_FORMAT
msg = "Invalid EXE file or error in EXE image"
Case Else
msg = "Unknown error"
End Select
Msgbox MSG_UnableToPrint + fname + Chr$(13) + MSG_Continue, 16, msg
Print("Could not print attachment: " & fname)
Else
Print("Printing attachment : " & fname)
End If
End Sub
Usage / Example
Comments
Posted by Joseph LeMay on 10/05/2004 04:21:08 PMSimple agent to use this script library
Option Public
Use "PrintingUtilities"
Sub Initialize
Dim session As New NotesSession
Dim db As NotesDatabase
Dim collection As NotesDocumentCollection
Dim doc As NotesDocument
Set db = session.CurrentDatabase
Set collection = db.UnprocessedDocuments
Set doc = collection.GetFirstDocument()
While Not(doc Is Nothing)
Call PrintAllAttachments(doc)
Set doc = collection.GetNextDocument(doc)
Wend
End Sub
Posted by Patrick Kwintensson on 04/02/2007 02:58:17 AMerror messages
I get the next error messages:
Error processing use list module: Scripted Object
and:
Error laoding USE or USELSX module : PrintingUtilities
debugging is not possible...
Posted by Joseph LeMay on 04/02/2007 09:17:53 AMre: error messages
you should have copied the entire library into a script library and named it "PrintingUtilities"
the the use statement should be in the (options) section of your script.
did you do those two things?
Posted by Virginia E Gibbs on 06/21/2007 12:38:07 PMThis works, but I only need to print Sheet 1 of Excel workbooks
Sorry, I am a complete tyro at this - I am not a programmer, although I was able to get this script working in Lotus Notes with the information above and in the comments. I added the "simple agent" into the Initialize section of the script library, which fixed the USE error as mentioned above.
In short, it works beautifully and even prints PDFs and TIF files, which are other file types I receive; but I only need to print the first sheet of each Excel attachment, (there can be multiple attachments in the emails).
This prints all the tabs, and each Excel attachment has 3 tabs, resulting in a lot of wasted paper.
Please, can someone advise a simple method for a non-programmer to adjust this so that only the first sheet prints? A snippet of code for the Excel section with specific instructions on placing it would probably suffice.
Thanks very much!
Posted by Joseph LeMay on 06/21/2007 01:14:34 PMsee documentation on excel printout method
http://msdn2.microsoft.com/en-us/library/microsoft.office.tools.excel.worksheet.printout(VS.80).aspx
in the PrintMSExcel routine, you should be able to change the line
Call docToPrint.PrintOut()
to
Call docToPrint.PrintOut(1,1)
and that will print only the first page.
I haven't tried this myself, but that's what the documentation indicates.
Posted by Virginia E Gibbs on 06/21/2007 03:22:22 PMFirst sheet successfully prints when run manually! But...
Wow, thanks! I had more or less guessed at it; turns out all I had to add was add (1,1) as in your example. Thanks also for the reference.
I can now get this to work if I select documents and run them from a menu, but ideally I would like it to run and print the attachments automatically as they are received - I have it set to select on the Inbox because it's a dedicated email for this purpose, but my test emails won't print. The setting on "Properties" is "After new mails arrive" and the agent is enabled.
Is there something else in the script that needs to be modified?
Posted by Joseph LeMay on 06/21/2007 03:54:16 PMThere's a whole bunch of stuff that could be wrong
do you have the agent set to run on server or client?
see if you have rights to run the agent on the server.
you might want to try signing the database, all design elements, with the server's ID (see your admin, if it's not you)
right-click on the server version of the agent in designer, and click 'test' and see what it tells you. you'll get some ideas.
make sure you have a default printer installed on the server. honestly I'm not sure how it finds the default print queue since notes usually runs under the local system account. I'm sure there's a way, I just don't know what it is.
if you're running on the client, go to file-preferences-user preferences and make sure "Enable Scheduled Local Agents" is checked.
Posted by Virginia E Gibbs on 06/22/2007 10:35:07 AMWorking! Thank you
I didn't have "Enable Scheduled Local Agents" checked - that was it. It works when I set the properties to run on manually selected emails, which I think is the way it was designed, and that's just fine. It automates a tedious process and frees up a lot of time.
Thank you very much.
Posted by Ron Warner on 06/27/2008 11:36:09 AMR6 Adaptation
Thanks, I found this all very useful. Since I can't help tinkering, and I'm running R6.5.1, I adapted the PrintAllAttachments sub to use the NotesRichTextNavigator class. This way, I'm only cruising through the doc if it has file attachments.
Public Sub PrintAllAttachments (doc As NotesDocument)
%REM
Prints out attachments in the document
IN
doc, the Notes document
OUT
nothing
%END REM
Dim rtitem As NotesRichTextItem
Dim nav As NotesRichTextNavigator
Dim att As NotesEmbeddedObject
Set rtitem = doc.GetFirstItem("Body")
Set nav = rtitem.CreateNavigator
If nav.FindFirstElement (RTELEM_TYPE_FILEATTACHMENT) Then
Do
Set att = nav.GetElement()
Call PrintAttachment (att)
Loop While nav.FindNextElement()
Else
Messagebox "This document contains no attached files"
End If
End Sub
Also, I found I needed to add the virgule (aka backslash) to my GetTmpDir function to implement correctly.
Private Function GetTmpDir As String
%REM
Gets (if exists) or creates a temporary directory temp in the Notes data directory
IN
Nothing.
OUT
Nothing.
RETURN
The temporary directory, terminated by ""
%END REM
On Error Goto TmpDirError
Dim s As New NotesSession
Dim TmpDir As String
'Directory is the Notes data Directory identified in User Preferences
TmpDir = s.GetEnvironmentString ("Directory", True)
If TmpDir <> "" And Right(TmpDir, 1) <> "\" Then TmpDir = TmpDir & "\"
TmpDir = TmpDir & "temp\"
If Dir$ (TmpDir , 16)="" Then
Mkdir TmpDir
End If
TmpDir = TmpDir & ""
GetTmpDir = TmpDir
Exit Function
TmpDirError:
On Error Goto 0
GetTmpDir = "c:\temp\"
Exit Function
End Function