繁体   English   中英

在 Access 中运行 Excel VBA

[英]Run Excel VBA in Access

我一直在研究这个问题,但我没有找到任何关于它如何工作的线索。

我已经在 Excel 中编写了我想在 MS Access 中运行的代码。 我已经粘贴了我希望在 Access 中运行的代码。

我找到的所有示例或信息均来自 2003 Access。 我正在使用 2016 Access。

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

我在 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

您需要先处理几个概念。

库参考和范围

您的原始代码是用 Excel 编写的。 因此,在该 VBA 项目中,它引用了 Excel 对象。 在您的 Access VBA 项目中,没有引用它。 您可以通过查看Tools -> References来进行比较。

这给我们带来了“早期绑定”和“后期绑定”的概念。 当您输入Range. ,你会得到 VBA 的智能感知来告诉你你可以用一个Range或其他什么来做什么。 但是在 Access 中,默认情况下您没有引用 Excel 对象库。 因此, Range. 不会产生智能感知并且您无法运行代码,因为 Access 在其对象模型中没有Range ,并且您的 VBA 项目很可能没有包含它的引用。

因此,如果您不想添加对 Excel 对象模型的引用,则需要调整您的代码以运行后期绑定,而且您很可能确实想要这样做。

不合格参考

您的原始 Excel 代码包含对 Excel 对象模型中可用的各种全局对象的非限定引用。

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

这些不一定能在 Excel 以外的其他主机托管的 VBA 项目中始终如一地工作,而且大多数肯定不会在后期绑定代码中工作。 此外,如果您选择添加对 Excel 对象模型的引用,您最终仍会泄漏 Excel 实例,这可能会导致幻影实例,因为对全局对象的不合格引用将隐式创建一个您无法交互的 Excel 实例,这也可能导致路径上的其他运行时错误。 为了让你的代码更晚绑定,你需要这样的东西:

Set ExcelApp = CreateObject("Excel.Application")

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

请注意,您可以在 Excel 托管的上下文中访问的所有全局对象现在必须是一个独立的变量。 此外,您将无权访问其他 VBA 项目中的ThisWorkbook甚至Sheet1 ,因为 Excel 不再是宿主。 您必须相应地进行调整。

在早期绑定和后期绑定之间切换

早期绑定代码使您更容易开发,因为您可以获得完整的智能感知和对象浏览器来帮助您编写代码。 但是,在引用其他对象模型时,您可能希望使用后期绑定来分发 VBA 代码以避免版本控制问题和引用损坏。 但是您可以同时拥有两个世界中最好的:

#Const EarlyBind = 1

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

Set ExcelApp = CreateObject("Excel.Application")

这说明了使用条件编译参数来允许您拥有ExcelApp变量,该变量可以是Excel.Application (又名早期绑定)与Object (又名后期绑定)。 要更改,只需将Const LateBind行更改为01之间。

首先,清理术语:

  • VBA 是一种独立的语言,不依赖于任何MS Office 应用程序。 在 Tools\References 下,您会看到Visual Basic for Applications通常是第一个选中的对象。 在 Excel、Access、Word、Outlook 等中运行 VBA 的不同之处在于默认访问它们的对象库。 具体来说:

    • 只有Excel可以看到WorkbookWorksheet等而无需定义其来源
    • 只有Access可以看到FormsReports等而无需定义其来源
    • 只有Word可以看到DocumentsParagraphs等而不定义其来源
  • 当在应用程序中运行外部对象库时,例如 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)

话虽如此,只需保持原始代码几乎完好无损,但更改定义和初始化即可。 值得注意的是,所有Application调用现在都指向Excel.Application对象,不要与 Access 的应用程序混淆。 另外,避免.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

顺便说一句,上面可以在任何MS Office 应用程序中运行,因为没有使用父应用程序(这里是 MS Access)的对象!

暂无
暂无

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

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