Python 运行 ms-Access 模块子例程的代码
Python code for running ms-Access Module Subroutine
我是编程新手,这是我关于 Whosebug 的第一个问题。我试图让 python 打开一个 .accdb 文件和 运行 一个已经在 Access 中定义的子例程。我设法用 Excel 使用此代码来做到这一点:
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
Sub TestMe 看起来像这样:
Sub TestMe()
MsgBox "Hi there"
End Sub
运行 Python 代码会立即启动 Excel,打开文件 open.xlsm 并显示一个消息框。到目前为止,一切都很好。感谢:Need skeleton code to call Excel VBA from PythonWin
我修改了代码以尝试使用 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
主要变化是"Workbooks.Open"改为"OpenCurrentDatabase"。我首先尝试找到更相似的东西,比如 "Databases.Open",但没有成功。 运行 新代码启动 Access 并打开文件 testdb.accdb,但仅此而已,没有出现消息框。我能想到的唯一有趣的控制台输出是:
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)
我很茫然。任何帮助将不胜感激!
考虑使用调用模块中函数的 RunCode
操作创建一个新的 Access 宏对象。然后,使用 DoCmd.RunMacro 方法调用 Python 的 Windows COM API 中的宏。
宏观
Macro
RunCode: TestMe()
注意:除非您创建一个调用子例程的 VBA 模块函数,否则只能用 RunCode
引用函数而不是子例程:Call SubroutineName
:
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
我绝不是 Python 方面的专家,但对 Access 和 Excel VBA 相当熟悉。如果我在我的业余编程生涯中更早地了解 Python,我将永远不会尝试使用任何 VBA 代码来完成我下面打算做的事情。考虑到在 VBA 代码上投入的时间,我必须找到一种方法....
我花了最后几个 days/week 试图找到一种方式来交谈 Python->Access VBA 满足以下要求:
- 从 Python
调用 Access VBA 函数
- 从 Python
向 Access VBA 函数发送参数
- return 值从 Access VBA 函数到 Python
我尝试使用 pythonnet 和 IronPython 使用 clr,发现越来越多的混乱和不清楚的错误消息和异常。我尝试了上面建议的 DoCmd.RunMacro 方法,但 Access 宏没有 return 值。尝试了一个名为数据宏的新(ish)版本的 Access 宏(2010),它确实有一个名为 SetReturnVar 的操作,但它们不会与 VBA 对话,除非通过更传统的宏,正如我上面提到的,传统宏不会return 值。今天仔细看了一些微软的文档(访问Application.Run方法):
Access Application.Run method
我不完全了解该声明的含义 "you can't set a reference to an individual Microsoft Access database from any application other than Microsoft Access" 但我想到很多 Python<->Office 应用程序文章在讨论时似乎更成功 Python<->ExcelVBA。我的理由是因为我过去能够 运行 Excel VBA <-> 访问 VBA 如果 Python <-> Excel VBA 工作得和我读过的一样好,然后一个解决方案(尽管很复杂)似乎是可能的(我认为合适的程序员称之为 hack)。
经过大约 1.5 小时的 cutting/pasting 代码片段和调试:
Python
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()
Excel VBA
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
访问VBA
这是一个完全微不足道的示例,掩盖了我已经在 Access VBA 中编写的代码量以保证此解决方法,但它用于演示方法
Option Compare Database
Option Explicit
Function TestLink(intNum As Integer) As Integer
TestLink = intNum + 10
End Function
Python 输出:
14
成功!!!!该数字最初在 Python 中是 4,并作为参数发送到 Excel 和 Access,在通过 Excel 编辑到 [=56 之前,它在其中添加了 10 个=] 打印(rtrn_int) = 14.
如果有人知道如何明确地(即通过上面演示的类似严谨性)从 Python 发送参数 -> 访问 VBA 和 return 一个值到 Python 而不使用 Excel VBA 作为中介,我很高兴收到您的来信。使用 pythonnet 引用 clr 的替代方法将同样受到赞赏。
我是编程新手,这是我关于 Whosebug 的第一个问题。我试图让 python 打开一个 .accdb 文件和 运行 一个已经在 Access 中定义的子例程。我设法用 Excel 使用此代码来做到这一点:
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
Sub TestMe 看起来像这样:
Sub TestMe()
MsgBox "Hi there"
End Sub
运行 Python 代码会立即启动 Excel,打开文件 open.xlsm 并显示一个消息框。到目前为止,一切都很好。感谢:Need skeleton code to call Excel VBA from PythonWin
我修改了代码以尝试使用 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
主要变化是"Workbooks.Open"改为"OpenCurrentDatabase"。我首先尝试找到更相似的东西,比如 "Databases.Open",但没有成功。 运行 新代码启动 Access 并打开文件 testdb.accdb,但仅此而已,没有出现消息框。我能想到的唯一有趣的控制台输出是:
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)
我很茫然。任何帮助将不胜感激!
考虑使用调用模块中函数的 RunCode
操作创建一个新的 Access 宏对象。然后,使用 DoCmd.RunMacro 方法调用 Python 的 Windows COM API 中的宏。
宏观
Macro
RunCode: TestMe()
注意:除非您创建一个调用子例程的 VBA 模块函数,否则只能用 RunCode
引用函数而不是子例程:Call SubroutineName
:
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
我绝不是 Python 方面的专家,但对 Access 和 Excel VBA 相当熟悉。如果我在我的业余编程生涯中更早地了解 Python,我将永远不会尝试使用任何 VBA 代码来完成我下面打算做的事情。考虑到在 VBA 代码上投入的时间,我必须找到一种方法....
我花了最后几个 days/week 试图找到一种方式来交谈 Python->Access VBA 满足以下要求:
- 从 Python 调用 Access VBA 函数
- 从 Python 向 Access VBA 函数发送参数
- return 值从 Access VBA 函数到 Python
我尝试使用 pythonnet 和 IronPython 使用 clr,发现越来越多的混乱和不清楚的错误消息和异常。我尝试了上面建议的 DoCmd.RunMacro 方法,但 Access 宏没有 return 值。尝试了一个名为数据宏的新(ish)版本的 Access 宏(2010),它确实有一个名为 SetReturnVar 的操作,但它们不会与 VBA 对话,除非通过更传统的宏,正如我上面提到的,传统宏不会return 值。今天仔细看了一些微软的文档(访问Application.Run方法):
Access Application.Run method
我不完全了解该声明的含义 "you can't set a reference to an individual Microsoft Access database from any application other than Microsoft Access" 但我想到很多 Python<->Office 应用程序文章在讨论时似乎更成功 Python<->ExcelVBA。我的理由是因为我过去能够 运行 Excel VBA <-> 访问 VBA 如果 Python <-> Excel VBA 工作得和我读过的一样好,然后一个解决方案(尽管很复杂)似乎是可能的(我认为合适的程序员称之为 hack)。
经过大约 1.5 小时的 cutting/pasting 代码片段和调试:
Python
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()
Excel VBA
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
访问VBA
这是一个完全微不足道的示例,掩盖了我已经在 Access VBA 中编写的代码量以保证此解决方法,但它用于演示方法
Option Compare Database
Option Explicit
Function TestLink(intNum As Integer) As Integer
TestLink = intNum + 10
End Function
Python 输出:
14
成功!!!!该数字最初在 Python 中是 4,并作为参数发送到 Excel 和 Access,在通过 Excel 编辑到 [=56 之前,它在其中添加了 10 个=] 打印(rtrn_int) = 14.
如果有人知道如何明确地(即通过上面演示的类似严谨性)从 Python 发送参数 -> 访问 VBA 和 return 一个值到 Python 而不使用 Excel VBA 作为中介,我很高兴收到您的来信。使用 pythonnet 引用 clr 的替代方法将同样受到赞赏。