Excel Reports generated by Microsoft Access routine gets Error 1004: Method Open Object Workbooks Failed
Asked Answered
U

2

7

I have several Excel reports reports that are launched on demand by buttons on a MS Access database application. The routine that launches these reports has worked fine for years with no issues, until last week when our share drive hit storage capacity.

Please note, I use a convention of a ready-made Excel Workbook that has most of the formatting to produce the final report, and adding the data to it by using VBA with the Excel Object library to build my final report. I call these "Templates" not to be associated in anyway with Microsoft Word template conventions. To avoid confusion, I will mark my reference to this convention throughout this description as Template***

The errors have become significantly less frequent since share drive space was freed up by the IT team here, but for about 30% of users, the following error is still returned when launching an excel download: "Error 1004: Method Open Object Workbooks Failed".
The line of code where the error hits has never had issues before:

Set WB = xlApp.Workbooks.Open(strPathToTemplate)

Where strPathToTemplate is the share drive path where the excel Template*** is saved.

After many calls with our IT, one help desk person applied the following solution: Navigate to ,locate a Microsoft Macro-Enabled Word Template file titled "Normal.dotm" and rename it to "Old.Normal.dotm". This IMMEDIATELY restored the functionality of the excel report downloads from the dashboard. The help desk person couldn't/wouldn't explain how they knew this was the issue or why it affected the excel downloads. The problem now is that although this solution works for every user I've applied it to, it's also temporary. Every time the user reboots, the normal.dotm file restores itself and has to be renamed again or the 1004 error will appear in the dashboard again.

I've called back to the help desk and haven't gotten any farther with an explanation or a more permanent solution.

My biggest question (aside from how to permanently solve this) is why does this MS Word normal.dotm file have any affect at all on excel files launched from the MS Access database? There are zero instances in the programming where we refer to this roaming templates file path and we don't use Word at all. I can find plenty online about how the normal.dotm file can cause problems in Word, but nothing on how it can affect other Microsoft applications other than Word.

Again, the convention I use to produce my Excel reports even though I call them Template*** has nothing to do with normal.dotm. I can't help but think that this IT help desk introduced a different problem.

Things I've tried:
1. Freeing more share drive space
2. Deleting all instances of temp files from the share drive
3. Compact and Repair on Access
4. using new excel Template*** files
5. Rewriting paths of excel Template***
6. ensuring there are no personal macros in MS word
7. Rewriting the procedure that creates the excel reports to do early binding instead of late binding
8. Rebooting several times on different computers to prove that restoration of the normal.dotm file is what causes the errors to return in the dashboard
9. Testing the dotm file renaming solution on other users' computers.

I provide as much of the vba code that may be in question below

Here is the main vba for the launch of our Status of Funds report where I use a formatted Excel workbook Template*** to produce the report by 'marrying' it to the data.

Sub CreateSOFRpt(strPathtoTemplate As String, bEOM As Boolean)

Dim strWHERE As String
Dim strSQL As String
Dim strSQL1 As String
Dim strSQL2 As String
Dim strSavePath As String
strSavePath = Environ$("UserProfile") & "\Documents\Status of Funds as of " & datestring & ".xlsm"

'This first part of the IF statement is launched only when bEOM (end of month reports) = true and if the user chooses to launch the reports.
'There are no data restrictions here because the only people who can launch end of month are the Comptroller's personnel

    If bEOM = True Then

        strSQL = "SELECT * FROM tbl_SOF_TRUECOMM IN '" & SharedRoot & "\02_Engines\SABRS.accdb';"
        strSQL1 = "SELECT * FROM tbl_SOF_TRUECOMM IN '" & SharedRoot & "\02_Engines\1EXP_YR\SABRS.accdb';"
        strSQL2 = "SELECT * FROM tbl_SOF_TRUECOMM IN '" & SharedRoot & "\02_Engines\2EXP_YR\SABRS.accdb';"

                    Call CreateExcel("Status of Funds_EndofMonth", strSavePath, strSQL, strPathtoTemplate, "PivotTable1", "MainCurrent", "Raw", _
                    "Raw1", "PivotTable2", "Main1EXP", strSQL1, "Raw2", "PivotTable3", "Main2EXP", strSQL2)
Else


                                strWHERE = GetBEA(AcquireUser)

    Select Case strWHERE

                                Case "ALL"

                                     strSQL = "SELECT VAL([FY FULL]) AS [FY FULL_], MRI, ARI, SRI, WCI, BEA, BESA, BSYM, SBHD, [FUND FUNC], BLI, [DIR BEA BESA RCVD BAL ITD AMT], " _
                                           & "[TrueComm], [OBL ITD AMT], [EXP ITD AMT], [LIQ ITD AMT], [UNCMT AMT], [UNOBL AMT], WCI_Desc, Organization " _
                                           & "FROM tbl_SOF_TrueComm;" 


                                Case "ZZ"

                                    MsgBox "Please see Admin to get access to section you are responsible for.", vbInformation, "Permission required"
                                    Exit Sub

                                Case Else

                                            strSQL = "SELECT VAL([FY FULL]) AS [FY FULL_], MRI, ARI, SRI, WCI, BEA, BESA, BSYM, SBHD, [FUND FUNC], BLI, [DIR BEA BESA RCVD BAL ITD AMT], " _
                                           & "[TrueComm], [OBL ITD AMT], [EXP ITD AMT], [LIQ ITD AMT], [UNCMT AMT], [UNOBL AMT], WCI_Desc, Organization " _
                                           & "FROM tbl_SOF_TrueComm " _
                                           & "WHERE BEA " & strWHERE & ";"

                                End Select

                                Call CreateExcel("Status of Funds", strSavePath, strSQL, strPathtoTemplate, "PivotTable1", "Main", "Raw")
End If



End Sub

Here is the CreateExcel routine referred to above

Sub CreateExcel(strRptTitle As String, strSavePath As String, Optional strQueryName As String, Optional strPathtoTemplate As String, Optional strPivotName As String, Optional strSheetName As String, Optional strRawSheetName As String, _
                                Optional strRawSheetName1 As String, Optional strPivotName1 As String, Optional strSheetName1 As String, Optional strQueryname1 As String, _
                                Optional strRawSheetName2 As String, Optional strPivotName2 As String, Optional strSheetName2 As String, Optional strQueryname2 As String)

'strQueryName = the query the raw data is sourced from
'strRptTitle = the name of the file after it is generated
'strPathtoTemplate = the directions to the template file for the excel
'strSavePath = the final save location of the completed excel file
'strPivotName = the title of the pivot table to refresh
'strSheetname = the title of the sheet where the pivot is

'any optional variable ending in a number (e.g, strSheetName2) refers to when an excel needs to be created with multiple raw data sheets and pivot tables.
'It allows the routine to expand and be more flexible when necessary


'this routine was originally just used to add excel files to KPI emails, now we call it from Form Choose and use it to generate email reports

Dim xlApp As Object
Dim WB As Object
Dim xlSheet As Object
Dim xlSheet1 As Object
Dim intCOL As Integer
Dim rs As DAO.Recordset
Dim fld As Variant
Dim db As DAO.Database
Dim pt As PivotTable

Set db = CurrentDb
Set xlApp = CreateObject("Excel.Application")
Set WB = xlApp.Workbooks.Open(strPathtoTemplate)

xlApp.Visible = False

'Generates the initial sheet, query, etc
                Set xlSheet = WB.Sheets(strRawSheetName)
                Set rs = db.OpenRecordset(strQueryName)

                'PLACE
                intCOL = 1
                For Each fld In rs.Fields
                                        xlSheet.Cells(1, intCOL).Value = fld.Name
                                            intCOL = intCOL + 1
                                            Next
                With xlSheet
                .Rows("2:" & xlSheet.Rows.Count).ClearContents
                .Range("A2").CopyFromRecordset rs
                .Cells.EntireColumn.AutoFit
                End With
                Set xlSheet = WB.Sheets(strSheetName)
                       'we could set the template to refresh on opening, but it won't refresh if someone uses outlook previewer. Better to make the excel file refresh before it ever gets sent.
                        Set pt = xlSheet.PivotTables(strPivotName)
                        pt.RefreshTable

'If a second sheet and query needs to be created, then:
'The first part of this If statement checks to see if the optional variable has been provided
'If it hasn't been provided (denoted by whether strRawSheetName1 is = to nothing) then do nothing because the place it's called from doesn't require a second sheet
'If it has been provided, then place the raw data from the query and autofit everything

    If strRawSheetName1 = "" Then
    Else
            Set xlSheet = WB.Sheets(strRawSheetName1)
                Set rs = db.OpenRecordset(strQueryname1)
                'PLACE
                intCOL = 1
                For Each fld In rs.Fields
                                        xlSheet.Cells(1, intCOL).Value = fld.Name
                                            intCOL = intCOL + 1
                                            Next
                With xlSheet
                .Rows("2:" & xlSheet.Rows.Count).ClearContents
                .Range("A2").CopyFromRecordset rs
                .Cells.EntireColumn.AutoFit
                End With

                Set xlSheet = WB.Sheets(strSheetName1)
                       'we could set the template to refresh on opening, but it won't refresh if someone uses outlook previewer. Better to make the excel file refresh before it ever gets sent.
                        Set pt = xlSheet.PivotTables(strPivotName1)
                        pt.RefreshTable
    End If

'If a third sheet and query needs to be created, then:

    If strRawSheetName2 = "" Then
    Else
            Set xlSheet = WB.Sheets(strRawSheetName2)
                Set rs = db.OpenRecordset(strQueryname2)
                'PLACE
                intCOL = 1
                For Each fld In rs.Fields
                                        xlSheet.Cells(1, intCOL).Value = fld.Name
                                            intCOL = intCOL + 1
                                            Next
                With xlSheet
                .Rows("2:" & xlSheet.Rows.Count).ClearContents
                .Range("A2").CopyFromRecordset rs
                .Cells.EntireColumn.AutoFit
                End With

                Set xlSheet = WB.Sheets(strSheetName2)
                       'we could set the template to refresh on opening, but it won't refresh if someone uses outlook previewer. Better to make the excel file refresh before it ever gets sent.
                        Set pt = xlSheet.PivotTables(strPivotName2)
                        pt.RefreshTable
    End If



'cleanup

        WB.SaveCopyAs strSavePath
        WB.Close SaveChanges:=False

Set xlSheet = Nothing
Set pt = Nothing
Set rs = Nothing
Set WB = Nothing
Set xlApp = Nothing
Set db = Nothing

End Sub
Urania answered 15/12, 2019 at 12:6 Comment(13)
A note about the renaming/restoration of Normal.dotm: If the template renaming is not "holding" when the user restarts this means that files are being downloaded from a central storage. This is not something Word will do on its own. Possibly, the issue has something to do with that. I don't know what, just offering "another piece of the puzzle". Possibly, there's a connection to that central storage that renaming the template is "breaking"? And that's helping with what you're doing? Are you able to test copying the Excel templates to a local drive and accessing them from there?Elated
Why using Excel to generate a 'report' as opposed to Access report object? To pivot data? Almost certainly a method could be utilized within Access to produce the same output.Callas
Please refrain from suggesting a redesign. Other than this new introduced problem from the network, there have been no problems. Our client prefers to work with an Excel report. There is also no VBA in the Workbook. Yes, we can output an access report, but they will usually try to export it as an Excel anyway.Urania
strPathToTemplate is passed as a parameter to CreateSOFReport. How is its value calculated? Is it the correct value even when you see the failure message?Know
Like this CreateSOFRpt(TemplatePath & "\Status of Funds Desc.xlsm") 'TemplatePath' is an environment constant that can be changed as needed. But after reading Cindy's comment, I decided to try copying the file to the users computer first and then calling the template*** locally.Urania
I use "templates" very often, and in a network environment with Excel and Access. It always works for me... but I never use .Open(strPathtoTemplate) when the "template" is somewhere else but rather I copy the template to the user's local drive, open and process that copy locally, save, and then move it to the destination location. Often it is also faster than the other way.Civilize
...And, when in a network world, I always have a bit of code to make sure the file is copied and can be opened successfully (Do..Loop, On Error..., and timer) before "processing" it: there are always random network-related timing problems, unavoidably so... Maybe this will help to make it reliably work for you. As for the "Normal.dotm", you can rename it (if present) at the top of the Sub CreateSOFRpt(), run your report creation and then, at the end of the sub rename it back to the original name--this way it is not a temporary but a built-in (a permanent) solution (a band-aid really).Civilize
Could there be something about Normal.dotm that moves with a user profile? Perhaps another piece to this puzzle: I thought I had one user with consistently no errors - but he just came up to my desk a minute ago and said now he has the error. I don't know what's changed---I didn't adjust anything at all about this computer. His copy of the front end is the same one he had yesterday. All I did was login to his computer with my CAC. I'm not sure if there's anyone else who hasn't experienced it at all.Urania
Can you please mention the version of Excel, the OS and the storage setup. It seems that the files are stored and run off a network drive and given the random nature of the error it may well be a network connectivity/performance issue. Newer versions of Excel and Access have become somewhat more resilient to these issues and copy files over to temp locations before trying to open them. To check if this is an issue, try setting up a long running ping from the host computers facing the issue to the target computer. Note any correlation between dropped packets/latency with the error.Menam
Excel Version: Microsoft Office Professional Plus 2016 2016 MSO (16.0.4549.1000) 32-bit Windows : Microsoft Windows 10 Enterprise Version: 10.0.17134 Build 17134 System type x64-based PC I also get this error multiple times in the event viewer: "Faulting application name MSACCESS.EXE version 16.0.4711.1000, faulting module name VBE7.DLL, version 7.1.10.56" Visual Basic Library version according to the properties of the file: VBE7.DLL 7.1.10.56 ________________________________________Urania
Sounds like the file has a corruption, try making a new doc and import everything back in. See if that resolves it.Leonaleonanie
Can you bring back an older version of the Acccess DB and Excel template files from before the drive filled up and test if those work? (I'm thinking that something bizarre may have happened to your files during this time)Impose
"If Normal.dotm is renamed, damaged, or moved, Word automatically creates a new version (which uses the original default settings) the next time that you start Word. The new version will not include any of the customizations that you made to the version that you renamed or moved." support.microsoft.com/en-us/office/…Cothurnus
V
1

(Sorry if my idea is stupid).

May-be is it related to a recent update of Windows or Office, so that the variable "strPathToTemplate" would become an internal or system variable name (for MS Word specificly), generating ambiguity with "Open" objet. Could you test just changing the name of that variable ?

(In fact, I hope this will not be the solution...).

Pierre.

Volar answered 23/12, 2019 at 12:21 Comment(0)
C
0

I had similar issue and since than I use this snipped to open Excel (note the comma in GetObject):

'Start Excel
On Error Resume Next
Set oExcel = GetObject(, "Excel.Application")    'Bind to existing instance of Excel

If Err.Number <> 0 Then    'Could not get instance of Excel, so create a new one
    Err.Clear
    On Error GoTo Error_Handler
    Set oExcel = CreateObject("Excel.Application")
    bExcelOpened = False
Else    'Excel was already running
    bExcelOpened = True
End If
On Error GoTo Error_Handler
Chorister answered 19/12, 2019 at 14:1 Comment(2)
@Valdo There is no need to be checking for a running Excel app. Just create a new instance of Excel in the first place, regardless of whether there are running instances of Excel application present. I do it quite often, esp. if I want to isolate a specific workbook form whatever else might be happening with Excel at the moment. Also, this will always work (or you have a general problem with MS Office/Windows) so there is no need for error checking either... And so we are back to a single line of code Set oExcel = CreateObject("Excel.Application"), after all.Civilize
@Valdo, can you please describe your "similar" issue? as @Gene points out the use of CreateObject("Excel.Application"). We are doing the same, but our problem with the error 1004 persists.Urania

© 2022 - 2024 — McMap. All rights reserved.