Office-JS 和 VBA Addin 如何混合在一起

问题描述 投票:0回答:3

是否可以将 OfficeJS 命令按钮放置到像 .xlam 文件一样构建的自定义 VBA 插件面板?
* 我仍然希望混合使用 VBA 和 OfficeJS

office-js
3个回答
5
投票

这尚未经过测试,但我相信按照这些思路可以完成这项工作:

使用

CustomXMLPart.dataNodeReplaced
事件:

function addNodeReplacedEvent() {
    Office.context.document.customXmlParts.getByIdAsync("vbaJSBridge", function (result) {
        var xmlPart = result.value;
            xmlPart.addHandlerAsync(Office.EventType.DataNodeReplaced, function (eventArgs) {
            // do stuff with xmlPart
            // here you should be able to receive information sent from VBA,
            // and return any data necessary.
        });
    });
}

在VBA中使用:

Dim part As CustomXMLPart 
    
' Returns a custom xml part by its ID:
Set part= ActiveDocument.CustomXMLParts.SelectByID("vbaJSBridge") 
    
part.LoadXML("<data id="vbaJSBridge">some data</data>")

正如我所说,我不确定这是否完全有效,但这是完成这项工作的一个很好的(有点hacky)方法。或者,您可以使用 VBA 设置 HTTP 服务器,您可以将 HTTP 请求发送到 JavaScript。为此,您必须使用 Mswsock.dll 并调用 accept 方法(我认为)。


编辑:

自从我最初的回答以来已经过去了很多个月,现在我确实有了更多的细节。我尝试将

NodeAfterInsert
NodeAfterReplace
VBA 事件与
customXmlPart.setXml(sXML);
一起使用,但这不会触发事件。 这是 Microsoft 选择不修复的问题。因此,当前无法进行事件驱动的通信。

在这种情况下,唯一的选择是通过 XML 来轮询 Excel VBA 中的

Application.OnTime()
和 Javascript 中的
setInterval()
更改。

HTTP 服务器仍然是可能的,但至少需要通过 VBA 托管 HTTP 服务器。完全可能(这里是一个 C++ 示例),但需要深入了解 Winsock API 和底层编程。


编辑2

我创建了一个库,它有助于单向消息发送。

  1. 下载并导入VBA代码
  2. 导入 scriptlab 要点
  3. 下载并运行示例 VBA 代码。

'Requires JsBridge from here:            https://github.com/sancarn/VbaJsBridge
'ScriptLab test can be downloaded here:  https://gist.github.com/sancarn/b974b650f4b451ff2de51861af1671b1
Sub test()
    Dim js As JsBridge: Set js = JsBridge.Create("test")
    Call js.SendMessageSync("hello world")
    
    Dim col as new collection
    For i = 1 to 10
        'Add action to a collection so we can check it's status later
        col.add js.SendMessage("hello " & i)
    next
End Sub

您应该看到我们可以在 JavaScript 控制台中打印“hello world”和“hello 1”...“hello 10”。

将数据从 JavaScript 发送到 VBA 可以使用相同的桥,但具有

for="vb"
属性。然而,这还没有连接起来,请注意,这需要在 VBA 端进行轮询,可能来自工作簿/工作表对象。


1
投票

不可以,您无法从 Web 插件与 VBA 宏或 COM 插件进行交互。请记住,Web 插件就像网页一样,它们被沙箱化,无法与操作系统或已安装的程序通信(至少在没有帮助程序或代理应用程序/库的情况下)。


1
投票

所以,这有点老了,但我发现了一种从officeJS 向VBA 发送消息的方法。它依赖于 CustomXMLParts.PartAfterAdd 事件。

本质上在 vba 中创建一个监视器类,类似于::

Public WithEvents parts as CustomXMLParts
Private Sub Class_Initialize
  set parts = ActiveWorkbook.CustomXMLParts
End Sub
Private Sub parts_PartAfterAdd(ByVal objPart As CustomXMLPart)
  MsgBox("Message received!")
end Sub
Private Sub parts_PartBeforeDelete(ByVal objPart As CustomXMLPart)
  MsgBox("Message received!")
end Sub

现在您可以添加或删除 customXML,并且该事件将会触发,但是 officeJS 添加

customXMLPart
的方式有点奇怪。它创建一条空白消息,然后对其进行更改。但事件触发时消息为空。此外,在方法中执行会被冻结,因此在消息非空之前您不能只使用
Application.Wait
。您也不应该从 vba 中删除
CustomXMLPart
,因为这会在 javascript 中引发错误。

您还可以将其与

CustomProperty
结合使用来发送消息,但有注意事项。该值必须介于 1 到 255 个字符之间,0 会导致 OOM 异常,超过 255 的任何内容都将被截断。

我需要这个hacky解决方法从officeJS发送消息来调用一些VBA来执行仅在VBA中可用的功能。由于在事件处理程序完成之前 JavaScript 不会恢复,因此我还可以在同一属性上写一条消息回 OfficeJS 以报告状态或其他内容。

从 VBA 发起通信怎么样?可悲的是,我还没有找到一种非侵入性的方法来做到这一点。

编辑: 有关这些事件的文档非常糟糕,但是

CustomXMLParts.PartAfterLoad
将在填充 XML 后触发。这意味着您可以简化一切,只需监听一个 XML 事件即可将消息发送到 vba。

我在 vba 监视器中包含了一个要点,它将侦听特定名称空间的 xml 消息: https://gist.github.com/mburbea/5300f41173a2eaae477dc4eb7cc69db1

© www.soinside.com 2019 - 2024. All rights reserved.