VBA DoCmd.OutputTo With QueryDef - ms-access

I've been looking a while now for a solution to export a query with open parameters. I need to export a Query as a Formatted Excel Spreadsheet and can't create additional Tables, Queries, Forms, or Reports to the Database being used. I use DoCmd.OutputTo as it exports a formatted query unlike DoCmd.TransferSpreadsheet however I can't seem to export the query with defined parameters. I need to include the parameters or else the user will be forced to input the start and end date three times a piece as the database for some reason asks for the startDate and endDate twice and in order to keep the excel spreadsheet and the subsequent outlook section consistant i would have to ask the user to input their previous parameters again
Sub Main()
On Error GoTo Main_Err
'Visually Display Process
DoCmd.Hourglass True
Dim fpath As String
Dim tname As String
Dim cname As String
Dim tType As AcOutputObjectType
Dim tempB As Boolean
fpath = CurrentProject.path & "\"
'tType = acOutputTable
'tname = "APPROVED SWPS FOR LOOK AHEAD & BAR CHART"
tType = acOutputQuery
tname = "ASFLA&BC Query"
cname = "Temp BPC Calendar"
Dim qdfQry As DAO.QueryDef
Dim strStart As String
Dim strEnd As String
Set qdfQry = CurrentDb().QueryDefs(tname)
'strStart = InputBox("Please enter Start date (mm/dd/yyyy)")
'strEnd = InputBox("Please enter Start date (mm/dd/yyyy)")
qdfQry.Parameters("ENTER START DATE") = FormatDateTime("6/30/12", vbShortDate) 'strEnd
qdfQry.Parameters("ENTER END DATE") = FormatDateTime("7/1/12", vbShortDate) 'strStart
tempB = Backup(fpath, qdfQry, tType)
If (Not tempB) Then
MsgBox "Excel Conversion Ended Prematurely..."
Exit Sub
End If
' tempB = sendToOutlook(qdfQry, cname)
' If (Not tempB) Then
' MsgBox "Access Conversion Ended Prematurely..."
' Exit Sub
' End If
MsgBox "Procedure Completed Successfully"
Main_Exit:
DoCmd.Hourglass False
Exit Sub
Main_Err:
DoCmd.Beep
MsgBox Error$
Resume Main_Exit
End Sub
'************************************************************************************
'*
'* Excel PORTION
'*
'************************************************************************************
Public Function Backup(path As String, db As DAO.QueryDef, Optional outputType As AcOutputObjectType) As Boolean
On Error GoTo Error_Handler
Backup = False
Dim outputFileName As String
Dim name As String
Dim tempB As Boolean
'Set Up All Name Variablesand
name = Format(Date, "MM-dd-yy") & ".xls"
'Cleans Directory of Any older files and places them in an archive
SearchDirectory path, "??-??-??.xls", name
'See If File Can Now Be Exported. If Already Exists ask to overwrite
outputFileName = path & name
tempB = OverWriteRequest(outputFileName)
If tempB Then
'Formats The Table And Exports Into A Formatted SpreadSheet
'Checks if an output type was added to the parameter if not defualt to table
If Not IsMissing(outputType) Then
DoCmd.OutputTo outputType, db.name, acFormatXLS, outputFileName, False
Else
DoCmd.OutputTo acOutputTable, db.name, acFormatXLS, outputFileName, False
End If
Else
Exit Function
End If
Backup = True
Error_Handler_Exit:
Exit Function
Error_Handler:
MsgBox "MS Access has generated the following error" & vbCrLf & vbCrLf & "Error Number: " & _
Err.number & vbCrLf & "Error Source: Main Excel Backup" & vbCrLf & "Error Description: " & _
Err.Description, vbCritical, "An Error has Occured!"
Resume Error_Handler_Exit
End Function
The SQL currently given looks like similar to below with omitted fields for for clarity
PARAMETERS [ENTER START DATE] DateTime, [ENTER END DATE] DateTime;
SELECT [SWPS].STATION,
[SWPS].START_DATE,
[SWPS].END_DATE,
FROM [SWPS]
WHERE ((([SWPS].STATION)
Like ("*"))
AND (([SWPS].START_DATE)<=[ENTER END DATE])
AND (([SWPS].END_DATE)>=[ENTER START DATE])
AND (([SWPS].SWP_STATUS) In ("A","P","W","T","R")));

I suggest you change the sql of the query.
Dim qdfQry As DAO.QueryDef
Dim strStart As String
Dim strEnd As String
''You could use a query specifically for this
Set qdfQry = CurrentDb.QueryDefs(tname)
sSQL=qdfQry.SQL
NewSQL = "SELECT [SWPS].STATION, [SWPS].START_DATE, [SWPS].END_DATE, " _
& "FROM [SWPS] WHERE [SWPS].STATION Like '*' " _
& "AND [SWPS].SWP_STATUS In ('A','P','W','T','R') " _
& "AND [SWPS].START_DATE)<=#" & Format(DateStart, "yyyy/mm/dd") & "# " _
& "AND [SWPS].END_DATE)>=#" & Format(DateEnd, "yyyy/mm/dd") & "#"
qdfQry.SQL = NewSQL
''Do the excel stuff
''Reset the query
qdfQry.SQL = sSQL

Related

How to compare data types of 2 tables in MS Access

Is there a way wherein I will be able to compare data types of 2 tables in MS Access? I have one table with 66 columns with specified names (Like ID, Name, ETc...) and another table that will be autogenerated based on an extract with the same number of columns but the field names default (F1, F2, F3, ... F66) so would like to check if there is a way in access that I can compare the data types of 66 columns from both tables? Thanks Much! :D
You can use some VBA to loop the Fields collection of each table. Something like this should get you started:
Sub sCompareTables(strTable1 As String, strTable2 As String)
On Error GoTo E_Handle
Dim db As DAO.Database
Dim tdf1 As DAO.TableDef
Dim tdf2 As DAO.TableDef
Dim lngLoop1 As Long
Set db = CurrentDb
Set tdf1 = db.TableDefs(strTable1)
Set tdf2 = db.TableDefs(strTable2)
If tdf1.Fields.Count = tdf2.Fields.Count Then
For lngLoop1 = 0 To tdf1.Fields.Count - 1
If tdf1.Fields(lngLoop1).Type = tdf2.Fields(lngLoop1).Type Then
Debug.Print "Match: " & tdf1.Fields(lngLoop1).name & vbTab & tdf2.Fields(lngLoop1).name & vbTab & fDatatype(tdf1.Fields(lngLoop1).Type)
Else
Debug.Print "No Match: " & tdf1.Fields(lngLoop1).name & vbTab & tdf2.Fields(lngLoop1).name & vbTab & fDatatype(tdf1.Fields(lngLoop1).Type) & "|" & fDatatype(tdf2.Fields(lngLoop1).Type)
End If
Next lngLoop1
Else
Debug.Print "Field counts do not match"
End If
sExit:
On Error Resume Next
Set tdf1 = Nothing
Set tdf2 = Nothing
Set db = Nothing
Exit Sub
E_Handle:
MsgBox Err.Description & vbCrLf & vbCrLf & "sCompareTables", vbOKOnly + vbCritical, "Error: " & Err.Number
Resume sExit
End Sub
Function fDatatype(lngDatatype As Long) As String
On Error GoTo E_Handle
Select Case lngDatatype
Case 4
fDatatype = "Long"
Case 8
fDatatype = "Date"
Case 10
fDatatype = "Text"
Case 12
fDatatype = "Memo"
Case Else
fDatatype = "Unknown"
End Select
fExit:
On Error Resume Next
Exit Function
E_Handle:
MsgBox Err.Description & vbCrLf & vbCrLf & "fDatatype", vbOKOnly + vbCritical, "Error: " & Err.Number
Resume fExit
End Function
The function fDatatype that I've created does not list all of the available datatypes that are available - you can see a full list by pressing F2 to bring up the Object Browser, and searching for something like dbText to see all members of the DAO.DataTypeEnum class.

Access 2007 VBA Error 2467 for function

Having a very weird problem. I have a function which is called when a form field gets focus. The function is passed four arguments, three of which are values from form fields and the fourth is a global variable which is set when the form loads. The function uses these variables to calculate the value for the field which called the function. This function is called in two different places. Everything was working fine, and now suddenly the function works when called from one place and doesn't work from the other, generating a 2467 run-time error, 'The expression you entered refers to an object that is closed or doesn't exists'. I've checked that the values of the arguments being passed are correct, the function exists OK, so can't see why I'm getting this error. Anyone any ideas?
Private Sub cboFinalStage_GotFocus()
'lookup stage based on TNM values
cboFinalStage = FindStage(cboFinalStageT, cboFinalStageN, cboFinalStageM, gblCancer)
End Sub
Public Function FindStage(cboT As ComboBox, cboN As ComboBox, cboM As ComboBox,
strCancer As String) As String
'use the TNM values entered to find the correct stage for the site and return it
'error handling
If gcfHandleErrors Then On Error GoTo PROC_ERR
'declare variables
Dim strTemp As String
Dim strTable As String
Dim db As DAO.Database
Dim rs As DAO.Recordset
Dim strQuery As String
Dim strSite As String
Dim strSiteFull As String
Dim strT As String
Dim strN As String
Dim strM As String
'initialise variables - if there are no values entered in the 3 comboboxes, exit
'load tumour first in case it isn't already loaded
Forms!frmContainer.subTumour.SourceObject = "fsubTumour"
If Not IsNull(Forms!frmContainer.subTumour.Form!txtICD10) Then
strSite = Left(Forms!frmContainer.subTumour.Form!txtICD10, 3)
strSiteFull = Forms!frmContainer.subTumour.Form!txtICD10
End If
If Not IsNull(cboT.Value) Then
strT = cboT.Value
Debug.Print "T is " & strT
End If
If Not IsNull(cboN.Value) Then
strN = cboN.Value
Debug.Print "N is " & strN
End If
If Not IsNull(cboM.Value) Then
strM = cboM.Value
Debug.Print "M is " & strM
End If
If (IsNull(strT) Or IsNull(strN) Or IsNull(strM)) Then
Debug.Print "null so exiting"
Exit Function
End If
'identify the correct AJCC lookup table by cancer site
Select Case [strCancer]
Case "bla"
strTable = "lkp_AJCC_bladder"
Case "bre"
strTable = "lkp_AJCC_breast"
...
End Select
Debug.Print "AJCC table is " & strTable
'query the AJCC lookup table for the stage
strQuery = "SELECT c_stage FROM " & strTable & " WHERE (((t_value)='" & strT & "')
AND ((n_value)='" & strN & "') AND ((m_value)='" & strM & "'))"
Debug.Print "query is " & strQuery
Set db = CurrentDb
Set rs = db.OpenRecordset(strQuery)
If Not rs.EOF Then
strTemp = rs.Fields(0).Value
Debug.Print "result is " & strTemp
End If
rs.Close
db.Close
'return stage
FindStage = strTemp
'error handling
PROC_EXIT:
Exit Function
PROC_ERR:
If (Err.Number = 2467) Then
MsgBox "Unable to evaluate the stage", vbOKOnly, "Processing error"
Resume PROC_EXIT
Else
MsgBox "Error: (" & Err.Number & ") " & Err.Description, vbCritical
Resume PROC_EXIT
End If
End Function

Force a zip to open unzip to specific location

I'm making a very basic data entry and database system application using excel (for bulk data entry) and Access (to house the data). I play to distribute it as a zip file. In order for it to work I need the file structure to remain unchanged and to unzip to c:/ drive. Is there anyway to force a zip file to unzip to a specific location?
The reason I need this is to automate the uploading of entered data. As far as I know in Access VBA you have to specify full filepaths in VBA to import data.
* Update
Thanks to Remou for getting me out of the woods. Just for posterity's sake this is how I solved it. not the prettiest code but it does the job. First the import function and then the export function.
Importing, a naming convention is still need for the files being uploaded but they can come from anywhere. That file name relates to the tables they will be stored in. At the back end of the excel sheets the data input sheet is split into two (Rec and Occ)
Code as follows:
Function importData_Click(Optional varDirectory As String, _
Optional varTitleForDialog As String) As String
Dim strFilter As String
Dim lngFlags As Long
Dim varFileName As String
Dim strFileName As String
Dim strTableName As String
Dim strColumnName As String
Dim The_Year As Long
Dim occNumber As Long
'Get combobox value and assign relavent values to occNumber
The_Year = Forms![Upload Data]!Year_Combo.value
'Ask the to check value
If MsgBox("Uploading " & The_Year & " data" & vbCrLf & "Continue?", VbMsgBoxStyle.vbYesNo) = 7 Then
Exit Function
End If
If The_Year = 2012 Then
occNumber = 1000
ElseIf The_Year = 2013 Then
occNumber = 2000
End If
' Specify that the chosen file must already exist,
' don't change directories when you're done
' Also, don't bother displaying
' the read-only box. It'll only confuse people.
lngFlags = ahtOFN_FILEMUSTEXIST Or _
ahtOFN_HIDEREADONLY Or ahtOFN_NOCHANGEDIR
If IsMissing(varDirectory) Then
varDirectory = ""
End If
If IsMissing(varTitleForDialog) Then
varTitleForDialog = ""
End If
strFilter = ahtAddFilterItem("Excel Files (*.xlsx)", "*.xlsx")
varFileName = ahtCommonFileOpenSave( _
openFile:=True, _
InitialDir:=varDirectory, _
Filter:=strFilter, _
Flags:=lngFlags, _
DialogTitle:=varTitleForDialog)
If Not IsNull(varFileName) Then
varFileName = TrimNull(varFileName)
End If
importData_Click = varFileName
'Sets filename
strFileName = Dir(varFileName)
'Sets TableName
strTableName = Left(strFileName, 4)
If IsNull(strFileName) Then
MsgBox "Upload cancelled"
Exit Function
End If
'Checks naming convetions of filenames
If strTableName Like "*MN" Or strTableName Like "*OP" Or strTableName Like "*DA" Or strTableName Like "*TR" Then
'Checks if data is Opportunistic
If strTableName Like "*OP" Then
strColumnName = "Year_" & strTableName
'Checks to see if that year's data already exists
If DLookup(strColumnName, strTableName & "_Rec", "" & strColumnName & " = " & The_Year & "") Then
MsgBox "2012 data is already present"
ElseIf DLookup(strColumnName, strTableName & "_Rec", "" & strColumnName & " = " & The_Year & "") Then
MsgBox "2013 data is already present"
Else
'Uploads data to relevant table
DoCmd.TransferSpreadsheet acImport, acSpreadsheetTypeExcel12Xml, strTableName & "_Rec", varFileName, True, "Rec_Prep$"
MsgBox "Upload successful"
End If
Exit Function
Else
strColumnName = "Occasion_" & strTableName
'Checks Occasions to see if that year exists
If DLookup(strColumnName, strTableName & "_Rec", "" & strColumnName & " = " & occNumber & "") Then
MsgBox "2012 data is already present"
ElseIf DLookup(strColumnName, strTableName & "_Rec", "" & strColumnName & " = " & occNumber & "") Then
MsgBox "2013 data is already present"
Else
'Uploads to Records table and Occasion table
DoCmd.TransferSpreadsheet acImport, acSpreadsheetTypeExcel12Xml, strTableName & "_Occ", varFileName, True, "Occ_Prep$"
DoCmd.TransferSpreadsheet acImport, acSpreadsheetTypeExcel12Xml, strTableName & "_Rec", varFileName, True, "Rec_Prep$"
MsgBox "Upload successful"
End If
End If
Else
MsgBox "Your file is named incorrectly! & vbCrLf & Please refer to the Data Dictionary & vbCrLf & for correct naming conventions"
Exit Function
End If
'DoCmd.TransferSpreadsheet acExport, acSpreadsheetTypeExcel12Xml, "BaMN_AllData", strSaveFileName
End Function
Private Function TrimNull(ByVal strItem As String) As String
Dim intPos As Integer
intPos = InStr(strItem, vbNullChar)
If intPos > 0 Then
TrimNull = Left(strItem, intPos - 1)
Else
TrimNull = strItem
End If
End Function
Then the export uses the names of command buttons (that match table names) to export to wherever the user wants:
Dim queryYear As Variant
'Function to export data to location of users choice. Query name is automatically detected from the control button used
'Year is derived from the combobox value on [Extract Data] form, null value defaults to all years.
Function exportData_Click()
Dim strFilter As String
Dim strSaveFileName As String
Dim The_Year As Variant
Dim ctlCurrentControl As Control
Dim queryName As String
'Get the name of the control button clicked (corresponds to query name to be run)
Set ctlCurrentControl = Screen.ActiveControl
queryName = ctlCurrentControl.Name
'Get combobox value and assign relavent values to The_Year
The_Year = Forms![Extract Data]!Extract_Year.value
'Change the year from a variant to what we need in the SQL
If The_Year Like "20*" Then
The_Year = CInt(The_Year)
MsgBox The_Year & "Data Type = " & VarType(The_Year)
Else: The_Year = "*"
MsgBox The_Year & "Data Type = " & VarType(The_Year)
End If
'Set queryYear variable
setYear (The_Year)
'Check the variable is correct
'MsgBox getYear()
'Open the Save as Dialog to choose location of query save
strFilter = ahtAddFilterItem("Excel Files (*.xlsx)", "*.xlsx")
strSaveFileName = ahtCommonFileOpenSave( _
openFile:=False, _
Filter:=strFilter, _
Flags:=ahtOFN_OVERWRITEPROMPT Or ahtOFN_READONLY)
DoCmd.TransferSpreadsheet acExport, acSpreadsheetTypeExcel12Xml, queryName, strSaveFileName
End Function
'Function to set queryYear used in data extraction queries
Public Function setYear(The_Year As Variant)
queryYear = The_Year
End Function
'Function to get queryYear used in data extraction queries
Function getYear()
getYear = queryYear
End Function
It should be noted that the file save and file open code sections are not mine. They come from Ken Getz and the whole code can be found here:
http://access.mvps.org/access/api/api0001.htm
It would be better to use the application path ( eg currentproject.Path ) or to ask the user to specify a location for the data store rather than to try to force an install at a location that may not be available to the user. There is no need at all to hard-code paths. In Access, you can store information relevant to the project in a table, including the data path. You can look up MS Access from Excel.

Cascading Combobox

Copy from: https://softwareengineering.stackexchange.com/questions/158330/cascading-comboboxes
ok so i have a form, in Access 2010, with 1 Textbox and 3 ComboBoxes (1 Enabled & 2 Disabled).
the first ComboBox is not tied to the datasource but is subjective to the other 2 comboboxes. So i handled the Click event for the first Combobox to then make the other 2 enabled, and preload the 2nd ComboBox with a custom RowSource SQL Script dynamically built based on the 1st ComboBox Value.
This all works great for New information but when i goto review the information, via Form, its back to the New mode on the controls.
Question:
What event do i need to handle to check if the current Form Data contains data for the Control Source of the Controls?
As i would express it in Logic (its a mix between C & VB, i know but should get the pt acrossed):
DataSet ds = Form.RowSet
if (ds = Null) then
cbo2.enabled = false
cbo3.enabled = false
else
cbo2.rowsource = "select id, nm from table"
cbo2.value = ds(3)
cbo3.value = ds(4)
end if
... do some other logic ...
Updated Logic - Still problem, cant catch for RecordStatus for some reason (gives 3251 Run-Time Error)
Private Sub Form_Current()
Dim boolnm As Boolean: boolnm = (IsNull(txtName.Value) Or IsEmpty(txtName.Value))
Dim booltype As Boolean: booltype = IsNull(cboType.Value)
Dim boolfamily As Boolean: boolfamily = IsNull(cboType.Value)
Dim boolsize As Boolean: boolsize = IsNull(cboType.Value)
Dim rs As DAO.Recordset: Set rs = Me.Recordset
MsgBox rs.AbsolutePosition
' If rs.RecordStatus = dbRecordNew Then
' MsgBox "New Record being inserted, but not committed yet!", vbOKOnly
' Else
' MsgBox rs(0).Name & " - " & rs(0).Value & vbCrLf & _
' rs(1).Name & " - " & rs(1).Value & vbCrLf & _
' rs(2).Name & " - " & rs(2).Value & vbCrLf & _
' rs(3).Name & " - " & rs(3).Value
' End If
'MsgBox "Name: " & CStr(boolnm) & vbCrLf & _
"Type: " & CStr(booltype) & vbCrLf & _
"Family: " & CStr(boolfamily) & vbCrLf & _
"Size: " & CStr(boolsize), vbOKOnly
End Sub
Here is the final result, with Remou's assistance, and this is only a precursor to the end result (which is out of the context of the question).
Private Sub Form_Current()
If Me.NewRecord Then <=======================
cboType.Value = 0
cboType.Enabled = True
cboFamily.Enabled = False
cboSize.Enabled = False
Else
Dim rs As DAO.Recordset: Set rs = Me.Recordset
'get Family ID
Dim fid As String: fid = rs(2).Value
'Build SQL Query to obtain Type ID
Dim sql As String
sql = "select tid from tblFamily where id = " & fid
'Create Recordset
Dim frs As DAO.Recordset
'Load SQL Script and Execute to obtain Type ID
Set frs = CurrentDb.OpenRecordset(sql, dbOpenDynaset, dbReadOnly)
'Set Type ComboBox Value to Type ID
cboType.Value = frs(0)
cboType_Click 'Simulate Click Event since the Value has changed
'Make sure all 3 Comboboxes are enabled and useable
cboType.Enabled = True
End If
End Sub

exporting code from Microsoft Access

Is there any way to bulk-export Microsoft Access code to files? I see I can export one file at a time, but there are hundreds and I'll be here all day. It there no "Export All" or multi-select export anywhere?
You can do this without having to write any code at all. From the menu, choose tools->analyze->database documenter.
This will give you a bunch of options to print out the code. You can then while viewing the report ether send it out to your PDF printer (if you have one). Or, simply print out to a text file printer. Or you can even then click on the word option in the report menu bar and the results will be sent out to word
The database documenter has provisions to print out all code, including code in forms.
So, in place of some of the suggested code examples you can do this without having to write any code at all. Do play with the additional options in the documenter. The documenter will produce HUGE volumes print out information for every single property and object in the database. So, if you don't un-check some of the options then you will easily empty a full size printer tray of paper. This documenter thus results in huge printouts.
To output all code to desktop, including code from forms and reports, you can paste this into a standard module and run it by pressing F5 or step through with F8. You may wish to fill in the name of the desktop folder first.
Sub AllCodeToDesktop()
''The reference for the FileSystemObject Object is Windows Script Host Object Model
''but it not necessary to add the reference for this procedure.
Dim fs As Object
Dim f As Object
Dim strMod As String
Dim mdl As Object
Dim i As Integer
Set fs = CreateObject("Scripting.FileSystemObject")
''Set up the file.
''SpFolder is a small function, but it would be better to fill in a
''path name instead of SpFolder(Desktop), eg "c:\users\somename\desktop"
Set f = fs.CreateTextFile(SpFolder(Desktop) & "\" _
& Replace(CurrentProject.Name, ".", "") & ".txt")
''For each component in the project ...
For Each mdl In VBE.ActiveVBProject.VBComponents
''using the count of lines ...
i = VBE.ActiveVBProject.VBComponents(mdl.Name).CodeModule.CountOfLines
''put the code in a string ...
If i > 0 Then
strMod = VBE.ActiveVBProject.VBComponents(mdl.Name).codemodule.Lines(1, i)
End If
''and then write it to a file, first marking the start with
''some equal signs and the component name.
f.writeline String(15, "=") & vbCrLf & mdl.Name _
& vbCrLf & String(15, "=") & vbCrLf & strMod
Next
''Close eveything
f.Close
Set fs = Nothing
End Sub
To get special folders, you can use the list supplied by Microsoft.
Enumerating Special Folders: http://www.microsoft.com/technet/scriptcenter/guide/sas_fil_higv.mspx?mfr=true
From: http://wiki.lessthandot.com/index.php/Code_and_Code_Windows
There is nothing in the interface to export more than one module at a time.
You can code your own "export all" equivalent easily:
Public Sub ExportModules()
Const cstrExtension As String = ".bas"
Dim objModule As Object
Dim strFolder As String
Dim strDestination As String
strFolder = CurrentProject.Path
For Each objModule In CurrentProject.AllModules
strDestination = strFolder & Chr(92) & objModule.Name & cstrExtension
Application.SaveAsText acModule, objModule.Name, strDestination
Next objModule
End Sub
Here's my version:
'============================================================'
' OutputCodeModules for Access
' Don Jewett, verion 2014.11.10
' Exports the following items from an Access database
' Modules
' Form Modules
' Report Modules
'
' Must be imported into Access database and run from there
'============================================================'
Option Explicit
Option Compare Database
Private Const KEY_MODULES As String = "Modules"
Private Const KEY_FORMS As String = "Forms"
Private Const KEY_REPORTS As String = "Reports"
Private m_bCancel As Boolean
Private m_sLogPath As String
'------------------------------------------------------------'
' >>>>>> Run this using F5 or F8 <<<<<<<<
'------------------------------------------------------------'
Public Sub OutputModuleHelper()
OutputModules
End Sub
Public Sub OutputModules(Optional ByVal sFolder As String)
Dim nCount As Long
Dim nSuccessful As Long
Dim sLine As String
Dim sMessage As String
Dim sFile As String
If sFolder = "" Then
sFolder = Left$(CurrentDb.Name, InStrRev(CurrentDb.Name, "\") - 1)
sFolder = InputBox("Enter folder for files", "Output Code", sFolder)
If sFolder = "" Then
Exit Sub
End If
End If
'normalize root path by removing trailing back-slash
If Right(sFolder, 1) = "\" Then
sFolder = Left(sFolder, Len(sFolder) - 1)
End If
'make sure this folder exists
If Not isDir(sFolder) Then
MsgBox "Folder does not exist", vbExclamation Or vbOKOnly
Exit Sub
End If
'get a new log filename
m_sLogPath = sFolder & "\_log-" & Format(Date, "yyyy-MM-dd-nn-mm-ss") & ".txt"
sLine = CurrentDb.Name
writeLog sLine
sMessage = sLine & vbCrLf
sLine = Format(Now, "yyyy-MM-dd nn:mm:ss") & vbCrLf
writeLog sLine
sMessage = sMessage & sLine & vbCrLf
'output modules
nCount = CurrentDb.Containers(KEY_MODULES).Documents.Count
nSuccessful = outputContainerModules(sFolder, KEY_MODULES)
'write to the log file and final message
sLine = nSuccessful & vbTab & "of" & vbTab & nCount & vbTab & KEY_MODULES & " exported"
writeFile m_sLogPath, sLine, True
sMessage = sMessage & vbTab & sLine & vbCrLf
'output form modules
If Not m_bCancel Then
nCount = CurrentDb.Containers(KEY_FORMS).Documents.Count
nSuccessful = outputContainerModules(sFolder, KEY_FORMS)
'write to the log file and final message
sLine = nSuccessful & vbTab & "of" & vbTab & nCount & vbTab & "Form Modules exported"
writeFile m_sLogPath, sLine, True
sMessage = sMessage & vbTab & sLine & vbCrLf
End If
'output report modules
If Not m_bCancel Then
nCount = CurrentDb.Containers(KEY_REPORTS).Documents.Count
nSuccessful = outputContainerModules(sFolder, KEY_REPORTS)
'write to the log file and final message
sLine = nSuccessful & vbTab & "of" & vbTab & nCount & vbTab & "Report Modules exported"
writeFile m_sLogPath, sLine, True
sMessage = sMessage & vbTab & sLine & vbCrLf
End If
If Len(sMessage) Then
MsgBox sMessage, vbInformation Or vbOKOnly, "OutputModules"
End If
End Sub
Private Function outputContainerModules( _
ByVal sFolder As String, _
ByVal sKey As String) As Long
Dim n As Long
Dim nCount As Long
Dim sName As String
Dim sPath As String
On Error GoTo EH
'refactored this to use reference to Documents,
'but the object reference doesn't stick around
'and I had to roll back to this which isn't as pretty.
'but this works (and if it ain't broke...)
For n = 0 To CurrentDb.Containers(sKey).Documents.Count - 1
nCount = nCount + 1
sName = CurrentDb.Containers(sKey).Documents(n).Name
Select Case sKey
Case KEY_FORMS
sName = "Form_" & sName
Case KEY_REPORTS
sName = "Report_" & sName
End Select
sPath = sFolder & "\" & sName & ".txt"
DoCmd.OutputTo acOutputModule, sName, acFormatTXT, sPath, False
Next 'n
outputContainerModules = nCount
Exit Function
EH:
nCount = nCount - 1
Select Case Err.Number
Case 2289 'can't output the module in the requested format.
'TODO: research - I think this happens when a Form/Report doesn't have a module
Resume Next
Case Else
Dim sMessage As String
writeError Err, sKey, sName, nCount
sMessage = "An Error ocurred outputting " & sKey & ": " & sName & vbCrLf & vbCrLf _
& "Number " & Err.Number & vbCrLf _
& "Description:" & Err.Description & vbCrLf & vbCrLf _
& "Click [Yes] to continue with export or [No] to stop."
If vbYes = MsgBox(sMessage, vbQuestion Or vbYesNo Or vbDefaultButton2, "Error") Then
Resume Next
Else
m_bCancel = True
outputContainerModules = nCount
End If
End Select
End Function
Private Function writeFile( _
ByVal sPath As String, _
ByRef sMessage As String, _
Optional ByVal bAppend As Boolean) As Boolean
'Dim oFSO as Object
'Dim oStream as Object
'Const ForWriting As Long = 2
'Const ForAppending As Long = 8
'Dim eFlags As Long
Dim oFSO As FileSystemObject
Dim oStream As TextStream
Dim eFlags As IOMode
On Error GoTo EH
'Set oFSO = Server.CreateObject("Scripting.FileSystemObject")
Set oFSO = New FileSystemObject
If bAppend Then
eFlags = ForAppending
Else
eFlags = ForWriting
End If
Set oStream = oFSO.OpenTextFile(sPath, eFlags, True)
oStream.WriteLine sMessage
writeFile = True
GoTo CLEAN
EH:
writeFile = False
CLEAN:
If Not oFSO Is Nothing Then
Set oFSO = Nothing
End If
If Not oStream Is Nothing Then
Set oStream = Nothing
End If
End Function
Private Sub writeError( _
ByRef oErr As ErrObject, _
ByVal sType As String, _
ByVal sName As String, _
ByVal nCount As Long)
Dim sMessage As String
sMessage = "An Error ocurred outputting " & sType & ": " & sName & " (" & nCount & ")" & vbCrLf _
& "Number " & oErr.Number & vbCrLf _
& "Description:" & oErr.Description & vbCrLf & vbCrLf
writeLog sMessage
End Sub
Private Sub writeLog( _
ByRef sMessage As String)
On Error GoTo EH
writeFile m_sLogPath, sMessage & vbCrLf, True
Exit Sub
EH:
'swallow errors?
End Sub
Private Function isDir(ByVal sPath As String) As Boolean
On Error GoTo EH
If Right$(sPath, 1) <> "\" Then
sPath = sPath & "\"
End If
If Dir$(sPath & ".", vbDirectory) = "." Then
isDir = True
ElseIf Len(sPath) = 3 Then
If Dir$(sPath, vbVolume) = Left(sPath, 1) Then
isDir = True
End If
End If
Exit Function
EH:
isDir = False
End Function