简体   繁体   English

在 Access 中运行 Excel VBA

[英]Run Excel VBA in Access

I have been researching this a great deal and I am not finding any leads to how this would work.我一直在研究这个问题,但我没有找到任何关于它如何工作的线索。

I have written code in Excel that I want to run in MS Access.我已经在 Excel 中编写了我想在 MS Access 中运行的代码。 I have pasted the code I wish to run in Access.我已经粘贴了我希望在 Access 中运行的代码。

All the examples or information I have found is from 2003 Access.我找到的所有示例或信息均来自 2003 Access。 I am using 2016 Access.我正在使用 2016 Access。

The Excel code Excel代码

Public Function getworkbook()
    ' Get workbook...
    Dim ws As Worksheet
    Dim Filter As String
    Dim targetWorkbook As Workbook, wb As Workbook
    Dim Ret As Variant

    Application.DisplayAlerts = False

    Sheets("DATA").Delete
    '   Sheets("DATA").Cells.Clear

    Set targetWorkbook = Application.ActiveWorkbook

    ' get the customer workbook
    Filter = "Text files (*.xlsx;*.xlsb),*.xlsx;*.xlsb"
    Caption = "Please Select an input file "
    Ret = Application.GetOpenFilename(Filter, , Caption)

    If Ret = False Then Exit Function

    Set wb = Workbooks.Open(Ret)

    wb.Sheets(1).Move After:=targetWorkbook.Sheets(targetWorkbook.Sheets.Count)

    ' ActiveSheet.Paste = "DATA"

    ActiveSheet.Name = "DATA"

    ThisWorkbook.RefreshAll

    ' Application.Quit
    Application.DisplayAlerts = True

End Function

Code I found and tried to use in Access.我在 Access 中找到并尝试使用的代码。

Public Function runExcelMacro(wkbookPath)
    Dim XL As Object
    Set XL = CreateObject("Excel.Application")
    With XL
        .Visible = False
        .displayalerts = False
        .Workbooks.Open wkbookPath
        'Write your Excel formatting, the line below is an example
        .Range("C2").value = "=1+2"
        .ActiveWorkbook.Close (True)
        .Quit
    End With
    Set XL = Nothing
End Function

There are few concepts you need to deal with first.您需要先处理几个概念。

Library references and scope库参考和范围

Your original code was written in Excel.您的原始代码是用 Excel 编写的。 Therefore, in that VBA project, it has Excel object referenced.因此,在该 VBA 项目中,它引用了 Excel 对象。 In your Access VBA project, that is not referenced.在您的 Access VBA 项目中,没有引用它。 You can compare this by looking at Tools -> References .您可以通过查看Tools -> References来进行比较。

That brings us to the concept of "early-binding" and "late-binding".这给我们带来了“早期绑定”和“后期绑定”的概念。 When you type in things like Range.当您输入Range. , you get VBA's intellisense to tell you what you can do with a Range or whatever. ,你会得到 VBA 的智能感知来告诉你你可以用一个Range或其他什么来做什么。 But in Access, you don't have Excel object library referenced by default.但是在 Access 中,默认情况下您没有引用 Excel 对象库。 Therefore, Range.因此, Range. will not yield intellisense and you can't run the code because Access does not have Range in its object model and your VBA project mostly likely don't have a reference that has it.不会产生智能感知并且您无法运行代码,因为 Access 在其对象模型中没有Range ,并且您的 VBA 项目很可能没有包含它的引用。

Therefore, your code need to be adjusted to run late-bound if you do not want to add reference to Excel object model, and you most likely do want that anyway.因此,如果您不想添加对 Excel 对象模型的引用,则需要调整您的代码以运行后期绑定,而且您很可能确实想要这样做。

Unqualified Reference不合格参考

Your original Excel code contains unqualified references to various global objects that are available in Excel's object model.您的原始 Excel 代码包含对 Excel 对象模型中可用的各种全局对象的非限定引用。

Application.DisplayAlerts = False
...
Sheets("DATA").Delete
...
Set wb = Workbooks.Open(Ret)
...

Those won't necessarily work consistently in VBA projects hosted by other hosts other than Excel and most certainly won't work in late-bound code.这些不一定能在 Excel 以外的其他主机托管的 VBA 项目中始终如一地工作,而且大多数肯定不会在后期绑定代码中工作。 Furthermore, if you elect to add a reference to Excel's object model, you still end up leaking Excel instance which can cause ghost instances because unqualified references to the global objects will implicitly create an Excel instance that you can't interact and that can also cause other runtime error down the path.此外,如果您选择添加对 Excel 对象模型的引用,您最终仍会泄漏 Excel 实例,这可能会导致幻影实例,因为对全局对象的不合格引用将隐式创建一个您无法交互的 Excel 实例,这也可能导致路径上的其他运行时错误。 To make your code more late-bindable, you need something like:为了让你的代码更晚绑定,你需要这样的东西:

Set ExcelApp = CreateObject("Excel.Application")

ExcelApp.DisplayAlerts = False
...
Set MyBook = ExcelApp.Workbooks("Whatever")
MyBook.Sheets("DATA").Delete
...
Set wb = ExcelApp.Workbooks.Open(Ret)
...

Note how all global objects that you could have accessed in a Excel-hosted context now have to be a variable on its own.请注意,您可以在 Excel 托管的上下文中访问的所有全局对象现在必须是一个独立的变量。 Furthermore, you won't have access to ThisWorkbook or even Sheet1 in other VBA projects because Excel is no longer the host.此外,您将无权访问其他 VBA 项目中的ThisWorkbook甚至Sheet1 ,因为 Excel 不再是宿主。 You must adjust accordingly.您必须相应地进行调整。

Switching between early-binding & late-binding在早期绑定和后期绑定之间切换

Early-bound code makes it much easier for you to develop since you get full intelisense and object browser helping you write the code.早期绑定代码使您更容易开发,因为您可以获得完整的智能感知和对象浏览器来帮助您编写代码。 However, when referencing other object models, you might want to distribute your VBA code using late-binding to avoid versioning problems and broken references.但是,在引用其他对象模型时,您可能希望使用后期绑定来分发 VBA 代码以避免版本控制问题和引用损坏。 But you can have best from both worlds:但是您可以同时拥有两个世界中最好的:

#Const EarlyBind = 1

#If EarlyBind Then
Dim ExcelApp As Excel.Application
#Else
Dim ExcelApp As Object
#End If

Set ExcelApp = CreateObject("Excel.Application")

This illustrates the use of conditional compilation argument to allow you to have ExcelApp variable that can be either Excel.Application (aka early-bound) vs. Object (aka late-bound).这说明了使用条件编译参数来允许您拥有ExcelApp变量,该变量可以是Excel.Application (又名早期绑定)与Object (又名后期绑定)。 To change, you simply change the Const LateBind line between 0 or 1 .要更改,只需将Const LateBind行更改为01之间。

First, to clear up terminology:首先,清理术语:

  • VBA is a separate language and not tied to any MS Office application. VBA 是一种独立的语言,不依赖于任何MS Office 应用程序。 Under Tools\References, you will see Visual Basic for Applications is usually the first checked object.在 Tools\References 下,您会看到Visual Basic for Applications通常是第一个选中的对象。 What differs between running VBA inside Excel, Access, Word, Outlook, etc. is the default access to their object library.在 Excel、Access、Word、Outlook 等中运行 VBA 的不同之处在于默认访问它们的对象库。 Specifically:具体来说:

    • Only Excel sees Workbook , Worksheet , etc. without defining its source只有Excel可以看到WorkbookWorksheet等而无需定义其来源
    • Only Access sees Forms , Reports , etc. without defining its source只有Access可以看到FormsReports等而无需定义其来源
    • Only Word sees Documents , Paragraphs , etc. without defining its source只有Word可以看到DocumentsParagraphs等而不定义其来源
  • When running a foreign object library inside an application, such as MS Access accessing Excel objects, you must define and initialize the foreign objects via reference either with early or late binding:当在应用程序中运行外部对象库时,例如 MS Access 访问 Excel 对象,您必须使用早期绑定或后期绑定通过引用定义和初始化外部对象:

     ' EARLY BINDING, REQUIRES EXCEL OFFICE LIBRARY UNDER REFERENCES Dim xlApp As Excel.Application Dim wb As Excel.Workbook Dim ws As Excel.Worksheet Set xlApp = New Excel.Application Set wb = xlApp.Workbooks.Open(...) Set ws = wb.Worksheets(1) ' LATE BINDING, DOES NOT REQUIRE EXCEL OFFICE LIBRARY UNDER REFERENCES Dim xlApp As Object, wb As Object, ws As Object Set xlApp = CreateObject("Excel.Application") Set wb = xlApp.Workbooks.Open(...) Set ws = wb.Worksheets(1)

With that said, simply keep original code nearly intact but change definitions and initializations.话虽如此,只需保持原始代码几乎完好无损,但更改定义和初始化即可。 Notably, all Application calls now point to Excel.Application object and not to be confused with Access' application.值得注意的是,所有Application调用现在都指向Excel.Application对象,不要与 Access 的应用程序混淆。 Plus, best practices of avoiding .Select/.Activate/ Selection/ ActiveCell/ ActiveSheet/ ActiveWorkbook .另外,避免.Select/.Activate/ Selection/ ActiveCell/ ActiveSheet/ ActiveWorkbook的最佳实践。

Public Function getworkbook()
    ' Get workbook...
    Dim xlApp As Object, targetWorkbook As Object, wb As Object, ws As Object         
    Dim Filter As String, Caption As String
    Dim Ret As Variant

    Set xlApp = CreateObject("Excel.Application")
    Set targetWorkbook = xlApp.Workbooks.Open("C:\Path\To\Workbook.xlsx")

    xlApp.DisplayAlerts = False

    targetWorkbook.Sheets("DATA").Delete

    ' get the customer workbook
    Filter = "Text files (*.xlsx;*.xlsb),*.xlsx;*.xlsb"
    Caption = "Please Select an input file "
    Ret = xlApp.GetOpenFilename(Filter, , Caption)

    If Ret = False Then Exit Function    
    Set wb = xlApp.Workbooks.Open(Ret)

    wb.Sheets(1).Move After:=targetWorkbook.Sheets(targetWorkbook.Sheets.Count)    
    Set ws = targetWorkbook.Worksheets(targetWorkbook.Sheets.Count)
    ws.Name = "DATA"

    targetWorkbook.RefreshAll

    xlApp.DisplayAlerts = True
    xlApp.Visible = True                        ' LAUNCH EXCEL APP TO SCREEN
    ' xlApp.Quit

    ' RELEASE RESOURCEES
    Set ws = Nothing: Set wb = Nothing: Set targetWorkbook = Nothing: Set xlApp = Nothing
End Function

By the way, above can be run in any MS Office application as no object of the parent application (here being MS Access) is used!顺便说一句,上面可以在任何MS Office 应用程序中运行,因为没有使用父应用程序(这里是 MS Access)的对象!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM