运行ms Access Module子例程的Python代码
我对编程非常陌生,这是我关于stackoverflow的第一个问题。我试图让python打开一个.accdb文件并运行Access中已经定义的子例程。我使用以下代码使用Excel完成此操作:运行ms Access Module子例程的Python代码,python,ms-access,vba,win32com,Python,Ms Access,Vba,Win32com,我对编程非常陌生,这是我关于stackoverflow的第一个问题。我试图让python打开一个.accdb文件并运行Access中已经定义的子例程。我使用以下代码使用Excel完成此操作: import win32com.client xl=win32com.client.Dispatch("Excel.Application") xl.Visible=True xl.Workbooks.Open(Filename="<mydirectory>\\open",ReadOnly=1)
import win32com.client
xl=win32com.client.Dispatch("Excel.Application")
xl.Visible=True
xl.Workbooks.Open(Filename="<mydirectory>\\open",ReadOnly=1)
xl.Application.Run("TestMe")
#...access spreadsheet data...
xl.Workbooks(1).Close(SaveChanges=0)
xl.Application.Quit()
xl=0
运行Python代码会迅速启动Excel,打开文件open.xlsm并显示一个messagebox。到现在为止,一直都还不错。感谢:
我修改了代码,试图通过Access实现同样的功能。我创建了一个名为“testdb”的新.accdb文件,并将上面的子例程“TestMe”复制到VBA模块中。修改后的python代码如下所示:
import win32com.client
xl=win32com.client.Dispatch("Access.Application")
xl.Visible=True
xl.OpenCurrentDatabase("<mydirectory>\\testdb.accdb")
xl.Application.Run("TestMe")
#...access spreadsheet data...
xl.Workbooks(1).Close(SaveChanges=0)
xl.Application.Quit()
xl=0
导入win32com.client
xl=win32com.client.Dispatch(“Access.Application”)
xl.Visible=True
xl.OpenCurrentDatabase(“\\testdb.accdb”)
xl.Application.Run(“TestMe”)
#…访问电子表格数据。。。
xl.工作簿(1).关闭(保存更改=0)
xl.Application.Quit()
xl=0
主要的变化是“Workbooks.Open”已更改为“OpenCurrentDatabase”。我首先试图找到一些更相似的东西,比如“Databases.Open”,但运气不好。运行新代码将启动Access并打开文件testdb.accdb,但仅此而已,不会出现messagebox。我能想象的唯一有趣的控制台输出是:
xl.Application.Run("TestMe")
File "<COMObject <unknown>>", line 14, in Run
result = self._oleobj_.InvokeTypes(*(dispid, LCID, wFlags, retType, argTypes) + args)
pywintypes.com_error: (-2147352567, 'Exception occurred.', (0, None, None, None, 0, -2147352562), None)
xl.Application.Run(“TestMe”)
文件“”,第14行,正在运行
结果=self.\u oleobj.\u.InvokeTypes(*(dispid、LCID、wFlags、retType、argTypes)+args)
pywintypes.com_错误:(-2147352567,‘发生异常’,(0,无,无,无,0,-2147352562),无)
我完全不知所措。任何帮助都将不胜感激 考虑使用调用模块中函数的
RunCode
操作创建一个新的Access宏对象。然后,使用以下方法调用Python的Windows COM API中的宏
宏
Macro
RunCode: TestMe()
注意:只有函数才能使用运行代码
而不是子例程引用,除非您创建了调用子例程的VBA模块函数:调用子例程name
:
Python
import win32com.client
ac = win32com.client.Dispatch("Access.Application")
ac.Visible=True
ac.OpenCurrentDatabase("<mydirectory>\\testdb.accdb")
ac.DoCmd.RunMacro('MacroName')
ac.DoCmd.CloseDatabase
ac = None
导入win32com.client
ac=win32com.client.Dispatch(“Access.Application”)
ac.Visible=True
ac.OpenCurrentDatabase(“\\testdb.accdb”)
ac.DoCmd.RunMacro('MacroName')
ac.DoCmd.CloseDatabase
ac=无
我绝对不是Python专家,但对Access和Excel VBA相当熟悉。如果我在业余编程生涯中更早更好地了解Python,我将永远不会尝试使用任何VBA代码来完成下面的工作。考虑到在VBA代码方面的时间投入,我必须找到一种方法
过去几天/每周,我都在试图找到一种方法,让Python->Access VBA满足以下要求:
- 从Python调用Access VBA函数
- 发送参数以从Python访问VBA函数
- 从Access VBA函数返回值到Python
如果有人知道如何在不使用Excel VBA作为中介的情况下从Python->Access VBA发送参数并向Python返回值,我将非常高兴收到您的来信。或者,使用pythonnet引用clr的方法也会受到同样的赞赏。当您在Access会话中打开
testdb.accdb
并在那里测试您的过程时会发生什么?您是否尝试过完全限定过程名称?HansUp:过程按预期运行,David Zemens:不,我真的不知道这意味着什么。将谷歌和尝试教育自己。谢谢你们的评论!将Sub改为Function,并按照您的建议制作宏,为我解决了这个问题。非常感谢你!而且两者都在C#中工作,所以如果IronPython中不能实现类似的功能,我会感到非常惊讶。。。。事实上,我刚刚确认,与IronPython 2.7.7一起使用时,Excel VBA需要引用Microsoft Access对象库。
import win32com.client
ac = win32com.client.Dispatch("Access.Application")
ac.Visible=True
ac.OpenCurrentDatabase("<mydirectory>\\testdb.accdb")
ac.DoCmd.RunMacro('MacroName')
ac.DoCmd.CloseDatabase
ac = None
from win32com.client import Dispatch
FILELOC = r'C:\Users\Desktop\PyExcel.xlsm'
PROGNAME='Excel.Application'
num = 4
#open excel workbook containing VBA code
#...could do more to ensure excel isn't already running
xl = Dispatch(PROGNAME)
xl.Visible = True
#open excel file containing the VBA code
#...could do more to check if file is already open, etc
xl.Workbooks.Open(Filename=FILELOC)
#call to VBA code within excel
rtrn_int = xl.Run("RunCOMObject", num)
#print return value
print(rtrn_int)
#Quit excel-this doesn't work very well and there are articles about
#Python or the COM object not being able to actually remove Excel
#from the task manager
xl.Quit()
Option Explicit
Private Const ACCESS_FILELOC As String = "C:\Users\Desktop\Test.accdb"
Private Const TEMP_FILELOC As String = "C:\Users\Desktop\TestTemp.accdb"
Function RunCOMObject(intNum As Integer) As Integer
Dim objAcc As Object, objProject As Object
Dim accAppl As Access.Application
Dim MyAppl As String
MyAppl = "Access.Application"
If Not IsRunning(MyAppl) Then 'Access not running, simply start
'up Access and open file
Set accAppl = CreateObject(MyAppl) 'start Access
accAppl.Visible = True
accAppl.OpenCurrentDatabase (ACCESS_FILELOC) 'open file
Else: 'Access is running
On Error Resume Next
Set accAppl = GetObject(, MyAppl) 'assign the running application
'to a variable
On Error GoTo Err_File_Open 'use an error in attempting to rename
'the database of interest to determine if the open file is the
'desired file
Name ACCESS_FILELOC As TEMP_FILELOC 'rename the file of interest
Name TEMP_FILELOC As ACCESS_FILELOC 'file was successfully renamed
'therefore not open
Call NoFileOrOther(accAppl, MyAppl)
End If
Err_File_Open:
'Required Access file is open
RunCOMObject = accAppl.Run("TestLink", intNum) 'run the VBA function in
'Access
accAppl.CloseCurrentDatabase 'close database
accAppl.Quit 'quit Access
Set accAppl = Nothing
End Function
Function IsRunning(ByVal MyAppl As String) As Boolean
Dim applRef As Object
On Error Resume Next 'error occurs if GetObject is unable to find a
'running version of the application
Set applRef = GetObject(, MyAppl) 'attempt to obtain the required
'application object
If Not applRef Is Nothing Then 'if application is already running
Set applRef = Nothing
IsRunning = True
Else 'application is not running
IsRunning = False
End If
Set applRef = Nothing
End Function
Sub NoFileOrOther(accAppl As Access.Application, MyAppl As String)
On Error GoTo Err_No_FileOpen
If accAppl.CurrentProject.Name <> "" Then 'Access active with another a
'different file open
Set accAppl = CreateObject(MyAppl) 'start a new instance of Access
accAppl.Visible = True
accAppl.OpenCurrentDatabase (ACCESS_FILELOC) 'open file
End If
Exit Sub
Err_No_FileOpen:
accAppl.OpenCurrentDatabase (ACCESS_FILELOC) 'in the event of Access
'being active without a database open
End Sub
Option Compare Database
Option Explicit
Function TestLink(intNum As Integer) As Integer
TestLink = intNum + 10
End Function