I think I've got it. The answer lies in the ShellExecute API function, along with some rummaging through the FolderItemVerbs shell object, where these associated commands (called "verbs" by Microsoft, apparantly) are stored. So here's the method I've developed for printing attachments:
Option Explicit
Private Declare Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" _
(ByVal hwnd As Long, ByVal lpOperation As String, ByVal lpFile As String, _
ByVal lpParameters As String, ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long
Private Declare Function GetTempPath Lib "kernel32" Alias "GetTempPathA" _
(ByVal nBufferLength As Long, ByVal lpBuffer As String) As Long
Public Function printAttachment(ByRef atm As Attachment) As Boolean
' Runs print command on associated file. Returns False if file cannot be printed.
On Error GoTo ErrorHandler
Dim tempFilePath As String, tempDir As String, i As Integer, fs
Set fs = CreateObject("Scripting.FileSystemObject")
' Get temp directory
tempDir = GetTempDirectory
' Ensure another temporary file is not replaced
Do
i = i + 1
tempFilePath = tempDir & i & atm.FileName
Loop While fs.fileExists(tempFilePath)
Debug.Print "FilePath: " & tempFilePath
' Save temporary file
atm.SaveAsFile tempFilePath
' Check file for print verb. Print if found, then delete temp file and exit function
Dim v, verbs As Variant
verbs = GetFileVerbs(tempFilePath)
For Each v In verbs
If v = "&Print" Then
ShellExecute 0, "print", tempFilePath, "", tempDir, 0
fs.DeleteFile tempFilePath, True
printAttachment = True
Exit Function
End If
Next
' File is not printable. Delete temp file and return false
printAttachment = False
fs.DeleteFile tempFilePath, True
Exit Function
' Something went wrong; return false
ErrorHandler:
If fs.fileExists(tempFilePath) Then fs.DeleteFile (tempFilePath)
printAttachment = False
End Function
Public Function GetTempDirectory() As String
' Borrowed from http://www.developerfusion.co.uk/show/2561/4/
Dim s As String
Dim c As Long
s = Space$(MAX_LENGTH)
c = GetTempPath(MAX_LENGTH, s)
If c > 0 Then
If c > Len(s) Then
s = Space$(c + 1)
c = GetTempPath(MAX_LENGTH, s)
End If
End If
GetTempDirectory = IIf(c > 0, Left$(s, c), "")
End Function
Public Function GetFileVerbs(FilePath As String) As Variant
' Returns string array of verb names
Dim sh As Object, folder1 As Object, file1 As Object, verbcol As Object, i As Integer
Set sh = CreateObject("Shell.Application")
For i = Len(FilePath) To 1 Step -1
If Mid(FilePath, i, 1) = "" Then
Set folder1 = sh.NameSpace(Left(FilePath, i - 1))
Exit For
End If
Next
Set file1 = folder1.ParseName(Mid(FilePath, i + 1))
Set verbcol = file1.verbs
Dim verbStrings() As Variant, v As Object
ReDim verbStrings(verbcol.count - 1)
For i = 0 To verbcol.count - 1
Set v = verbcol.Item(i + 1)
verbStrings(i) = v.Name
Next
GetFileVerbs = verbStrings
End Function
Some things I noted about this process:
- As mentioned before, this utilizes the print "verb" as configured for a file extension in the File Types tab of the Folder Options window. That process is also called by right-clicking a file and selecting Print from the shortcut menu, which is an easy way to test it. I also wrote the GetFileVerbs function to return a list of available verb names, which might be useful if you ever have to experiment with additional verb commands.
- The FolderItemVerb shell object has a DoIt method which could have been used instead of the ShellExecute function. However, ShellExecute seems to wait for the file to be sent to the printer before continuing code execution -- which is important since the next step involves deleting the temporary file. Using the DoIt method caused the file to be deleted before the default application could load it. Then again, I've only tested this on my computer, so it may be different on other systems.
- The above process utilizes the system Temp directory, obtained through the GetTempDirectory function graciously borrowed from Thushan Fernando. This should make the function more portable to other systems. However, for some reason, the Kodak Imaging Previewer (kodakprv.exe /p) doesn't seem to be able to load files from this directory on my system. I may have to recode the above function to allow for a different temp directory... unless I can find another image printer that will work properly.
Now that this is coming along, I should see if there's a decent way to print just the main email (no attachments) of an Outlook MailItem object without resorting to the PrintOut method. With that, I can rewrite my original Email Converter program to account for unprintable files.
If anyone finds this useful, relevent, or at the very least just a little bit interesting, drop me a line.