使用wsh从vba调用python脚本

3
我需要通过使用Shell从VBA调用Python脚本,这样可以正常工作。
Sub CallPythonScript()

        Call Shell("C:\Program Files (x86)\Python27\python.exe C:\Users\Markus\BrowseDirectory.py")

End Sub

但是当我尝试使用wsh(因为它具有等待功能)时,它就无法正常工作了。

Sub CallPythonScript()

    Dim wsh As Object
        Set wsh = VBA.CreateObject("WScript.Shell")

    Dim myApp As String: myApp = "C:\Program Files (x86)\Python27\python.exe C:\Users\Markus\BrowseDirectory.py"
    Dim waitOnReturn As Boolean: waitOnReturn = True
    Dim windowStyle As Integer: windowStyle = 1

    wsh.Run """"" & myApp & """"", windowStyle, waitOnReturn

End Sub

然而,我在家使用相同的代码,一切都很顺利,唯一的区别是路径中没有任何空格。因此,很自然地认为问题出在空格上。非常感谢您的帮助。


我怀疑它从未使用过该路径:您的路径中有空格。 wsh.Run如何知道如何解析参数?在家里,您肯定将Python安装在“C:\ python27”中。 - Jean-François Fabre
没错,这就是我所说的“路径中没有空格”的意思。 - Billi B
4个回答

2

如果你不使用引号来保护包含空格的目录,解释器就无法区分它们和真正的参数。

一个更好的解决方案是使用Python将 .py 扩展名与已安装的Python解释器相关联。

只需要像运行 .bat 文件一样执行以下操作:

Dim myApp As String: myApp = "C:\Users\Markus\BrowseDirectory.py"

只要安装了Python,您的代码就可以在任何地方运行(空格问题也会消失)。

这个小测试在Excel中对我有效,并且运行了pycrust.py,它恰好在我的系统PATH中:

Sub foo()
  Dim wsh As Object
  Set wsh = VBA.CreateObject("WScript.Shell")

    Dim myApp As String: myApp = "pycrust.py"
    Dim waitOnReturn As Boolean: waitOnReturn = True
    Dim windowStyle As Integer: windowStyle = 1

    wsh.Run myApp, windowStyle, waitOnReturn

End Sub

我不得不简化你的wsh.Run代码行,因为它不能正常工作,我怀疑你添加的256个引号没有起到任何好处。


谢谢您的回答。不幸的是,两个版本都对我无效。使用第一种方法,我会得到错误429 ActiveX组件无法创建对象。第二种方法会导致对象iwshshell3的方法运行失败的错误。 - Billi B

1

请问您确认该路径是否直接通往解释器?

可以尝试以下方法:

Dim myApp As String: myApp = "C:\""Program Files (x86)""\Python27\python.exe C:\Users\Markus\BrowseDirectory.py"

是的,路径本身是正确的。问题在于路径中的空格。不幸的是,你的解决方案对我没有起作用。 - Billi B
这个应该可以。还有另一种方法,"C:\" & chr(34) & "Program Files (x86)" & chr(34) & "\Python27\python.exe C:\Users\Markus\BrowseDirectory.py" 这样行吗? - Jimmy Smith
此外,使用我的更改,wsh.Run myApp, windowStyle, waitOnReturn 就足够了。 - Jimmy Smith

0

我的脚本在我的表格和Python中都能工作(但我把表格和py脚本放在同一个文件夹中):

Path = ActiveWorkbook.Path
Pth = """" & Path & "\pythonscript_name.py" & """"
Ph = """" & "C:\Python27\python.exe " & Pth & """"

Dim wsh As Object
Set wsh = VBA.CreateObject("WScript.Shell")
Dim waitOnReturn As Boolean: waitOnReturn = True
Dim windowStyle As Integer: windowStyle = 1
ErrorCode = wsh.Run(Ph, windowStyle, waitOnReturn)

0

我不知道这是否能解决你的问题,但当我尝试使用CX-Freeze(从VBA和wsh)启动“frozen”Python脚本时,遇到了相同的问题。一切都很顺利,直到我将EXE文件夹更名为带空格的名称。在阅读您的帖子并提到空格后,我才明白问题所在。

我在互联网上找到了一个函数(也许是在SO上),它可以给我DOS中文件夹的名称。如果像我一样,您必须传递一些参数作为文件夹名称,则可以重复使用该函数以在DOS中获取名称。

以下是在互联网上找到的函数:

Public Function GetShortFileName(ByVal FullPath As String) As String

'PURPOSE: Returns DOS File Name (8.3 Format) Give
'FullPath for long file name

'PARAMETERS: FullPath: Full Path of Original File

'RETURNS: 8.3 FileName, or "" if FullPath doesn't
'         exist or file fails for other reasons

'EXAMPLE:
'  GetShortFileName("C:\Nouveau dossier\Nouveau dossier\Nouveau 
dossier\Nouveau dossier\Nouveau dossier\")


Dim lAns As Long
Dim sAns As String
Dim iLen As Integer

On Error Resume Next

'this function doesn't work if the file doesn't exist
If Dir(FullPath) = "" Then Exit Function

sAns = Space(255)
lAns = GetShortPathName(FullPath, sAns, 255)
GetShortFileName = Left(sAns, lAns)

End Function

以下是如何创建子程序的方法:

Dim wsh As Object
Set wsh = VBA.CreateObject("WScript.Shell")
Dim waitOnReturn As Boolean: waitOnReturn = True
Dim windowStyle As Integer: windowStyle = 1
Dim program_folder_path
Dim file_path

program_folder_path = "C:\Program Files (x86)\Python27\"
program_folder_path = CStr(GetShortFileName(program_folder_path))

file_path = "C:\Users\Markus\BrowseDirectory.py"
file_path = CStr(GetShortFileName(file_path))

wsh.Run program_folder_path & "python.exe" & file_path, windowStyle,_
waitOnReturn

希望这能有所帮助,顺便说一下,我的英语不太好...


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接