【问题标题】:Access VBA <-win32 com server-> python script访问 VBA <-win32 com 服务器-> python 脚本
【发布时间】:2019-10-29 09:14:34
【问题描述】:

我已将示例代码 https://inneka.com/programming/vba/moving-numpy-arrays-from-vba-to-python-and-back/(解决方案 2)复制到 VBA Sub 和 python 脚本中。

import sys, os, win32api, win32com.server.localserver, win32com.server.register 
import numpy as np

class MyModule(object):

  _reg_clsid_ = "{5B4A4174-EE23-4B70-99F9-E57958CFE3DF}"
  _reg_desc_ = "My Python COM Server"
  _reg_progid_ = "Python.MyModule"
  _public_methods_ = ['MyFunction']

  def MyFunction(self, data) :
      arr = np.array(data) + 1
      return arr

def register(*classes) :
    regsz = lambda key, val: win32api.RegSetValue(-2147483647, key, 1, val)
    python_path = 'C:/Program Files (x86)/Python/Python37-32/python.exe'
    server_path = 'C:/Program Files (x86)/Python/Python37-32/Lib/site-packages/win32com/server/localserver.py'

    for cls in classes :
        file_path = sys.modules[cls.__module__].__file__
        class_name = '%s.%s' % (os.path.splitext(os.path.basename(file_path))[0], cls.__name__)
        command = '"%s" "%s" %s' % (python_path, server_path, cls._reg_clsid_)

    regsz("SOFTWARE\\Classes\\" + cls._reg_progid_ + '\\CLSID', cls._reg_clsid_)
    regsz("SOFTWARE\\Classes\\AppID\\" + cls._reg_clsid_, cls._reg_progid_)
    regsz("SOFTWARE\\Classes\\CLSID\\" + cls._reg_clsid_, cls._reg_desc_)
    regsz("SOFTWARE\\Classes\\CLSID\\" + cls._reg_clsid_ + '\\LocalServer32', command)
    regsz("SOFTWARE\\Classes\\CLSID\\" + cls._reg_clsid_ + '\\ProgID', cls._reg_progid_)
    regsz("SOFTWARE\\Classes\\CLSID\\" + cls._reg_clsid_ + '\\PythonCOM', class_name)
    regsz("SOFTWARE\\Classes\\CLSID\\" + cls._reg_clsid_ + '\\PythonCOMPath', os.path.dirname(file_path))
    regsz("SOFTWARE\\Classes\\CLSID\\" + cls._reg_clsid_ + '\\Debugging', "0")

if __name__ == "__main__":
    register(MyModule)

编辑:手动添加了 python_path 和 server_path。

初始化 com 服务器工作正常(只需运行 python 脚本)。 还运行一个返回 1 的简单函数。 当我导入 numpy 时,它在 vba 中崩溃并导致此错误消息:

Error # -2147467259 was generated by Python COM Server Internal Error
Error Line: 0
Unexpected Python Error: Traceback (most recent call last):
  File "C:\Users\*user*\AppData\Local\Continuum\anaconda3\envs\pyApp\lib\site-packages\win32com\server\policy.py", line 136, in CreateInstance
    return retObj._CreateInstance_(clsid, reqIID)
  File "C:\Users\*user*\AppData\Local\Continuum\anaconda3\envs\pyApp\lib\site-packages\win32com\server\policy.py", line 194, in _CreateInstance_
    myob = call_func(classSpec)
  File "C:\Users\*user*\AppData\Local\Continuum\anaconda3\envs\pyApp\lib\site-packages\win32com\server\policy.py", line 728, in call_func
    return resolve_func(spec)(*args)
  File "C:\Users\*user*\AppData\Local\Continuum\anaconda3\envs\pyApp\lib\site-packages\win32com\server\policy.py", line 717, in resolve_func
    module = _import_module(mname)
  File "C:\Users\*user*\AppData\Local\Continuum\anaconda3\envs\pyApp\lib\site-packages\win32com\server\policy.py", line 736, in _import_module
    __import__(mname)
  File "C:/Users/*user*/python/19-10-29_VBA_python\myserver.py", line 4, in <module>
    import numpy as np
  File "C:\Users\*user*\AppData\Local\Continuum\anaconda3\envs\pyApp\lib\site-packages\numpy\__init__.py", line 140, in <module>
    from . import _distributor_init
  File "C:\Users\*user*\AppData\Local\Continuum\anaconda3\envs\pyApp\lib\site-packages\numpy\_distributor_init.py", line 34, in <module>
    from . import _mklinit
ImportError: DLL load failed: Das angegebene Modul wurde nicht gefunden.

编辑:不知道为什么它采用这条路径(这是一个 64 位应用程序)而不是定义的路径:C:\Users\*user*\AppData\Local\Continuum\anaconda3\envs\pyApp\lib\site-packages

【问题讨论】:

  • 首先,您能告诉我们您实际使用的脚本吗?您粘贴的脚本不包含在回溯中可见的 import numpy as np 行。
  • 其次,您能否在尝试 numpy 导入之前向我们展示print(sys.path)print(os.environ['PATH']) 的输出?我认为 COM 上下文中的导入/DLL 解析路径不正确。另一种选择是您尝试在 x86_64(64 位)上下文中加载 x86(32 位)DLL,反之亦然。
  • 您应该将示例简化为 mcve ([SO]: How to create a Minimal, Reproducible Example (reprex (mcve)))。乍一看,这与 VBA 或使用的任何相关包装器没有任何关系。它看起来与 NumPy 密切相关。使用简单的脚本检查它是否可重现 import numpy 尝试将其更新到最新版本 (pip install -upgrade numpy)。
  • @AKX ,编辑了您的第一个提示。其次,打印的输出很长……所以我添加了 python_path 和 server_path。机器上有一个python 32bit和64bit。访问是 32 位的……正如发布的那样,它采用 64 位 python 应用程序的路径。不明白为什么它不能通过使用 py32 应用程序运行脚本来解决。
  • @CristiFati 我试图减少我的例子。我不明白为什么你认为它只是 numpy 相关的。

标签: python ms-access win32com


【解决方案1】:

找不到 Com 服务器的解决方案。 不过还是有办法换的....

python32 设置 Path 是临时的,pyscripts 包含一个项目文件夹

Public Const python32 = "cmd.exe /k @echo off && SET PATH=C:\Program Files (x86)\Python\Python37-32;C:\Program Files (x86)\Python\Python37-32\Scripts && python "

在访问中我运行以下函数:

Public Function RunPython(scriptsubfolder As String, input_args As Variant) As Variant

    Dim oExec As Object, oOutput As Object, oShell As Object
    Dim waitOnReturn As Boolean: waitOnReturn = True
    Dim windowStyle As Integer: windowStyle = 1
    Dim s As String, sLine As String, scmd As String
    Dim i As Integer

    Set oShell = CreateObject("WScript.Shell")

    'define the command string with globalvars
    scmd = python32 & pyscripts & scriptsubfolder

    For i = LBound(input_args) To UBound(input_args)
        scmd = scmd & " " & str(input_args(i))
    Next i

    'execute the shell command
    Set oExec = oShell.Exec(scmd)

    'handle the results as they are written to and read from the StdOut object
    Set oOutput = oExec.StdOut
    While Not oOutput.AtEndOfStream
        sLine = oOutput.ReadLine
        If sLine <> "" Then s = s & sLine & vbCrLf
    Wend

    RunPython = s

End Function

可以触发以下python函数:

import sys

def main(inp1, inp2):
        print(inp1 + inp2)
        print(inp1 * inp2)

if __name__ == '__main__':

    inp1 = int(sys.argv[1])
    inp2 = int(sys.argv[2])

    main(inp1, inp2)

该解决方案运行良好,但遗憾的是我在 cmd 窗口中看不到任何输出。 只有黑屏在等待我关闭窗口。有人对此有解释吗?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-30
    • 2012-07-10
    • 2012-03-25
    • 2015-06-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多