Создание многопоточного сервера Python COM + нездоровый разбрызгивание VBA - PullRequest
0 голосов
/ 05 июля 2019

Я пытаюсь создать зарегистрированный COM-класс Python, который позволяет обратному вызову в моем основном потоке запускаться таймером в отдельном потоке.По сути, я хочу асинхронно вызывать методы VBA из python (поскольку VBA сама не может делать это очень хорошо).Я, вероятно, делаю какую-то ошибку новичка, но вот код python:

from threading import Timer
import pythoncom
import win32com.client as client
from win32com.server.register import UseCommandLine

class PythonUtilities:
    _public_methods_ = [ "Test", ]
    _reg_progid_ = "PythonDemos.Utilities"
    _reg_clsid_ = "{C1DFDB56-C8B4-4024-A04F-22DF4DEE6C61}" #pythoncom.CreateGuid()
    @staticmethod
    def Test(callbackObj):

        pythoncom.CoInitialize() #IDK!
        callbackRoutine = client.Dispatch(callbackObj).tick
        thread = Timer(1.0, callbackRoutine) #CoInitialize needs to go on this thread surely?
        thread.start()

if __name__== "__main__":
    print("Registering COM server...")
    UseCommandLine(PythonUtilities)

Я запускаю это, делая экземпляр класса PythonUtilities в потоке вызывающей стороны.Этот поток также содержит callbackObj с методом .tick.

Я создаю новый поток с помощью Timer и регистрирую его для вызова метода tick.Однако у меня есть ощущение, что потоку таймера необходимо CoInitialize для загрузки информации COM, необходимой для использования win32com.client.Dispatch object

Я получаю сообщение об ошибке:

File "<COMObject <unknown>>", line 2, in tick
pywintypes.com_error: (-2147221008, 'CoInitialize has not been called.', None, None)

из метода тиков, поэтому я угадываю, какой из тиковых потоков выполняется в CoInitializing.Вот код вызывающего абонента (в VBA, стандартный модуль)

Public callbackObj As Callback 'declare up here so they don't fall out of scope
Public pyTest As Object

Sub test()
    Set pyTest = CreateObject("PythonDemos.Utilities")
    Set callbackObj = New Callback
    On Error Resume Next
    pyTest.test callbackObj 'call the python object asynchronously
    If Err.Number <> 0 Then Debug.Print Err.Description 'print error info if there is any
    Debug.Print "Here"
End Sub

и класс Callback выглядит как

Public Sub tick()
    Debug.Print "Called"
End Sub

, который будет бороться за вызов любого pythoncom.CoInitialize(), но может использоватьapi напрямую, или, надеюсь, я справлюсь с этим на стороне python.Или, может быть, я неправильно диагностировал проблему!


PS Я делаю это в VBA, возможно, это будет аналогичная история в других языках, использующих COM, так что если вы видите, что делатьвместо этого я уверен, что смогу перевести себя позже:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...