0

我有一个提供一组 UDF 的 Excel 自动化插件。即使通过互操作 API 打开 Excel,我也想让这些 UDF 正常工作。我知道当通过互操作 API 打开 Excel 时,Excel 以/automation使 Excel不加载 addins的参数启动。为了解决这个问题,我添加了以下Workbook_Open()事件:

Private Sub Workbook_Open()
    Application.AddIns("SomeApp.DemoAddin").Installed = False
    Application.AddIns("SomeApp.DemoAddin").Installed = True
End Sub

此代码成功加载插件。我验证了在插件中使用一些日志记录。

我整理了一个名为 UDF 的测试工作簿=myDemoFunction()。通过打开该工作簿时,"C:\path\to\EXCEL.exe" /automation C:\path\to\workbook.xlsm我观察到以下行为。首先,带有 UDF 的单元格显示正确的结果(在本例中为“15.0”)。公式显示为=SomeApp.DemoAddin.myDemoFunction()好像,这通常仅在未加载插件时出现。当使用 VBA 进行重新计算CTRL+ALT+F9Application.CalculationFullRebuild在 VBA 中进行重新计算时,甚至使用 all 将所有填充的单元格标记为脏时,ThisWorkbook.Worksheets(1).UsedRange.Dirty都会导致带有 UDF 的单元格显示#NAME?。编辑其中一个 UDF 单元格(选择F2、、、Return)时,该工作表上的所有 UDF(不在其他也使用该 UDF 的工作表上)突然再次返回正确的结果,并且公式=myDemoFunction()再次变为。

所以我的问题是,如何触发 Excel 以编程方式识别插件?


我的代码库要大得多,但下面是自动化插件的精简版本,显示了这种行为(在 VB.net 中):

Imports Extensibility
Imports System.Runtime.InteropServices
Imports Excel = Microsoft.Office.Interop.Excel

<GuidAttribute("352B1C10-DC5A-4BF8-9D31-DB9913B07364"),
ProgIdAttribute("SomeApp.DemoAddin"),
ClassInterface(ClassInterfaceType.AutoDual)>
Public Class DemoAddin
    Implements IDTExtensibility2

    Private excelApp As Excel.Application

    Public Sub OnBeginShutdown(ByRef custom As Array) Implements IDTExtensibility2.OnBeginShutdown
    End Sub
    Public Sub OnAddInsUpdate(ByRef custom As Array) Implements IDTExtensibility2.OnAddInsUpdate
    End Sub
    Public Sub OnStartupComplete(ByRef custom As Array) Implements IDTExtensibility2.OnStartupComplete
    End Sub

    Public Sub OnDisconnection(RemoveMode As ext_DisconnectMode, ByRef custom As Array) Implements IDTExtensibility2.OnDisconnection
        Marshal.ReleaseComObject(excelApp)
        excelApp = Nothing
    End Sub

    Public Sub OnConnection(application As Object, connectMode As ext_ConnectMode, addInInst As Object, ByRef custom As Array) Implements IDTExtensibility2.OnConnection
        excelApp = CType(application, Excel.Application)
    End Sub

    Public Function myDemoFunction() As String
        Return excelApp.Version
    End Function
End Class
4

1 回答 1

0

调用从 VBA 中断的所有 UDF 就足够了。所以更新Workbook_Open()就可以了。下面的代码还进行了一些探索,以免不必要地重新加载插件,但这不是必需的。真正的魔力在倒数第二行Application.Run "myDemoFunction"

Private Sub Workbook_Open()
    ensureAddinLoaded
End Sub

Public Sub ensureAddinLoaded()
    Debug.Print "Probing for addin"
    On Error GoTo NotLoaded
    Application.Run "myDemoFunction"
    Exit Sub
NotLoaded:
    Debug.Print "Addin not loaded. Reloading."
    Application.AddIns("SomeApp.DemoAddin").Installed = False
    Application.AddIns("SomeApp.DemoAddin").Installed = True
    Application.Run "myDemoFunction"
End Sub

此解决方案需要知道有哪些确切的 UDF,因此它不是最理想的。

于 2019-10-28T14:37:11.393 回答