在软件开发中,经常需要为Microsoft Office套件(如Excel、Word、PowerPoint和Outlook)扩展功能。通常,Visual Basic for Applications (VBA) 是实现这些扩展的首选语言。然而,随着Python的流行,开发者可能希望使用Python来实现类似的功能。那么,是否有可能创建一个同时支持VBA和Python的库呢?
这种跨平台库的优势显而易见:代码维护更为简单,因为所有代码都在一个项目中。经过一番探索,发现Robert Giesecke的Unmanaged Exports Nuget包是实现这一目标的理想工具。将一些有用的功能打包到DLL中,这可能会为其他人节省宝贵的时间。这个库仍在开发中,如果有任何建议,请在文章下方留言。
要测试这个库,请下载演示文件并解压整个文件夹 "PythonVbaDemo"。
在Excel中测试:打开 "VbaCallDLL.xlsm" 文件。
在Python中测试:使用Visual Studio Code打开 "PythonVbaDemo" 文件夹。
VBA:运行 "VbaTestDllDemo Sub"。
Python:运行 "PythonCallDLL.py" 脚本。
1. 在VBA中的使用
存在两个版本的DLL(32位和64位)。如何让VBA代码自动处理这两个版本,请参考以下代码片段。
Function IsOffice32Bit() As Boolean
' 参考链接:https://docs.microsoft.com/en-us/office/troubleshoot/office-suite-issues/numbering-scheme-for-product-guid
' p => 0=32位, 1=64位
IsOffice32Bit = (Mid(Application.ProductCode, 21, 1) = "0")
End Function
现在可以使用 "更改当前目录" 让VBA知道它应该引用哪个DLL。
Sub ChangeCurDirToDllFolder()
Dim sSubfolderName As String
If IsOffice32Bit() Then
sSubfolderName = "x86"
Else
sSubfolderName = "x64"
End If
ChDir ThisWorkbook.Path & "\" & sSubfolderName
End Sub
以下是VBA可以使用的函数列表:
有三种类型的接口:
对于类型1和2,可以直接在VBA中使用以下声明来调用它们。
#If VBA7 Then
Private Declare PtrSafe Sub Vba_PlotFreeSpaceChart Lib "ExtLib4VbaPython.dll" (ByVal sSpaceCheckPathsInCsv As String, ByVal nMinFreeSpacePercent As Integer)
Private Declare PtrSafe Function Vba_Echo Lib "ExtLib4VbaPython.dll" (ByVal sName As String) As String
Private Declare PtrSafe Function Sum Lib "ExtLib4VbaPython.dll" (ByVal nNum1 As Integer, ByVal nNum2 As Integer) As Integer
' ... 其他声明
#Else
' ... 其他声明
#End If
对于类型3接口,必须使用以下方法来调用它们:
Dim oExtLib As Object
Set oExtLib = InstantiateExtLib("Alarm01.wav")
Debug.Print oExtLib.Vba_Hello(Application.UserName)
Debug.Print oExtLib.MediaFileName
' ... 其他调用
2. 在Python中的使用
以下是Python可以使用的函数列表:
有三种类型的接口:
对于类型1和2,可以直接在Python中使用以下声明来调用它们。
import ctypes
import os
from ctypes import *
from comtypes.automation import VARIANT
full_path = os.path.realpath(__file__)
sPath, sFilename = os.path.split(full_path)
sDllPath = sPath + "\\x64\\ExtLib4VbaPython.dll"
oExtLib = ctypes.cdll.LoadLibrary(sDllPath)
print("3 + 5 = " + str(oExtLib.Sum(3, 5)))
oExtLib.Py_PlotFreeSpaceChart('C:', 10)
对于类型3接口,必须使用以下方法来调用它们:
def Hello(name, oExtLib):
oExtLib.Py_Hello.argtypes = [VARIANT, POINTER(VARIANT)]
v = VARIANT()
oExtLib.Py_Hello(name, v)
return v.value
full_path = os.path.realpath(__file__)
sPath, sFilename = os.path.split(full_path)
sDllPath = sPath + "\\x64\\ExtLib4VbaPython.dll"
oExtLib = ctypes.cdll.LoadLibrary(sDllPath)
print(Hello('Wayne', oExtLib))
在VBA中播放媒体文件可以正常工作,但在Python中不行。如果有人知道原因,请指出,非常感谢。
import ctypes
import os
from ctypes import *
from comtypes.automation import VARIANT
full_path = os.path.realpath(__file__)
sPath, sFilename = os.path.split(full_path)
sDllPath = sPath + "\\x64\\ExtLib4VbaPython.dll"
oExtLib = ctypes.cdll.LoadLibrary(sDllPath)
oExtLib.Py_ReloadMediaFile('')
oExtLib.StartPlayingMediaFile()