0

I am trying to build a COM server to get real time information. The problem is that all other functionalities stop while localserver is opened. The rest of the code just runs when the localserver is closed.

I have searched for solutions and failed trying multiprocessing, not because this wouldn't work, I guess because I suck. Anyway, I am stuck in this part.

import pythoncom
import win32com
from win32com.server import localserver
from multiprocessing import Process

class PythonUtilities(object):

    _reg_clsid_      = '{D9C54599-9011-4678-B1EB-A07FD272F0AF}'
    _reg_desc_       = "Change information between programs"
    _reg_progid_     = "Python.LetsTalk"
    _public_attrs_   = ['speech', 'roger']
    _readonly_attrs_ = ['roger']
    _public_methods_ = ['talktome']

    def __init__(self):
        self.roger  = 'roger'
        self.speech = None

    def talktome(self,speech):
        self.speech = speech
        print ('New speech received: ' + self.speech)
        return self.roger

### ___ ###

def runserver(mess):
    print(mess)
    localserver.serve(['{D9C54599-9011-4678-B1EB-A07FD272F0AF}'])

if __name__=='__main__':

     pu = PythonUtilities

     print ("Registering COM Server ")
     win32com.server.register.UseCommandLine(pu)

     # Fine so far.
     # The problem starts here:

     localserver.serve(['{D9C54599-9011-4678-B1EB-A07FD272F0AF}'])

     #... rest of the code waiting for localserver be closed

     # Experiment... Doesnt work:
     #proc = Process(target=runserver, args = ('starting process',))
     #proc.start()
     #proc.join()

It's important to say that all messages sent from the client seem to be correctly displayed BUT ONLY AFTER I close the local server manually. I want to receive it in real time like a chat app. I mean, I want to keep the localserver opened and being able to work with the information received along the rest of the code.

  • You're not supposed to register and serve at the same time as an out-of-process server will be started by pythonw.exe when requested. So first register your server and just do nothing more. See an example here: https://stackoverflow.com/questions/1054849/consuming-python-com-server-from-net – Simon Mourier Nov 12 '18 at 08:53
  • @SimonMourier, I have already seen this post. Notice that the Rob's answer marked as solved. He explains that ...register.UseCommandLine() only registers a piece of code so much so that it can be accessed even when the server application is closed. Therefore, I need to keep this server running because I need to listen the client. That's why the ...localserver.serve (). And It works. The problem is that when I run the server, everything else waits the server's process ends. Just when I close the server's window manually the code above prints all the client's "speech". It should be real time. – Eric Trevisani Nov 12 '18 at 19:12
  • I understood your question and I pointed to this answer precisely because it explains how to do it. You don't have to run your server and wait for something. You run it manually only for register and unregister. After than, it will be started by pythonw.exe when someone accesses it. – Simon Mourier Nov 13 '18 at 08:31
  • @SimonMourier, yes. You are right. There is no need... register.UseCommandLine() ...localserver.serve() does it. Afterwards, I got a solution rewriting the localserver.serve() function and starting it in a new thread. – Eric Trevisani Nov 14 '18 at 03:03

1 Answers1

0

My problem was solved rewriting the localserver.serve() function and starting it in a new thread as the code below.

import pythoncom
from win32com.client import Dispatch # to get attributes
from win32com.server import register, factory
from threading import Thread
from queue import Queue

class PythonUtilities(object):

    _reg_clsid_      = '{D9C54599-9011-4678-B1EB-A07FD272F0AF}'
    _reg_desc_       = "Change information between programs"
    _reg_progid_     = "Python.LetsTalk"
    _public_attrs_   = ['speech']
    _public_methods_ = ['talktome']

    queue_speech = Queue()

    def talktome(self,speech):
        self.queue_speech.put(speech)
        print ('New speech received: ' + speech)
        return 'roger'

### ___ ###

# use instead localserver.serve()
def runserver():

    # added - multithread support
    pythoncom.CoInitialize()

    clsids = ['{D9C54599-9011-4678-B1EB-A07FD272F0AF}']

    infos = factory.RegisterClassFactories(clsids)

    # commented - from original localserver.serve() method
    #pythoncom.EnableQuitMessage(win32api.GetCurrentThreadId())  

    pythoncom.CoResumeClassObjects()

    pythoncom.PumpMessages()

    factory.RevokeClassFactories( infos )

    pythoncom.CoUninitialize()

 if __name__=='__main__':

    #use this
    server_thread = Thread(target=runserver) # Process works as well
    server_thread.start()

    #instead this     
    #localserver.serve(['{D9C54599-9011-4678-B1EB-A07FD272F0AF}'])

    #... rest of the code now works in parallel

Also I have made some improvements like Queue to get data later. I hope it can help others.