ND6 Bible example: Save and Open Attachment code - PART 2
Category Technical
Bookmark :
NOTE: This story is a continuation of ND6 Bible example: Save and Open Attachment code - PART 1, which can be viewed here.
In our last installment I introduced you to my Detach and Open feature, and how it works. This installment dives into the code itself.
Spelunking the code
The code is actually pretty simple for this. First, there is a field on the form called "Attachments" with the simple formula @AttachmentNames. The values in this field are used to check for multiple attachments, and as the choices for the dialog above if there is more than one attachment. This field is a Computed For Display (CFD) field.
The Detach and Open action calles an agent called DetachOpen. This agent loads a script library called LS.Utilities.FE (more on it later). The rest of the agent code looks like this....
The code:
Sub Initialize
On Error Goto errHandler
Dim ws As New NotesUIWorkspace
Dim doc As NotesDocument
Dim attachname As Variant, attachnamelist As Variant
Dim retflg As Boolean
Set doc = ws.CurrentDocument.Document
attachnamelist = doc.Attachments
If Ubound(attachnamelist) = 0 And attachnamelist(0) = "" Then
Error 1000, "No attachments in this document."
End If
If Ubound(attachnamelist) > 0 Then
attachname = ws.Prompt(PROMPT_OKCANCELLIST, "Attachment",_
"Choose the attachment to open...", attachnamelist(0), attachnamelist)
If Isempty(attachname) Then Exit Sub
Else
attachname = attachnamelist(0)
End If
REM detachFileOpen(doc As NotesDocument, rtname As String, fname As String) As Boolean
retflg = detachFileOpen(doc, "Files", Cstr(attachname))
getOut:
Exit Sub
errHandler:
Select Case Err
Case 1000
Msgbox Error$,,"Error"
Case Else
Msgbox Error$ & " (" & Err & ") [in DetachOpen agent]",,"Unhandled Error"
End Select
Resume getOut
End Sub
So, all this code really does is figure out if I need to prompt the user to choose an attachment (if there is more than one), get the file name, then hand it off to the detachFileOpen function, which comes from the LS.Utilities.FE (FE for "front-end") script library.
The LS.Utilities.FE library loads the LS.Utilities.BE (BE for "back-end") script library, which contains a collection of useful back-end (i.e. no UI) functions (incidentally, a version of this library is downloadable from here). The detachFileOpen function in the LS.Utilities.FE library looks like this:
Function detachFileOpen(doc As NotesDocument, rtname As String, fname As String) As Boolean
On Error Goto errHandler
detachFileOpen = True
Dim ws As New NotesUIWorkspace
Dim rtitem As NotesRichTextItem
Dim fpath As Variant
Dim retflg As Boolean, res As Long, res2 As Integer
Dim exepath As String, shellpath As String
REM this holds the executable path
exepath = String(MAX_FILENAME_LEN, 32)
REM prompt the user for where to save the attachment
fpath = ws.SaveFileDialog(False, "Save Attachment and Open", "", "", fname)
If Isempty(fpath) Then
detachFileOpen = False
Exit Function
End If
REM detach the file (this function is from the LS.utilities.BE lib)
retflg = detachFile(doc, rtname, fname, Cstr(fpath(0)))
REM use the C API call to find the associated executable
res = FindExecutable(Cstr(fpath(0)), "", exepath)
REM shorten the executable, removing the extra spaces
exepath = Left$(exepath, Instr(exepath, Chr$(0)) - 1)
REM prep the string to pass to the shell command
If Fulltrim(exepath) = "" Then Error 1000, "Unable to locate associated program"
shellpath = exepath & | "| & fpath(0) & |"|
REM open the file with the associated executable
res2 = Shell(shellpath)
getOut:
Exit Function
errHandler:
On Error Goto 0
Error Err, "(" & Err & ") " & Error$ & " [in " & Lsi_info(2) & "]"
Resume getOut
End Function
This function prompts the user to find out the location where she wants to save the file, and then saves the file there using the detachFile function (which is from the LS.Utilities.BE library - and I'm not covering that function today, it is pretty straightforward). It then hands the filepath to a Win32 C API function called FindExecutable, which is declared in the Declarations of the FE library, like so:
(Declarations)
REM this C API call is used to find the executable associated with a file
REM this function is used by the detachFileOpen function
Const MAX_FILENAME_LEN = 260
Declare Function FindExecutable Lib "shell32.dll" Alias "FindExecutableA" _
(Byval lpFile As String, Byval lpDirectory As String, Byval lpResult As String) As Long
I discovered how to declare this function using the wonderful (and free) C API Guide (read more about it here). This function figures out the associated program executable path from the file extension of the provided file path.
Then I simply take that executable path, trim it, and build a string containing the filepath and the executable path that I can hand to the Shell function. Some of you are asking, "Rock, you idiot! You can just hand the filepath itself to the shell function!" Wrong-o, my simpleton friend. The Shell function only works with executables, not with files. Therefore we need to hand it a string in the form of
EXEpath "FilePath"
This format tells the executable to open and launch the provided file. BTW, it is important to include the double-quotes around the filepath, which is what this line does in my function:
shellpath = exepath & | "| & fpath(0) & |"|
Conclusion
I encourage you to download the example and look through it. It provides simple yet useful functionality that can be easily integrated into any application. It also demonstrates proper error handling, chaining of script libraries, and C API calls.
If you have any questions, or want to share kewl stuff you've done, please post them here!
Rock
**Good thing the guy's name was Henry Ford and not Henry Anal. Otherwise, a half million Americans would be driving Anal Probes.







Blog Roll









Comments
Rock
Posted by Rock At 02:40:44 PM On 02/13/2004 | - Website - |
Shell( Environ$( "ComSpec" ) & " /C """ & path$ & """" )
Posted by Nik Shenoy At 02:27:02 PM On 02/13/2004 | - Website - |