6

When automating other MS-Office applications with excel, I frequently get ok-only prompts saying that Microsoft Excel is waiting for another application to complete an OLE action.

This only happens when automating lengthy tasks.

How can I deal with this in an appropriate fashion?

Two recent examples (I recon the code is less important):

  • creating an accdb-Database from Excel with an Access.Application and populating it by running rather complex SQL-queries on large amount of data.

    Public Function createDB(pathDB As String, pathSQL As String) As String
    
        Dim dbs As DAO.Database
        Dim sql As String
        Dim statement As Variant, file As Variant
    
        Dim sErr As String, iErr As Integer
    
        With New Access.Application
    
            With .DBEngine.CreateDatabase(pathDB, dbLangGeneral)
    
                For Each file In Split(pathSQL, ";")
    
                    sql = fetchSQL(file)
                    For Each statement In Split(sql, ";" & vbNewLine)
                        If Len(statement) < 5 Then GoTo skpStatement
                        Debug.Print statement
    
                        On Error Resume Next
                        .Execute statement, dbFailOnError
    
                        With Err
                            If .Number <> 0 Then
                                iErr = iErr + 1
                                sErr = sErr & vbCrLf & "Error " & .Number & " | " & Replace(.Description, vbCrLf, vbNullString)
                                .Clear
                            End If
                        End With
                        On Error GoTo 0
    skpStatement:
                    Next statement
                Next file
            End With
            .Quit acQuitSaveAll
        End With
    
        dTime = Now() - starttime
    
        ' Returnwert
        If sErr = vbNullString Then sErr = "Keine Fehler"
        createDB = "Zeit: " & Now & " | Dauer: " & Format(dTime, "hh:mm:ss") & " | Anzahl Fehler: " & iErr & vbCrLf & sErr
    
        ' Log
        With ThisWorkbook
            '...
            .Saved = True
            .Save
        End With
    
    End Function
    
  • create mail merges from Excel in a Word.Application, using existing and rather large .docm-templates and dynamic SQL-queries that returns the receipents

    Set rst = GetRecordset(ThisWorkbook.Sheets("Parameter").Range("A1:S100"))
    
    With New Word.Application
    
        .Visible = False
    
        While Not rst.EOF
            If rst!Verarbeiten And Not IsNull(rst!Verarbeiten) Then
                Debug.Print rst!Sql
    
                .Documents.Open rst!inpath & Application.PathSeparator & rst!infile
                stroutfile = fCheckPath(rst!outpath, True) & Application.PathSeparator & rst!outfile
    
                .Run "quelle_aendern", rst!DataSource, rst!Sql
    
                .Run MacroName:="TemplateProject.AutoExec.SeriendruckInDokument"
    
                Application.DisplayAlerts = False
    
                .ActiveDocument.ExportAsFixedFormat _
                    OutputFileName:=stroutfile _
                    , ExportFormat:=wdExportFormatPDF _
                    , OpenAfterExport:=False _
                    , OptimizeFor:=wdExportOptimizeForPrint _
                    , Range:=wdExportAllDocument _
                    , From:=1, To:=1 _
                    , Item:=wdExportDocumentContent _
                    , IncludeDocProps:=False _
                    , KeepIRM:=True _
                    , CreateBookmarks:=wdExportCreateNoBookmarks _
                    , DocStructureTags:=False _
                    , BitmapMissingFonts:=True _
                    , UseISO19005_1:=False
    
                Application.DisplayAlerts = True
    
                For Each doc In .Documents
                    With doc
                        .Saved = True
                        .Close SaveChanges:=wdDoNotSaveChanges
                    End With
                Next doc
    
            End If
            rst.MoveNext
        Wend
    
        .Quit
    End With
    

notes:

  • When run on a smaller scale (for example, when querying less records or using less complex templates), both codes do run smoothly.
  • In both cases, when I OK through all the reappearing prompts, the code will eventually finish with the desired results. Therefore, I guess I'm not encountering an error (also it doesn't trigger the error handlers), but rather something like a timeout.

As suggested on other sources, I do wrap my code into Application.DisplayAlerts = False. This, however, seems like a horrible idea, since there might actually be cases where I do need to be alerted.

Martin Dreher
  • 1,514
  • 2
  • 12
  • 22
  • 3
    https://groups.google.com/forum/?hl=en#!msg/microsoft.public.excel.programming/ct8NRT-o7rs/jawi42S8Ci0J – Tehscript May 31 '17 at 15:27
  • We need more context. How do the two methods relate? Does the mail merge connect to the database being built? Where do you call the two routines? It's not clear why you need to build a whole database on the fly each time. – Parfait May 31 '17 at 15:47
  • Finally, it seems you have MS Access installed, consider using it to call the other office apps as it arguably has a better object model and application/automation environment. – Parfait May 31 '17 at 15:48
  • 4
    Seems shutting off that message is tackling the *symptom* rather than the actual problem. If your queries have performance issues, the solution isn't to tell the client to stop whining - the solution is to get the queries to complete in a reasonable amount of time. Are you missing indexes? Are your queries written in inefficient ways? Anything that takes more than, say, 7 seconds to refresh, should be done differently. Consider doing the heavy processing overnight and dumping the results in a table, and then simply querying that table. Oh wait, Access. Good luck! – Mathieu Guindon May 31 '17 at 15:50
  • A little free code-review: Please consider changing `If Len(statement) < 5 Then GoTo skpStatement` to `if Len(statement) >=5 Then`. It eliminates the needless `GoTo` statement by simply testing for the cases when you _do_ want to execute the code instead of when you _don't_ want to. – FreeMan May 31 '17 at 17:26
  • @Mat'sMug `Oh wait, Access. Good luck!` Ye well, don't get me started. ;) `SQL` runs as fast as you'd expect (no indexes bc flatfiles with `schema.ini`, normalizing columns to rows with `UNION ALL` for a lack of better options).... so: pretty slow. Still, I feel like I did what I could to streamline the `SQL`. I am perfectly content with the `.Execute` taking 10 minutes, as long as I am not buggered by messages suggesting something is amiss, when in fact the code does run error-free – Martin Dreher Jun 01 '17 at 08:34
  • @Parfait Thanks for your input. As stated, those are only two examples of lengthy operations that cause said behavior, not related. As for your 2nd point: interesting advice, will keep that in mind! Sadly, in this particular case, I had to use `Excel`, since afaik `Access` can't be automated with `Powershell` – Martin Dreher Jun 01 '17 at 08:40
  • @FreeMan Fair point, thanks for pointing that out. However, in that example, it's actually the `.Execute` that takes like 5 minutes per file (which by itself would be perfectly fine by me) – Martin Dreher Jun 01 '17 at 08:42
  • Eliminating the `Goto` has nothing to do with code execution speed (in particular), it's just an opportunity to get rid of a `Goto`! It's bad enough that we're forced to use them in VBA for error handling... :/ (Yes, there are a few legitimate uses for `Goto`, just not many.) – FreeMan Jun 01 '17 at 11:37
  • @MartinDreher I worked in a place where it was deemed *normal* for a SSRS report to take 30 minutes to process... People have varying standards I guess. Still, I would recommend you put your SQL up for review on [codereview.se] if you can - you never know, maybe there's a chance it can be tweaked to run in under 10 seconds =) – Mathieu Guindon Jun 01 '17 at 13:34
  • Yes, MSAccess.exe is an exe like Excel and so can be automated with PowerShell, Batch, Cmd, etc. Build a module called in its [AutoExec macro](https://support.office.com/en-us/article/Automate-startup-events-with-a-macro-b08d4f22-b517-4ccf-bd14-8670416628b0) so runs every time Access opens. – Parfait Jun 01 '17 at 15:08
  • I am aware of Access being an exe. I do vaguely remember running into errors when powershell tried calling a sub that creates a database from scratch stored in my access database, with the same sub running smoothly when stored in an excel. Might want to look into it some more. **Thanks for your input guys!** – Martin Dreher Jun 02 '17 at 07:11

2 Answers2

10

I'll add the code that @Tehscript linked to in the comments.

You can solve this by using the COM API to remove VBA's message filter. This will prevent COM from telling VBA to displaying a message box when it thinks the process you're calling has blocked. Note that if the process really has blocked for some reason this will prevent you from receiving any notification of that. [source]

I think this is the code I used back in 2006 for the same problem (it worked).

Private Declare Function _
    CoRegisterMessageFilter Lib "OLE32.DLL" _
    (ByVal lFilterIn As Long, _
    ByRef lPreviousFilter) As Long

Sub KillMessageFilter()  
    '''Original script Rob Bovey  

    '''https://groups.google.com/forum/?hl=en#!msg/microsoft.public.excel.programming/ct8NRT-o7rs/jawi42S8Ci0J
    '''http://www.appspro.com/

    Dim lMsgFilter As Long

    ''' Remove the message filter before calling Reflections.
    CoRegisterMessageFilter 0&, lMsgFilter

    ''' Call your code here....

    ''' Restore the message filter after calling Reflections.
    CoRegisterMessageFilter lMsgFilter, lMsgFilter

End Sub
David Zemens
  • 53,033
  • 11
  • 81
  • 130
Darren Bartrup-Cook
  • 18,362
  • 1
  • 23
  • 45
  • @Tehscript , Darren: Does feel like I throwing the baby out with the bathwater. I do, however, really need that tub. Works for me, thanks a ton! – Martin Dreher Jun 01 '17 at 09:14
  • I add this issue while a mht file was locked by ms-word app instance fired up from ms-excel. Solution was to close the ms-word process, so that unlocking the mht file. – hornetbzz Jan 27 '23 at 04:36
0

I tried the COM API code as well, which works. But it is only useful in so far as you don't see the error - the 30-sec delay every time the error is triggered still happens which makes this unworkable for me.

The better change I have made is to turn off "Real time presence in Microsoft Office" in Drive File Stream (the google product). This has (so far!) resolved the issue for me. I'm guessing there is some sort of clash between this and another excel addin.

user1487861
  • 420
  • 6
  • 16