Unable to edit msgraph seriescollection - ms-access

I am pulling out my hair trying to parse data or edit into a msgraph series collection.
I get error 438 - object does not support this property or method.
I can manipulate other properties that the object has such as ChartTitle.Font.Size but not the seriescollection.
Intellisencing is not working wth this object which leads me to susspect that I have not set a particular reference.
Sections of the code is below.
The main routine gets the object:
strReportName = "Security Selection"
strChartName = "MACD_Chart"
DoCmd.OpenReport strReportName, acViewDesign
Set rptMACD = Reports(strReportName)
Set chartMACD = rptMACD(strChartName)
A data recordset is built then all of it is passed into the subroutine:
Call UpdateChart(chartMACD, rstMACD)
Public Sub UpdateChart(chartPlot As Object, rstChart As ADODB.Recordset)
'FUNCTION:
' a chart object is passed into the routine,
' source data is update to the recordset being passed in.
Dim lngType As Long
Dim i, j, iFieldCount As Integer
Dim rst As Recordset
Dim arXValues() As Date
Dim arValues() As Double
Dim strChartName, strYAxis, strXAxis As String
Dim ChrtCollection As ChartObjects
Dim colmCount As Integer
chartPlot.RowSourceType = "Table/Query"
'get number of columns in chart table/Query
iFieldCount = rstChart.Fields.Count
With chartPlot
'change chart data to arrays of data from recordset
.Activate
j = 0
rstChart.MoveFirst
Do While Not rstChart.EOF
j = j + 1
ReDim Preserve arXValues(1 To j)
arXValues(j) = rstChart.Fields("Date").Value
rstChart.MoveNext
Loop
For i = 1 To iFieldCount - 1 'Date is first field
j = 0
rstChart.MoveFirst
Do While Not rstChart.EOF 'get next array of data
j = j + 1
ReDim Preserve arValues(1 To j)
arValues(j) = rstChart.Fields(i + 1).Value
rstChart.MoveNext
Loop
.SeriesCollection(i).Name = rstChart.Fields(i + 1).Name
.SeriesCollection(1).XValues = arXValues
.SeriesCollection(i).Values = arValues
Next i
end sub
I've tried many things and now I'm totally confused. I've also been trying to parse in recordsets (which is my preference) but i'll take anything at the moment.

Before continuing: I recommend setting the Chart's Rowsource property to a query that returns the data you want and then Requerying the Chart. This is WAY easier than the following.
You are getting the Error 438 because Name, XValues, Values are not properties of the Series Object. MSDN Info
That being said, here is a go at your method and some recommendations for doing it that way. The SeriesCollection doesn't contain the values associated with MSGraph points like it does in Excel. You need to edit the data in the DataSheet, which is VERY finicky. A reference to the Microsoft Graph Library must be included. This was tested to work with my database. Microsoft Graph MSDN info
DAO
Public Sub testing()
Dim rstChart As Recordset
Dim seri As Object, fld As Field
Dim app As Graph.Chart
chartPlot.SetFocus
Set app = chartPlot.Object
Set rstChart = CurrentDb.OpenRecordset("SELECT DateTime, ASIMeasured FROM Surv_ASI WHERE CycleID = 2 ORDER BY DateTime")
app.Application.DataSheet.Range("00:AA1000").Clear
With rstChart
For Each fld In .Fields
app.Application.DataSheet.Range("a1:AA1").Cells(0, fld.OrdinalPosition) = fld.Name
Next
Do While Not .EOF
For Each fld In .Fields
app.Application.DataSheet.Range("a2:AA1000").Cells(.AbsolutePosition, fld.OrdinalPosition).Value = fld
Next
.MoveNext
Loop
End With
app.Refresh
End Sub
ADO (Assuming rstChart is already a valid ADODB.Recordset)
Public Sub testing()
Dim app As Graph.Chart, i As Integer
chartPlot.SetFocus
Set app = chartPlot.Object
app.Application.DataSheet.Range("00:AA1000").Clear
With rstChart
.MoveFirst 'Since I don't know where it was left off before this procedure.
For i = 0 To .Fields.Count - 1
app.Application.DataSheet.Range("a1:AA1").Cells(0, i) = .Fields(i).Name
Next
Do While Not .EOF
For i = 0 To .Fields.Count - 1
app.Application.DataSheet.Range("a2:AA1000").Cells(.AbsolutePosition, i).Value = .Fields(i)
Next
.MoveNext
Loop
End With
app.Refresh
End Sub
Some notes about my changes:
1. I prefer having my With point to the Recordset being cycled, instead of the Object being operated on, especially since more calls are made to the Recordset's properties in your procedure.
2. You don't need to specify the variable to which a Next applies (Next i). Just put Next.
3. Please pick my answer if it helped :)

Related

How can I get the value from a control using the name of the control source?

I am trying to write some code to audit changes made via a form. I have a function that works to do this:
Function WriteChanges()
Dim f As Form
Dim c As Control
Dim user As String
Dim db As DAO.Database
Dim cnn As ADODB.Connection
Dim MySet As ADODB.Recordset
Dim tbld As TableDef
Dim recsource As String
Set f = Screen.ActiveForm
Set db = CurrentDb
Set cnn = CurrentProject.Connection
Set MySet = New ADODB.Recordset
recsource = f.RecordSource
Set tbld = db.TableDefs(recsource)
pri_key = fFindPrimaryKeyFields(tbld)
Debug.Print "pri_key: "; pri_key
user = Environ("username")
MySet.Open "Audit", cnn, adOpenDynamic, adLockOptimistic, adCmdTable
For Each c In f.Controls
Select Case c.ControlType
Case acTextBox, acComboBox, acListBox, acOptionGroup
If c.Value <> c.OldValue Then
With MySet
.AddNew
![EditDate] = Now
![user] = user
![SourceTable] = f.RecordSource
![SourceField] = c.ControlSource
![BeforeValue] = c.OldValue
![AfterValue] = c.Value
.update
End With
End If
End Select
Next c
MySet.Close
Set MySet = Nothing
Set f = Nothing
Set db = Nothing
End Function
I use this function on the before update property of various forms and it populates the Audit table with the details of the changes to values in each of the controls. I need to also get the value from the primary key field to add to the Audit table. I can use the following code to identify the name of the primary key within the form's record source:
Function fFindPrimaryKeyFields(tdf As TableDef) As String
Dim idx As Index
On Error GoTo HandleIt
For Each idx In tdf.Indexes
If idx.Primary Then
fFindPrimaryKeyFields = Replace(idx.Fields, "+", "")
GoTo OutHere
End If
Next idx
OutHere:
Set idx = Nothing
Exit Function
HandleIt:
Select Case Err
Case 0
Resume Next
Case Else
Beep
MsgBox Err & " " & Err.Description, vbCritical + vbOKOnly, "Error"
fFindPrimaryKeyFields = vbNullString
Resume OutHere
End Select
End Function
How can I use this to get the value from the control (text box) that has the identified primary key as its control source.
Please forgive any silly errors in my code as I'm a relative novice. Thanks in advance for any help.
I'm not 100% sure what you want exactly, but if you have the name of the field, you can use the following:
Dim primaryKeyValue As Variant
Dim primaryKeyColumnName As String
primaryKeyColumnName = fFindPrimaryKeyFields(TableDefs!MyTable)
Dim f as Form
'Get the form somehow
Dim c As Control
On Error GoTo NextC 'Escape errors because lots of controls don't have a control source
For Each c In f.Controls
If c.ControlSource = primaryKeyColumnName Then
primaryKeyValue = c.Value
End If
NextC:
Next c
On Error GoTo 0
If the primary key column is part of the form record source, you can simply read it by:
Debug.Print "PK value: " & f(pri_key)
Every column of the record source is a form property at runtime, independent of whether there is a control with the same name.
Note: your whole construct will stop working if you have a form that is based on a query that joins multiple tables.

Error in getting Table from VBA recordset

I am using a mySql server connection to get table data into excel. I have a total of three queries, two of which work perfectly and are copied correctly from copyFromRecordSet. However, the third query does not work correctly when I use copyFromRecordset. It gets two of the columns I want, but leaves off the next five. The query works correctly when I use it in a database GUI so that is not the issue.
I am trying to use an alternative to copyFromRecordSet, a piece of code which I altered from https://support.microsoft.com/en-us/help/246335/how-to-transfer-data-from-an-ado-recordset-to-excel-with-automation.
'Open and copy the recordset to an array to allow for copying into worksheet
RS.Open PriceChangeQuery
recArray = RS.GetRows
recCount = UBound(recArray, 2) + 1 '+1 since the array is zero-based
fldCount = RS.Fields.Count
' Check the array for contents that are not valid when
' copying the array to an Excel worksheet
For iCol = 0 To fldCount - 1
For iRow = 0 To recCount - 1
' Take care of Date fields
If IsDate(recArray(iCol, iRow)) Then
recArray(iCol, iRow) = Format(recArray(iCol, iRow))
' Take care of OLE object fields or array fields
ElseIf IsArray(recArray(iCol, iRow)) Then
recArray(iCol, iRow) = "Array Field"
End If
Next iRow 'next record
Next iCol 'next field
'Transpose and copy the array to the worksheet,
'starting in cell A2
CompareFile.Sheets("VendorFilteredPriceChangeReport").Cells(2, 1).Resize(recCount, fldCount).Value = TransposeDim(recArray)
'CompareFile.Sheets("VendorFilteredPriceChangeReport").Range("A2").CopyFromRecordset RS
'Close ADO objects
RS.Close
And this is the TransposeDim function.
Function TransposeDim(v As Variant) As Variant
' Custom Function to Transpose a 0-based array (v)
Dim X As Long, Y As Long, Xupper As Long, Yupper As Long
Dim tempArray As Variant
Xupper = UBound(v, 2)
Yupper = UBound(v, 1)
ReDim tempArray(Xupper, Yupper)
For X = 0 To Xupper
For Y = 0 To Yupper
tempArray(X, Y) = v(Y, X)
Next Y
Next X
TransposeDim = tempArray
End Function
However, when I run this piece of code the query is again leaving off the last five columns.
Any insights as to how to fix this piece of code or insights as to why copyFromRecordSet would be behaving strangely would be appreciated
In order to access some records properly, a recordSet's cursor must be set to client side. I was able to do this by using:
RS.CursorLocation = adUseClient in my code, right after opening the recordset using my query. I was then able to copy the data from the recordset using only CompareFile.Sheets("VendorFilteredPriceChangeReport").Range("A2").CopyFromRecordset RS and I got the correct data in my workbook.

Extracting Tables From Email, innerHTML err 91

have been googling around for a code to extract tables from emails and am trying to adapt the codes by changing early binding to late binding.
However, the code seems to bug out at the objHTML.body.innerHTML = objMailItem.HTMLBody line.
Code seems to run alright when used in Excel but bugs out when I run on outlook vba.
any help to point me in the right direction would be appreciated!
Public Function ExtractOutlookTables(objMailItem As Object) As Object
Dim vTable As Variant
Dim objHTML As Object: Set objHTML = CreateObject("htmlFile")
Dim objEleCol As Object
objHTML.Body.innerHTML = objMailItem.HTMLBody ' <<error line>>
With objHTML
objHTML.Body.innerHTML = objMailItem.HTMLBody
Set objEleCol = .getElementsByTagName("table")
End With
'import in Excel
Dim x As Long, y As Long
For x = 0 To objEleCol(0).Rows.Length - 1
For y = 0 To objEleCol(0).Rows(x).Cells.Length - 1
vTable(x, y) = objEleCol(0).Rows(x).Cells(y).innerText
Next y
Next x
ErrorHandler:
Set objHTML = Nothing: Set objEleCol = Nothing
End Function
''
' Function that returns a dictionary of arrays of strings, each representing a table in the email; key = 0 represents the most recent table
' #param objMailItem object representing an Outlook Mail Item object
' #return Dictionary of arrays of strings where each key represents the index of the table (0 being the most recent table)
' #remarks Please note that index 0 = table in the most recent email conversation
' #see none
Public Function fnc_ExtractTablesFromMailItem(objMailItem As Object) As Object
Dim objHTMLDoc As Object: Set objHTMLDoc = CreateObject("HTMLFile")
Dim dicTables As Object: Set dicTables = CreateObject("scripting.Dictionary")
Dim arrTable() As String
Dim objTable As Object
Dim lngRow As Long
Dim lngCol As Long
Dim intCounter As Integer: intCounter = 0
objHTMLDoc.body.innerHTML = objMailItem.htmlbody
' Loop through each table in email
For Each objTable In objHTMLDoc.getElementsByTagName("table")
ReDim arrTable(objTable.Rows.Length - 1, objTable.Rows(1).Cells.Length - 1)
For lngRow = 0 To objTable.Rows.Length - 1
Set rw = objTable.Rows(lngRow)
For lngCol = 0 To rw.Cells.Length - 1
' Ignore any problems with merged cells etc
On Error Resume Next
arrTable(lngRow, lngCol) = rw.Cells(lngCol).innerText ' Store each table in 1 array
On Error GoTo 0
Next lngCol
Next lngRow
dicTables(intCounter) = arrTable ' Store each array as a dictionary item
intCounter = intCounter + 1
Next objTable
Set fnc_ExtractTablesFromMailItem = dicTables
' Garbage collection
Set dicTables = Nothing: Set objTable = Nothing: Set objHTMLDoc = Nothing
End Function
The problem seems to be in the code that is calling the function. You should post that code.
If the only thing that you actual want from objMailItem is it's HTMLBody then objMailItem As Object should be removed from function signature should and replaced with HTMLBody as String.
You must be missing a couple of lines of code; because vTablewas never allocated and will throw a type mismatch error the way the function is written.
You should also wrap your test whether objEleCol is Nothing before you try and use it.
Here I pass the MailItem to fnc_ExtractTablesFromMailItem from Application_ItemSend to in Outlook. There are no errors.
The Application_NewMail and Application_NewMailEx events do not recieve MailItems as parameters. How are you retrieving the MailItem that you are passing into your function?

Type mismatch when comparing two variants, why?

I have written a function that’s sole purpose is to loop through all forms in a continuous form, grab the names from an "Owner" field, and then create a collection out of them which only contains unique values (no repeated names).
The code below is my current code, I realize that this may seems to be a roundabout way to do what I want but some unforeseen issues prevent me from doing this the way I would like to. So while I realize the code isn't super effective (and is very rough coding) I want to finish this path if only for a learning experience. This line of code always gives me a type mismatch error message. I have used a break line to see what those variables are in the local window, they both contain a string which should be the same therefore should return true. I can't seem to find a way to make that comparison actually work.
ElseIf var = o Then
The code (heavy commenting to make sure I am clear):
Private Sub Command39_Click()
Dim intRecordCount As Integer
Dim rs As DAO.Recordset
Dim colNames As Collection
Set colNames = New Collection
Set rs = Me.RecordsetClone
intRecordCount = rs.RecordCount
DoCmd.GoToRecord , , acFirst
If intRecordCount > 0 Then
Dim thisCol As Collection
Set thisCol = New Collection
'For each record on the form
Do While Not rs.EOF
Dim str As String
Dim o As Variant
str = Me.txtOwners.Value & ""
'If the textbox isn't empty
If Len(str) > 0 Then
'Send the string containing names ("Bob, Cheryl, Jeff, Tim")
Set thisCol = SplitNames(str)
'Loop through all of the names found
For Each o In thisCol
Dim var As Variant
Dim blnFound As Boolean
'Loop through all names in the main collection
For Each var In colNames
'If the collection is empty simply add the first name
If colNames.Count = 0 Then
blnFound = False
'If the collection has items check each one to see if the name is already in the collection
'This line is where the problem lies, I can't find anyway to compare var to o
ElseIf var = o Then
blnFound = True
End If
Next var
'If the name was not found in the collection add it
If Not blnFound Then
colNames.Add (o)
End If
Next o
End If
'Go to the next record in the continuous
DoCmd.GoToRecord , , acNext
rs.MoveNext
Loop
End If
End Sub
'Accepts the name of the owners to be split
Public Function SplitNames(strNames As String) As Collection
Dim colNames As Collection
Dim strThisName As String
Set colNames = New Collection
'Replaces ("Bob, Cheryl, Jeff, Tim") with ("Bob Cheryl Jeff Tim")
'I realize this isn't really needed simply my OCD requires I do
strNames = Trim(Replace(strNames, ", ", " "))
'Create the collection of names
colNames.Add (Split(strNames, " "))
'Send back the collection
Set SplitNames = colNames
End Function
Update - For some reason I need to access the var string propery by using var(0) so it seems like somehow var became its own array?
Here's an example of modifying your SplitNames function to a Dictionary object.
WHile there is an Exists method which you may make use of elsehwere in your code, you need not use that to ensure uniqueness. Merely referring to a Key will create it, so you can create a new key (or overwrite it if it exists) using the same method:
dict(key) = value
Note that this overwrites the value portion of the Key/Value pair. But since your SplitNames function is merely building the "list" of unique names, I don't think that will be an issue. For the sake of example, I simply assign nullstring to each value.
I added an optional parameter to this function to allow you to return either a Dictionary of unique names, or a Collection (converted from the Dictionary). Untested, but I think it should work. Let me know if you have any trouble with it.
Public Function SplitNames(strNames As String, Optional returnCollection as Boolean=False) As Object
'returns a Dictionary of unique names, _
' or a Collection of unique names if optional returnCollection=True
Dim dictNames as Object
Dim strThisName As Variant
Dim coll as Collection
Set dictNames = CreateObject("Scripting.Dictionary")
'Replaces ("Bob, Cheryl, Jeff, Tim") with ("Bob Cheryl Jeff Tim")
'I realize this isn't really needed simply my OCD requires I do
strNames = Trim(Replace(strNames, ", ", " "))
'Create the collection of names
For Each strThisName in Split(strNames, " ")
dictNames(strThisName) = ""
Next
If Not returnCollection Then
Set SplitNames = dictNames
Else
Set coll = New Collection
For each strThisName in dictNames.Keys()
coll.Add strThisName
Next
Set SplitNames = coll
End If
End Function
So I think you can reduce your procedure like so:
Private Sub Command39_Click()
Dim intRecordCount As Integer
Dim rs As DAO.Recordset
Dim dictNames As Object
Dim collNames as Collection
Dim str As String
Dim o As Variant
Set rs = Me.RecordsetClone
intRecordCount = rs.RecordCount
DoCmd.GoToRecord , , acFirst
rs.MoveFirst
If intRecordCount > 0 Then
'For each record on the form
Do While Not rs.EOF
str = Me.Controls("Text27").Value & ""
'If the textbox isn't empty
If Len(str) > 0 Then
'Send the string containing names ("Bob, Cheryl, Jeff, Tim")
Set dictNames = SplitNames(str)
'Alternatively, if you want to work with the Collection instead:
Set collNames = SplitNames(str, True)
End If
Loop
End If
End Sub
The following is the updated code that works for what I need it to do. I was adding a string array (being created by the Split() function) which was what I was adding instead of the string value itself.
Private Sub Command39_Click()
Dim intRecordCount As Integer
Dim rs As DAO.Recordset
Dim dictNames As New Collection
Set rs = Me.RecordsetClone
intRecordCount = rs.RecordCount
DoCmd.GoToRecord , , acFirst
rs.MoveFirst
If intRecordCount > 0 Then
Dim dictTheseNames As New Collection
'For each record on the form
Do While Not rs.EOF
Dim str As String
Dim o As Variant
str = Me.Controls("Text27").Value & ""
'If the textbox isn't empty
If Len(str) > 0 Then
'Send the string containing names ("Bob, Cheryl, Jeff, Tim")
Set dictTheseNames = SplitNames(str)
'Loop through all of the names found
For Each o In dictTheseNames
Dim var As Variant
Dim blnFound As Boolean
blnFound = False
'Loop through all names in the main collection
For Each var In dictNames
'If the collection is empty simply add the first name
If dictNames.Count = 0 Then
dictNames.Add (o)
'If the collection has items check each one to see if the name is already in the collection
'This line is where the problem lies, I can't find anyway to compare var to o
ElseIf o = var Then
blnFound = True
End If
Next var
'If the name was not found in the collection add it
If Not blnFound Then
dictNames.Add (o)
End If
Next o
End If
'Go to the next record in the continuous
rs.MoveNext
If (rs.RecordCount - rs.AbsolutePosition) > 2 Then
DoCmd.GoToRecord , , acNext
End If
Loop
End If
End Sub
'Accepts the name of the owners to be split
Public Function SplitNames(strNames As String) As Collection
Dim dictNames As New Collection
Dim strThisName As String
Dim strArray() As String
Set dictNames = New Collection
'Replaces ("Bob, Cheryl, Jeff, Tim") with ("Bob Cheryl Jeff Tim")
'I realize this isn't really needed simply my OCD requires I do
strNames = Trim(Replace(strNames, ", ", " "))
'Create the array of names
strArray = Split(strNames, " ")
Dim o As Variant
For Each o In strArray
dictNames.Add (o)
Next o
'Send back the collection
Set SplitNames = dictNames
End Function

errors when exporting database to other computers

I have created a data base that comes in an installer that runs as an epos system.
On installing it on other computers, I get a large number of errors all saying that something is missing. the file runs perfectly on my computer, but the errors stop anything from working on other computers....
the errors are as follows. each has its own popup box.
broken reference to excel.exe version 1.7 or missing.
acwztool.accde missing
npctrl.dll v4.1 missing
contactpicker.dll v1.0 missing
cddbcontolwinamp.dll v1.0 missing
cddbmusicidwinamp.dll v1.0 missing
colleagueimport.dll v1.0 missing
srstsh64.dll missing
I feel like this may because I altered the module vba library referencing so that I could run a vba code that uses excel, unfortunatly i have forgotten which librarys i have added
if it helps, the code that I added which required new references is below
Public Sub SalesImage_Click()
Dim rst As ADODB.Recordset
' Excel object variables
Dim xlApp As Excel.Application
Dim xlBook As Excel.Workbook
Dim xlSheet As Excel.Worksheet
Dim xlChart As Excel.Chart
Dim i As Integer
On Error GoTo HandleErr
' excel aplication created
Set xlApp = New Excel.Application
' workbook created
Set xlBook = xlApp.Workbooks.Add
' set so only one worksheet exists
xlApp.DisplayAlerts = False
For i = xlBook.Worksheets.Count To 2 Step -1
xlBook.Worksheets(i).Delete
Next i
xlApp.DisplayAlerts = True
' reference the first worksheet
Set xlSheet = xlBook.ActiveSheet
' naming the worksheet
xlSheet.name = conSheetName
' recordset creation
Set rst = New ADODB.Recordset
rst.Open _
Source:=conQuery, _
ActiveConnection:=CurrentProject.Connection
With xlSheet
' the field names are imported into excel and bolded
With .Cells(1, 1)
.Value = rst.Fields(0).name
.Font.Bold = True
End With
With .Cells(1, 2)
.Value = rst.Fields(1).name
.Font.Bold = True
End With
' Copy all the data from the recordset into the spreadsheet.
.Range("A2").CopyFromRecordset rst
' Format the data the numbering system has been extended to encompas up to 9,999,999 sales to cover all posibilities of sales since the last stock take
.Columns(1).AutoFit
With .Columns(2)
.NumberFormat = "#,###,###"
.AutoFit
End With
End With
' Create the chart.
Set xlChart = xlApp.Charts.Add
With xlChart
.ChartType = xl3DBarClustered
.SetSourceData xlSheet.Cells(1, 1).CurrentRegion
.PlotBy = xlColumns
.Location _
Where:=xlLocationAsObject, _
name:=conSheetName
End With
'the reference must be regotten as it is lost
With xlBook.ActiveChart
.HasTitle = True
.HasLegend = False
With .ChartTitle
.Characters.Text = conSheetName & " Chart"
.Font.Size = 16
.Shadow = True
.Border.LineStyle = xlSolid
End With
With .ChartGroups(1)
.GapWidth = 20
.VaryByCategories = True
End With
.Axes(xlCategory).TickLabels.Font.Size = 8
.Axes(xlCategoryScale).TickLabels.Font.Size = 8
End With
With xlBook.ActiveChart
.Axes(xlCategory, xlPrimary).HasTitle = True
.Axes(xlCategory, xlPrimary).AxisTitle.Characters.Text = "Product"
.Axes(xlValue, xlPrimary).HasTitle = True
.Axes(xlValue, xlPrimary).AxisTitle.Characters.Text = "Sales"
End With
'format the size and possition of the chart
With xlBook.ActiveChart
.Parent.Width = 800
.Parent.Height = 550
.Parent.Left = 0
.Parent.Top = 0
End With
'this displays the chart in excel. excel must be closed by the user to return to the till system
xlApp.Visible = True
ExitHere:
On Error Resume Next
'this cleans the excel file
rst.Close
Set rst = Nothing
Set xlSheet = Nothing
Set xlBook = Nothing
Set xlApp = Nothing
Exit Sub
HandleErr:
MsgBox Err & ": " & Err.Description, , "There has been an error!"
Resume ExitHere
End Sub
Deployment should be less troublesome if you remove your project's Excel reference and use late binding for Excel objects.
A downside is you lose the benefit of Intellisense during development with late binding. However it's very easy to switch between early binding during development and late binding for production. Simply change the value of a compiler constant.
In the module's Declarations section ...
#Const DevStatus = "PROD" 'PROD or DEV
Then within the body of a procedure ...
#If DevStatus = "DEV" Then
Dim xlApp As Excel.Application
Dim xlBook As Excel.Workbook
Dim xlSheet As Excel.Worksheet
Set xlApp = New Excel.Application
#Else ' assume PROD (actually anything other than DEV)
Dim xlApp As Object
Dim xlBook As Object
Dim xlSheet As Object
Set xlApp = CreateObject("Excel.Application")
#End If
With late binding your code will need to use the values of Excel constants rather than the constants names. Or you can define the named constants in the #Else block for production use then continue to use them by name in your code.
I don't know what all those other reference are. Suggest you take a copy of your project, remove all those references and see what happens when you run Debug->Compile from the VB Editor's main menu. Leave any unneeded references unchecked. And try late binding for the rest. I use only 3 references in production versions of Access applications: VBA; Access; and DAO.