You can use your favorite social network to register or link an existing account:
Or use your email address to register without a social network:
Sign in with these social networks:
Or enter your username and password
Forgot your password?
Yes, please link my existing account with for quick, secure access.
No, I would like to create a new account with my profile information.
Rob Cooper recently made a post, Adding Attachments from a Folder, which shows how to add a single attachment file per row. But what if you wanted to add more than one file? One (highly contrived) scenario would be to add all of the files in a folder to one row, and do so recursively if requested, similar to Rob's example.
What follows is some VBA code to do this, which borrows a bit from Rob's post and a bit from one of my earlier posts. However, I should point out this (again, highly contrived scenario) is meant only as an example and not something I would recommend doing, because if you are adding more than just a few files you can (ok, WILL) bloat your database very quickly, and in doing so can negatively impact performance and potentially hit the two gigabyte file size limit very quickly (see Access 2007 Specifications for details on database file size and object limitations).
First, to use the following sample code you will need to do some setup. Create a new table, add the following fields, and save it as Table1:
Table1
Next, open the VBE window (ALT+F11) and insert a new module (Insert -> Module), and paste in the following code:
' ------------------------------------------------------------------------- ' Procedure : StoreFilesInTable ' Purpose : Adds all files matching the specified file mask from the ' : specified folder to an attachment field. ' : Each row in the represents all files stored from the folder. ' Arguments : strFolder - The path to the folder stored in the attachment field. ' : strTable - The name of the table containing the attachment field. ' : strPathField - The name of the field for the archived folder. ' : strAttachmentField - The name of the attachment field. [Files] ' : strPattern - File mask. [*.*] ' : blnIncludeSubfolders - Recurse into subfolders. [False] ' : db1 - The database to operate on. [CurrentDb] ' Comments : The db1 param is included so this can be used to store files in ' : a separate database, since using the attachment field this way ' : can quickly push a database beyond the 2gb file size limit. ' ------------------------------------------------------------------------- Public Function StoreFilesInTable( _ ByVal strFolder As String, _ ByVal strTable As String, _ ByVal strPathField As String, _ Optional ByVal strAttachmentField As String = "Files", _ Optional ByVal strPattern As String = "*.*", _ Optional ByVal blnIncludeSubfolders As Boolean = False, _ Optional ByRef db1 As DAO.Database) Const CALLER = "StoreFilesInTable" On Error GoTo StoreFilesInTable_ErrorHandler Dim strFilePath As String Dim rstParent As DAO.Recordset2 Dim rstChild As DAO.Recordset2 Dim fldAttach As DAO.Field2 ' These objects require a reference to the "Microsoft Scripting Runtime" ' but are defined as "Object" instead to use late binding and avoid that. ' If you've added the reference, remove the "Object" and uncomment the ' following lines to get the intellisense autocomplete for these objects. Dim objFso As Object ' Scripting.FileSystemObject Dim objFolder As Object ' Scripting.Folder Dim objSubFolder As Object ' Scripting.Folder Dim objFile As Object ' Scripting.File ' If the user did not specify a database, use the current one. If db1 Is Nothing Then Set db1 = Application.CurrentDb ' Instantiate the FileSystemObject. Set objFso = CreateObject("Scripting.FileSystemObject") ' Make sure the folder path always ends with a "\". If (Right(strFolder, 1) <> "\") Then strFolder = strFolder & "\" ' Make sure the folder exists. If Not objFso.FolderExists(strFolder) Then MsgBox "Folder does not exist: " & strFolder, _ vbExclamation, CALLER Exit Function End If ' It exists, so get the folder object. Set objFolder = objFso.GetFolder(strFolder) ' Open the table containing the attachment field Set rstParent = db1.OpenRecordset(strTable) rstParent.AddNew rstParent.Fields(strPathField).Value = objFolder.Path ' Get the first file in this directory. strFilePath = Dir(strFolder & strPattern) ' Store each file that meets the pattern While (Len(strFilePath) > 0) Set rstChild = rstParent.Fields(strAttachmentField).Value rstChild.AddNew Set fldAttach = rstChild.Fields("FileData") fldAttach.LoadFromFile strFolder & strFilePath rstChild.Update rstChild.Close strFilePath = Dir() ' Get the next file Wend ' Commit the new row with the attachments field populated ' with all of the files from the current folder. rstParent.Update ' Recurse into subfolders if requested. If (blnIncludeSubfolders) Then For Each objSubFolder In objFolder.SubFolders StoreFilesInTable objSubFolder.Path, strTable, _ strPathField, strAttachmentField, _ strPattern, blnIncludeSubfolders, db1 Next End If Cleanup: rstParent.Close Set rstParent = Nothing Exit Function StoreFilesInTable_ErrorHandler: Debug.Print "Error # " & Err.Number & " in " & CALLER & " : " & Err.Description MsgBox Err.Description, vbCritical, "Error # " & Err.Number & " in " & CALLER GoTo Cleanup End Function 'StoreFilesInTable
' ------------------------------------------------------------------------- ' Procedure : StoreFilesInTable ' Purpose : Adds all files matching the specified file mask from the ' : specified folder to an attachment field. ' : Each row in the represents all files stored from the folder. ' Arguments : strFolder - The path to the folder stored in the attachment field. ' : strTable - The name of the table containing the attachment field. ' : strPathField - The name of the field for the archived folder. ' : strAttachmentField - The name of the attachment field. [Files] ' : strPattern - File mask. [*.*] ' : blnIncludeSubfolders - Recurse into subfolders. [False] ' : db1 - The database to operate on. [CurrentDb] ' Comments : The db1 param is included so this can be used to store files in ' : a separate database, since using the attachment field this way ' : can quickly push a database beyond the 2gb file size limit. ' ------------------------------------------------------------------------- Public Function StoreFilesInTable( _ ByVal strFolder As String, _ ByVal strTable As String, _ ByVal strPathField As String, _ Optional ByVal strAttachmentField As String = "Files", _ Optional ByVal strPattern As String = "*.*", _ Optional ByVal blnIncludeSubfolders As Boolean = False, _ Optional ByRef db1 As DAO.Database)
Const CALLER = "StoreFilesInTable" On Error GoTo StoreFilesInTable_ErrorHandler
Dim strFilePath As String Dim rstParent As DAO.Recordset2 Dim rstChild As DAO.Recordset2 Dim fldAttach As DAO.Field2
' These objects require a reference to the "Microsoft Scripting Runtime" ' but are defined as "Object" instead to use late binding and avoid that. ' If you've added the reference, remove the "Object" and uncomment the ' following lines to get the intellisense autocomplete for these objects. Dim objFso As Object ' Scripting.FileSystemObject Dim objFolder As Object ' Scripting.Folder Dim objSubFolder As Object ' Scripting.Folder Dim objFile As Object ' Scripting.File
' If the user did not specify a database, use the current one. If db1 Is Nothing Then Set db1 = Application.CurrentDb
' Instantiate the FileSystemObject. Set objFso = CreateObject("Scripting.FileSystemObject")
' Make sure the folder path always ends with a "\". If (Right(strFolder, 1) <> "\") Then strFolder = strFolder & "\"
' Make sure the folder exists. If Not objFso.FolderExists(strFolder) Then MsgBox "Folder does not exist: " & strFolder, _ vbExclamation, CALLER Exit Function End If
' It exists, so get the folder object. Set objFolder = objFso.GetFolder(strFolder)
' Open the table containing the attachment field Set rstParent = db1.OpenRecordset(strTable)
rstParent.AddNew rstParent.Fields(strPathField).Value = objFolder.Path
' Get the first file in this directory. strFilePath = Dir(strFolder & strPattern)
' Store each file that meets the pattern While (Len(strFilePath) > 0) Set rstChild = rstParent.Fields(strAttachmentField).Value rstChild.AddNew Set fldAttach = rstChild.Fields("FileData") fldAttach.LoadFromFile strFolder & strFilePath rstChild.Update rstChild.Close strFilePath = Dir() ' Get the next file Wend
' Commit the new row with the attachments field populated ' with all of the files from the current folder. rstParent.Update
' Recurse into subfolders if requested. If (blnIncludeSubfolders) Then For Each objSubFolder In objFolder.SubFolders StoreFilesInTable objSubFolder.Path, strTable, _ strPathField, strAttachmentField, _ strPattern, blnIncludeSubfolders, db1 Next End If
Cleanup: rstParent.Close Set rstParent = Nothing
Exit Function StoreFilesInTable_ErrorHandler: Debug.Print "Error # " & Err.Number & " in " & CALLER & " : " & Err.Description MsgBox Err.Description, vbCritical, "Error # " & Err.Number & " in " & CALLER GoTo Cleanup End Function 'StoreFilesInTable
Here is a short routine to help you test the above code. You will need to change the "<YourUserName>" to your login name, or just change the whole path in the strRootFolder string constant to the folder you want to store in the table. Note that I've set the blnIncludeSubfolders parameter to False to keep you from inadvertently bloating your database, but you can set it to True if you want to include all of the subfolders, too.
Sub TestStoreFilesInTable() Const strRootFolder As String = "C:\Users\<YourUserName>\Pictures\" StoreFilesInTable strRootFolder, "Table1", "FolderPath", "Files", "*.jpg", False MsgBox "Done adding files from: " & vbCrLf & strRootFolder & "*.jpg", _ VbMsgBoxStyle.vbInformation, "TestStoreFilesInTable" End Sub
Comments: (10) Collapse
Off-topic: Where can I report A2007 bugs?
How do I export A2007 report to PDF? I desperately NEED to apply filter on the report data. It's very easy with PDFCreator but I can't do it in A2007. I'm stuck!
P.S. I can't do it in A2007 without PDFCreator. P.P.S. How do I export macro to VBA in A2007?
Vladimir, Feel free to send me bug reports. Most of the bugs we take in Access 2007 codebase are issues reported by customers through our support organization. The bar for fixes is pretty high as we don't want to introduce other regressions. Export a report to pdf should be straight forward. Download and install the addin. Open a report in browse mode or open the report in print preview with a filter. If you use browse mode use the right click filters to filter it down. Then you can use External Data | Export | PDF/XPF. The integration should be just like any other export formats. WRT - save macro as VBA... Open the form/report in design view. Use the command Database Tools | Macros | Convert Form's Macro to Visual Basic.
Many thanks for this Posting. It gifs me a good solution for one of my problems. Thanks and many greagings.
Clint C.
I'll report some bugs & issues soon. PDF: I'd appreciate if there was an option to set filter during DoCmd.OutputTo and DoCmd.SendObject. I have a procedure which automatically creates more than 30 reports (accountings - annular analysis & report) without user's response. I need to apply filter for some of the reports and I need to do it in VBA to automate the process. So, if I want to use Office 2007's PDF add-in I must do some more coding in reports to apply filter through a global variable. I can't use report's OpenArgs to apply the filter.
PDF printer would do the trick. Office 2007's PDF add-in installs a virtual printer "Microsoft XPS Document Writer". I'd appreciate "Microsoft PDF Document Writer" as well.
>I must do some more coding in reports to apply filter through a global variable Don’t use global here (they are not needed and it is a VERY poor coding practice). Open the report in preview mode + where clause, and then send it to pdf. Here a simple code snip Dim strR As String strR = "contacts" DoCmd.OpenReport strR, acViewPreview, , "ID = " & Me!ID Reports(strR).visible = False DoCmd.OutputTo acOutputReport, strR, acFormatPDF, "c:\t.pdf" DoCmd.Close acReport, strR You of course could/would wrap the above code in a nice sub that you can call over and over... Albert D. Kallal
Edmonton, Alberta Canada
Albert D. Kallal said on August 3, 2008 2:15 PM:
Thanks a million for the trick! Couldn't find it in A2007 help examples.
Not sure of using this scenario since the screen is blinking due to acViewPreview. I'd like to let the Echo True so that users can see some action. But I really hate blinking screens... so do many users. I'll keep trying to adapt your code snipet for a non-blinking function.
If you turn off the application echo before you launch the report, you not see any echo from the report. strR = "contacts" Application.Echo False DoCmd.OpenReport strR, acViewPreview, , "ID = " & Me!ID Reports(strR).visible = False DoCmd.OutputTo acOutputReport, strR, acFormatPDF, "c:\t.pdf" DoCmd.Close acReport, strR Application.Echo True The flicker you see is likey the dialog box from use of outputTo. I kind of like that dialog since it shows somthing is going on. So, give the echo idea you mentioned a try.
by the way, you *can* surpress the dialog box. there is some code at the access web, not sure if it works with 07
Comments: (loading) Collapse