Edit a workbook, whether open or closed, from Word VBA

北战南征 提交于 2021-02-17 02:47:26

问题


I am trying to write a macro in Word so that I can save some information into an Excel file somewhere else in my computer. For this reason I wrote this:

Dim exlApp As Object
Dim exlWbk As Object
Set exlApp = CreateObject("Excel.Application")
Set exlWbk = exlApp.Workbooks.Open(FileName:="D:\database.xlsx")
exlWbk.ActiveSheet.Cells(1, 1).Value = "some info"
exlWbk.Close SaveChanges:=True
Set exlWbk = Nothing
exlApp.Quit
Set exlApp = Nothing

The code works perfectly fine for me, except when the Excel file in question (database.xlsx) is already opened by the user. In that case, running the macro will prompt me to save the new changes into a new copy of my excel file, which is not what I want. I want the new changes to be included in the current Excel file without creating a second copy of it.

Since the above code presented some problems, I wrote this:

Dim exlApp As Object
Dim exlWbk As Object
Set exlApp = CreateObject("Excel.Application")
Set exlWbk = exlApp.GetObject("D:\database.xlsx")
exlWbk.ActiveSheet.Cells(1, 1).Value = "some info"
exlWbk.Save
Set exlWbk = Nothing
exlApp.Quit
Set exlApp = Nothing

But nothing changed. I know there are some ways to figure out whether my Excel file is open or not, but the problem is that I don't know how to change my code if I find out that file is open.

How can I determine whether a workbook is open in Excel so that it can be edited, or open the file in order to edit it if it's closed?


回答1:


According to the documentation, GetObject(filename) will pick up the existing file if it's already open or, optionally, open the file if it is not open:

When this code is executed, the application associated with the specified pathname is started, and the object in the specified file is activated.

If Excel is not running, by default nothing will be visible when GetObject(filename) executes. Excel will be opened, the file will be opened and changed. There's a real danger, therefore, that the instance of Excel and the workbook will "hang" in memory, which could be seen in the Windows "Task Manager". Repeated running of such code can eventually crash Windows, so care must be taken to clean things up correctly on each iteration.

Since the question also stipulates that the file could be opened already by a user, it's necessary to determine that, as well as whether the Excel application is already running.

The following code sample demonstrates how this can be done. The assumption is that neither the applicaton nor the file is open. Then it tests whether Excel is already running.

Set xlApp = GetObject(, "Excel.Application")

Notice the difference in the syntax: instead of the fileName there's a comma, followed by the name of the application. This will check whether the application is available; if it's not, an error will be triggered. Therefore, On Error Resume Next precedes GetObject, which means the error will be ignored.

Since ignoring errors is dangerous, the next line Or Error GoTo 0 turns errors back on.

If GetObject is not successful, the variable xlApp could not be instantiated and its "value" is Nothing. If Not xlApp Is Nothing executes if xlApp could be instantiated and the Boolean appAlreadyOpen is set to true so that we know to not quit Excel when the code finishes. It also checks whether the required workbook is already open. If it is, xlWb can be instantiated and fileAlreadyOpened set to true.

If xlWb could not be instantiated, either because the Excel application was not running or the workbook was not yet open, GetObject(fileName) is executed. The workbook will be opened, in the existing instance of Excel if already running or in a new instance of Excel. At the end of this code block two lines are commented: should the newly started Excel application be made visible and remain open when the code ends, uncomment them.

The workbook can then be edited.

Lastly, things need to be cleaned up. The Booleans are checked and if not true, the workbook and possibly the application are closed. Very important are the last two lines that release these objects from memory. If the code creates any other objects, such as Ranges, these should also be released, in the reverse order they are instantiated.

Sub GetFileOpenedOrClosed()
    Dim xlApp As Object              ' Excel.Application
    Dim xlWB As Object, wb As Object ' Excel.Workbook
    Dim fileName As String
    Dim fileAlreadyOpen As Boolean, appAlreadyOpen As Boolean

    fileName = "C:\Test\SampleChart.xlsx"
    fileAlreadyOpen = False
    appAlreadyOpen = False
    On Error Resume Next
    Set xlApp = GetObject(, "Excel.Application")
    On Error GoTo 0
    If Not xlApp Is Nothing Then
        appAlreadyOpen = True
        For Each wb In xlApp.Workbooks
            If wb.FullName = fileName Then
                Set xlWB = wb
                fileAlreadyOpen = True
                Exit For
            End If
        Next
    End If
    If xlWB Is Nothing Then
        Set xlWB = GetObject(fileName)
        Set xlApp = xlWB.Application
        xlWB.Windows(1).Visible = True 'So that the window is not hidden when file is opened again
        'xlApp.Visible = True
        'xlApp.UserControl = True
    End If
    xlWB.Worksheets(1).Cells(7, 1).value = "some other info"
    If Not fileAlreadyOpen Then
        xlWB.Save
        xlWB.Close
    End If
    If Not appAlreadyOpen Then
        xlApp.Quit
    End If
    Set xlWB = Nothing
    Set xlApp = Nothing
End Sub


来源:https://stackoverflow.com/questions/60119174/edit-a-workbook-whether-open-or-closed-from-word-vba

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!