Jul-23-2021, 11:52 PM
I'm trying to implement a COM server that will expose some methods, in order to link a third-party API with a PyQt application. The application is a grammar tool called Antidote. The server was registered successfully, but then I need to instantiate it and pass its object to Antidote's API. Thus;
Full code below;
def _connect(self): self.server = win32com.client.Dispatch("Correcteur.Antidote") # , clsctx=pythoncom.CLSCTX_LOCAL_SERVER) self.antidote = win32com.client.Dispatch("Antidote.ApiOle") self.antidote.LanceOutilDispatch2(self.server, "C", "", "2.0") # Server, outil, langue, version APIIt successfully find the COM object in registry with the provided progid (Correcteur.Antidote), but it crash with a bunch of gibberish errors;
Error:Microsoft Windows [Version 6.1.7601]
Copyright (c) 2009 Microsoft Corporation. All rights reserved.
C:\Users\user>"C:\Users\user\Desktop\AntidoteCOM.py - Shortcut.lnk"
pythoncom error: ERROR: server.policy could not create an instance.
Traceback (most recent call last):
File "C:\Users\user\AppData\Local\Programs\Python\Python38\lib\site-packages\win32com\server\policy.py", line 136, in CreateInstance
return retObj._CreateInstance_(clsid, reqIID)
File "C:\Users\user\AppData\Local\Programs\Python\Python38\lib\site-packages\win32com\server\policy.py", line 194, in _CreateInstance_
myob = call_func(classSpec)
File "C:\Users\user\AppData\Local\Programs\Python\Python38\lib\site-packages\win32com\server\policy.py", line 728, in call_func
return resolve_func(spec)(*args)
TypeError: __init__() missing 1 required positional argument: 'parent'
pythoncom error: Unexpected gateway error
Traceback (most recent call last):
File "C:\Users\user\AppData\Local\Programs\Python\Python38\lib\site-packages\win32com\server\policy.py", line 136, in CreateInstance
return retObj._CreateInstance_(clsid, reqIID)
File "C:\Users\user\AppData\Local\Programs\Python\Python38\lib\site-packages\win32com\server\policy.py", line 194, in _CreateInstance_
myob = call_func(classSpec)
File "C:\Users\user\AppData\Local\Programs\Python\Python38\lib\site-packages\win32com\server\policy.py", line 728, in call_func
return resolve_func(spec)(*args)
TypeError: __init__() missing 1 required positional argument: 'parent'
pythoncom error: CPyFactory::CreateInstance failed to create instance. (80004005)
Traceback (most recent call last):
File "C:\Users\user\AppData\Local\Programs\Python\Python38\lib\site-packages\win32com\client\dynamic.py", line 81, in _GetGoodDispatch
IDispatch = pythoncom.connect(IDispatch)
pywintypes.com_error: (-2147221021, 'Operation unavailable', None, None)
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "Z:\.antidote_\AntidoteCOM.py", line 44, in _connect
self.server = win32com.client.Dispatch("Correcteur.Antidote") # , clsctx=pythoncom.CLSCTX_LOCAL_SERVER)
File "C:\Users\user\AppData\Local\Programs\Python\Python38\lib\site-packages\win32com\client\__init__.py", line 95, in Dispatch
dispatch, userName = dynamic._GetGoodDispatchAndUserName(dispatch,userName,clsctx)
File "C:\Users\user\AppData\Local\Programs\Python\Python38\lib\site-packages\win32com\client\dynamic.py", line 98, in _GetGoodDispatchAndUserName
return (_GetGoodDispatch(IDispatch, clsctx), userName)
File "C:\Users\user\AppData\Local\Programs\Python\Python38\lib\site-packages\win32com\client\dynamic.py", line 83, in _GetGoodDispatch
IDispatch = pythoncom.CoCreateInstance(IDispatch, None, clsctx, pythoncom.IID_IDispatch)
pywintypes.com_error: (-2147467259, 'Unspecified error', None, None)
From some examples I've seen, I tried to run the server beforehand in another thread, but the same error remains.def run(self): pythoncom.CoInitialize() localserver.serve(['{D390AE78-D6A2-47CF-B462-E4F2DC9C70F5}']) # ##I suppose something is wrong in my COM object class (AdapteurAntidote) ?
Full code below;
#!/usr/bin/python3 import pythoncom import winreg import win32com.client import win32com.server.register from win32com.server import localserver from pathlib import Path from PyQt5 import QtCore, QtWidgets class MainWindow(QtWidgets.QMainWindow): def __init__(self): super().__init__() self.body = QtWidgets.QTextEdit("Texte à corrigée.") self.setCentralWidget(self.body) self.antidote = ImplementationAntidote(self, self.body) class ImplementationAntidote(QtCore.QObject): def __init__(self, parent: QtCore.QObject, body: QtWidgets.QTextEdit): super().__init__() self.parent = parent self.body = body # self._register() self._launch() self.worker = WorkerThread() self.workerThread = QtCore.QThread() self.workerThread.started.connect(self.worker.run) self.worker.moveToThread(self.workerThread) self.workerThread.start() QtCore.QTimer.singleShot(3000, self._connect) @staticmethod def hkey(path: str, name: str): registry_key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, path, 0, winreg.KEY_READ) value, regtype = winreg.QueryValueEx(registry_key, name) winreg.CloseKey(registry_key) return value def _connect(self): self.server = win32com.client.Dispatch("Correcteur.Antidote") # , clsctx=pythoncom.CLSCTX_LOCAL_SERVER) # ## Crash self.antidote = win32com.client.Dispatch("Antidote.ApiOle") self.antidote.LanceOutil2(self.server, "C", "", "2.0") # Server, outil, langue, version API def _launch(self): # antidoteAPI = self.hkey(r"Software\Druide informatique inc.\Antidote", "VersionAPI") antidoteFolder = self.hkey(r"Software\Druide informatique inc.\Antidote", "DossierAntidote") antidotePath = Path(antidoteFolder) / "Antidote.exe" QtCore.QProcess.startDetached(str(antidotePath), ["-activex"]) def _register(self): win32com.server.register.UseCommandLine(AdapteurAntidote) class WorkerThread(QtCore.QObject): def __init__(self): super().__init__() def run(self): pythoncom.CoInitialize() localserver.serve(['{D390AE78-D6A2-47CF-B462-E4F2DC9C70F5}']) # ## class AdapteurAntidote: _reg_clsctx_ = pythoncom.CLSCTX_LOCAL_SERVER # https://msdn.microsoft.com/en-us/library/windows/desktop/ms693716(v=vs.85).aspx _reg_clsid_ = "{D390AE78-D6A2-47CF-B462-E4F2DC9C70F5}" # pythoncom.CreateGuid() _reg_progid_ = "Correcteur.Antidote" _public_methods_ = ["ActiveApplication", "ActiveDocument", "DonneDebutSelection", "DonneFinSelection", "DonneIdDocumentCourant", "DonneIdZoneDeTexte", "DonneIdZoneDeTexteCourante", "DonneIntervalle", "DonneLongueurZoneDeTexte", "DonneNbZonesDeTexte", "DonnePolice", "DonneTitreDocCourant", "RemplaceIntervalle", "SelectionneIntervalle"] _public_attrs_ = [] _reg_verprogid_ = "Correcteur.Antidote.1" _reg_class_spec_ = "AntidoteCOM.AdapteurAntidote" def __init__(self, parent): super().__init__() self.parent = parent def DonneIdDocumentCourant(self): raise NotImplementedError def DonneIdZoneDeTexte(self): raise NotImplementedError def DonneIdZoneDeTexteCourante(self): raise NotImplementedError def DonneIntervalle(self): raise NotImplementedError def DonneLongueurZoneDeTexte(self): raise NotImplementedError def DonneNbZonesDeTexte(self): raise NotImplementedError def DonnePolice(self): raise NotImplementedError def DonneTitreDocCourant(self): raise NotImplementedError def RemplaceIntervalle(self): raise NotImplementedError def ActiveDocument(self): self.parent.activeDocument() def ActiveApplication(self): self.parent.activeDocument() def DonneDebutSelection(self) -> int: return self.parent.donneDebutSelection() def DonneFinSelection(self) -> int: return self.parent.donneFinSelection() def SelectionneIntervalle(self, debut: int, fin: int): self.parent.selectionneIntervalle(debut, fin) if __name__ == '__main__': app = QtWidgets.QApplication([]) gui = MainWindow() gui.show() app.exec()