【问题标题】:Using MS Access to run code in excel vba使用 MS Access 在 excel vba 中运行代码
【发布时间】:2015-06-24 09:14:29
【问题描述】:

我使用访问前端从 SQL Server 中提取查询。然后我将记录集导出到一个新的 Excel 工作簿。然后我想使用 excel 来运行我在 Access 中的代码。它只是循环遍历单元格并添加格式并检查某个值。我可以从访问中运行它,它将使工作簿打开循环正常。然而,它的速度非常缓慢。

如果我进入 excel 并粘贴访问正在运行的代码以进行格式化和检查。它在几秒钟内运行。但是从访问中运行它需要 10 多分钟。

如果可以做到这一点,有人有任何想法吗?

【问题讨论】:

  • 我不太明白。 Access 是否使用自动化系统向 Excel 输入值? Excel 是否在 Access 中运行代码? Excel 是否在 Access 中运行代码?
  • 访问不会花费超过 10 分钟进行格式检查。你做错了什么。粘贴我们可能会理解缺少什么的代码。也可以尝试使用模板。
  • 这是一种格式检查,它将任何非文本单元格转换为文本。由于有很多包含数字的单元格需要采用文本格式才能将文件上传到只能采用文本格式的系统。运行需要一段时间。但是,从 Excel 模块内部运行它大约需要 10 秒。

标签: excel vba ms-access


【解决方案1】:

我已将此代码放在 Excel 中的“ThisWorkbook”对象中:

Public Sub TestScript()

    Debug.Print "Hello"

End Sub

然后使用表单上的按钮从 Access 成功调用它:

Private Sub cmdRunExcel_Click()

    Dim xl As Excel.Application
    Set xl = CreateObject("Excel.Application")

    xl.Visible = True

    xl.Workbooks.Open "C:/Your/FolderPath/And/FileName.xlsx", True, False

    xl.Run "ThisWorkbook.TestScript"

    Set xl = Nothing

End Sub

诚然,我没有给它很多代码来运行,但这里的代码至少可以在 Excel 上运行,来自 Excel...这一定比尝试在其上运行代码更好来自 Access 的 Excel。

更新:看看你是否可以通过测试来创建从 Access 到 Excel 的模块(我无法正确测试它,因为我使用的是一台工作计算机,它似乎不让我由于安全设置,运行此类代码)

Private Sub cmdRunExcel_Click()

    Dim xl As Excel.Application
    Dim myWrkBk As Excel.Workbook
    Dim myModule As VBComponent
    Dim strVb As String

    Set xl = CreateObject("Excel.Application")

    xl.Visible = True

    xl.Workbooks.Open "C:/Your/FolderPath/And/FileName.xlsx", True, False

    Set myWrkBk = xl.Workbooks.Add
    Set myModule = myWrkBk.VBProject.VBComponents.Add(vbext_ct_StdModule)

    strVb = "Public Sub TestScript()" & vbCrLf _
          & "Debug.Print 'Hello'" _
          & "End Sub"

    myModule.CodeModule.AddFromString strVb

'    xl.Run "ThisWorkbook.TestScript"

    Set myModule = Nothing
    Set myWrkBk = Nothing
    Set xl = Nothing

End Sub

【讨论】:

  • 这将是完美的。除了每次从 Access 运行代码时我都会创建新的工作簿。它确实创建了大约 10~ 个 Excel 工作簿。每个都需要运行代码。但由于它们是新工作簿,我无法在其中添加任何模块
  • 啊,那更复杂。我确实尝试过测试您是否可以使用此处的一些示例从 Access 中创建 Excel 模块:bit.ly/1JQqr0N 我正在使用我工作的计算机,但出现了似乎与我工作的安全设置相关的错误。不过你可能很幸运。
  • 我已将我在更新部分尝试的内容添加到我的答案中......就像我说的,我收到了一条安全错误消息,这可能取决于我雇主的安全设置,所以它可能为你工作。这个想法是它会在你的电子表格中添加一个带有一些代码的模块。
  • 尝试添加。这就是我所追求的。但是我收到消息“不信任对 Visual Basic 项目的编程访问”所以我猜测使其受信任的唯一方法是通过信任中心?但这意味着我将无法做到。因为它是通过 Access 创建的。感谢您迄今为止的所有帮助。
  • 我遇到了同样的问题。我无权在工作中调整这些安全设置,但也许您可以在您的计算机上进行调整? (显然这会降低您的文件安全性)stackoverflow.com/questions/25638344/…
【解决方案2】:

如果我理解正确,您将代码从 Access 复制到 Excel 并在 Excel 中运行相同的代码,在这两种情况下,代码都会操作电子表格,Excel 中的一个速度很快,Access 中的另一个速度很慢,您可以尝试以下方法:

  • 隐藏 Excel 窗口 (ActiveWorkbook.Windows(1).Visible = False),同时检查 here
  • 停止重新计算工作表 - 检查this
  • 在 Excel 工作表中编写相同的函数(作为模板文件)并仅从 Access 运行它

我希望这会有所帮助。

通常,自动化比宏(vba 代码)慢得多。这同样适用于其他应用程序,例如。微软Word。

【讨论】:

  • 我已经隐藏了 Excel 窗口。 MS Access 代码创建大约 10 个 Excel 文件,隐藏窗口,然后将它们保存在网络上。我试图关闭计算方法,但速度没有差异。两者都没有帮助。我会考虑添加一个模板文件并尝试一下
【解决方案3】:

如果您希望在 Excel 中运行的代码始终相同,请打开一个 Excel 模板,其中附有一个包含您的代码的宏工作簿。 然后,从 Access 中,您可以运行一系列宏,或者如果只有一个宏被传递给参数数组,当然也可以只运行一个宏:

Function RunExcelMacros( _
  ByVal strFileName As String, _
  ParamArray avarMacros()) As Boolean

Debug.Print "xl ini", Time

  On Error GoTo Err_RunExcelMacros

  Static xlApp      As Excel.Application
  Dim xlWkb         As Excel.Workbook

  Dim varMacro      As Variant
  Dim booSuccess    As Boolean
  Dim booTerminate  As Boolean

  If Len(strFileName) = 0 Then
    ' Excel shall be closed.
    booTerminate = True
  End If

  If xlApp Is Nothing Then
    If booTerminate = False Then
      Set xlApp = New Excel.Application
    End If
  ElseIf booTerminate = True Then
    xlApp.Quit
    Set xlApp = Nothing
  End If

  If booTerminate = False Then
    Set xlWkb = xlApp.Workbooks.Open(FileName:=strFileName, UpdateLinks:=0, ReadOnly:=True)

    ' Make Excel visible (for troubleshooting only) or not.
    xlApp.Visible = False 'True

    For Each varMacro In avarMacros()
      If Not Len(varMacro) = 0 Then
  Debug.Print "xl run", Time, varMacro
        booSuccess = xlApp.Run(varMacro)
      End If
    Next varMacro
  Else
    booSuccess = True
  End If

  RunExcelMacros = booSuccess

Exit_RunExcelMacros:

  On Error Resume Next

  If booTerminate = False Then
    xlWkb.Close SaveChanges:=False
    Set xlWkb = Nothing
  End If

Debug.Print "xl end", Time
  Exit Function

Err_RunExcelMacros:
  Select Case Err
    Case 0      'insert Errors you wish to ignore here
      Resume Next
    Case Else   'All other errors will trap
      Beep
      MsgBox "Error: " & Err & ". " & Err.Description, vbCritical +
vbOKOnly, "Error, macro " & varMacro
      Resume Exit_RunExcelMacros
  End Select

End Function

另外,请注意您 - 如上所示 - 必须非常严格地以正确的顺序打开、使用和关闭 Excel 对象。没有 ActiveWorkbook 之类的。

【讨论】:

    【解决方案4】:

    基于 Matt Hall 的回答,但经过更改以显示您可以如何通过 Access:

    • 调用ThisWorkbook以外的Excel模块;
    • 调用 Excel Subs 或从 Excel 函数中检索值;和
    • 获取通过引用传递的参数的atlered 值。

    在 Excel 中名为 basTextModule 的自定义模块中:

    Public Sub ShowCoolMessage()
     MsgBox "cool"
    End Sub
    
    ' Add02 is explictly ByRef (the default in VBA) to show that
    ' the parameter will be altered and have its value changed even for
    ' prodedures higher up the call stack.
    Public Function GetCoolAmount(Add01 As Variant, _
                                Optional ByRef Add02 As Integer) As Integer
      Add02 = Add02 + 1
      GetCoolAmount = 10 + Add01 + Add02
    End Function
    
    

    访问中:

    • 设置对 Excel 的引用(VBA IDE > 工具 > 参考 ... Microsoft Excel 16.0 对象库)。
    • 然后创建一个(有点)通用的 RunExcelCode ...

    对于通过引用传递给工作的参数:

    • Microsoft Docs, Application.Run method (Excel) 请注意,当您将参数传递给 Excel 子程序或函数时,“您不能在此方法中使用命名参数。参数必须按位置传递”。

    • 声明 excelApp 使用Object 而不是Excel.Application 以确保可以检索通过引用传递给excelApp.Run 的任何参数的值。资料来源:Jaafar Tribak "Application.Run .. (Argument Passed ByRef)" at https://www.mrexcel.com/board/threads/application-run-argument-passed-byref.998132/post-4790961

    • 在被调用的子函数或函数中,参数(除了第一个ModuleAndSubOrFunctionName)必须具有与调用模块或函数的参数数据类型相匹配的数据类型。它们可以是变体或特定的数据类型。例如,出于说明目的,Arg02 是一个整数,因此在使用 RunExcelCode(WorkbookPathAndFileName, "basTestModule.GetCoolAmount" ...) 时,GetCoolAmount 的第二个参数也必须如此。

      但是,为了使您的RunExcelCode 更通用,确保Arg01Arg02、...Arg30 参数都是变体可能是明智的;因此,您最终调用的子函数或函数的参数也是变体,例如 ...

      Public Function GetCoolAmount(Add01 As Variant, _
                                Optional ByRef Add02 As Variant) As Integer
      ...
      
    Public Function RunExcelCode(WorkbookPathAndFileName As String, _
                                 ModuleAndSubOrFunctionName As String, _
                                 Optional ByRef Arg01 As Variant, _
                                 Optional ByRef Arg02 As Integer) As Variant
      ' Must be Object, not Excel.Application, to allow for parameters pass by reference
      Dim excelApp  As Object
      Dim workbook  As Excel.workbook
      
      Dim Result As Variant
      
    On Error GoTo HandleErr
      
      ' Can be Excel.Application if excelApp previously declared as Object
      Set excelApp = New Excel.Application
      
    '  excelApp.Visible = True ' For debugging
      
      Set workbook = excelApp.Workbooks.Open(WorkbookPathAndFileName)
      
      ' Get a value from a function or,
      ' if it is a sub a zero length string "" will be returned
      Result = excelApp.Run(ModuleAndSubOrFunctionName, Arg01, Arg02)
      
      RunExcelCode = Result
    
    ExitHere:
      workbook.Close
      excelApp.Quit
      Set workbook = Nothing
      Set excelApp = Nothing
    Exit Function
    
    HandleErr:
      Select Case Err.number
        Case Else
          MsgBox "Error " & Err.number & ": " & Err.Description, _
            vbCritical, "RunExcelCode"
      End Select
      Resume ExitHere
    End Function
    

    测试(来自 Access),调用 Sub 和 Function:

    Private Sub TestRunExcelCode()
      Dim WorkbookPathAndFileName  As String
      Dim Result As Variant
      
      WorkbookPathAndFileName = "C:\Users\YourName\Documents\MyWorkbook.xlsm"
      
      '   Run a sub
      Result = RunExcelCode(WorkbookPathAndFileName, "basTestModule.ShowCoolMessage")
      If IsNull(Result) Then
        Debug.Print "{Null}"
      ElseIf Result = "" Then
        Debug.Print "{Zero length string}"
      Else
        Debug.Print Result
      End If
    
      ' Will output "{Zero length string}"
      
      ' Get a value from a function
      Dim Arg02 As Integer
      Arg02 = 1
      Debug.Print "Arg02 Before: " & Arg02
      Result = RunExcelCode(WorkbookPathAndFileName, _
                          "basTestModule.GetCoolAmount", 1, Arg02)
      Debug.Print "Arg02 After : " & Arg02  ' Value will have changed, as desired.
      Debug.Print "Result      : " & Result
      
    End Sub
    

    编辑 01:使代码更通用的重大更改。

    编辑 02:处理通过引用传递的参数的重大更改。

    编辑 03:在“使您的 RunExcelCode 更通用”的案例中添加了详细信息。

    【讨论】:

      猜你喜欢
      • 2018-06-24
      • 1970-01-01
      • 1970-01-01
      • 2015-10-27
      • 2017-08-17
      • 1970-01-01
      • 2022-10-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多