Quantcast

Questions about deploying COM server via py2exe

classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Questions about deploying COM server via py2exe

Kevin Walzer-7
Hi all,

I'm working on a Tkinter app that is being deployed to Windows via py2exe for wrapping and InnoSetup for its installer. In order to provide a similar scripting capability to the app that is present in its Mac version, I've made the app a COM server using the examples from python-win32 code base. 

I am running into two issues with the app that I would like some clarification on:

1. What is the best way to register the exe as a COM server? I'm using the code from the python-win32 extension to register the code dynamically, but on Windows 7 this requires administrator privileges--which means that the entire app must be run as an administrator (via a flag in py2exe). This works, but seems overkill. I understand from the list archives that there is no current built-in way to escalate UAC privileges for a single function, cf. to register the server. Is there another way to register the wrapped exe as a server, i.e. from the command line (regsvr32) during the installation phase? 

2. I am testing the app via a simple vbscript with a create object() call and then running the command exported by the COM server. While my app launches, it blocks forever, and then eventually the Windows Scripting Host times out with an error ("couldn't create ActiveX object"). Any suggestions on how to debug this? I can find no obvious error in my code and the app does start up successfully, which tells me it's registered, but for some reason it locks up before it can run its command. (The app does pop up a dialog on startup, I don't know if that would have any effect or not.)

Thanks,
Kevin 

_______________________________________________
python-win32 mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/python-win32
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Questions about deploying COM server via py2exe

Matteo Boscolo
Hi Kevin ,

Il 18/08/2011 17:10, Kevin Walzer ha scritto:
Hi all,

I'm working on a Tkinter app that is being deployed to Windows via py2exe for wrapping and InnoSetup for its installer. In order to provide a similar scripting capability to the app that is present in its Mac version, I've made the app a COM server using the examples from python-win32 code base. 

I am running into two issues with the app that I would like some clarification on:

1. What is the best way to register the exe as a COM server? I'm using the code from the python-win32 extension to register the code dynamically, but on Windows 7 this requires administrator privileges--which means that the entire app must be run as an administrator (via a flag in py2exe). This works, but seems overkill. I understand from the list archives that there is no current built-in way to escalate UAC privileges for a single function, cf. to register the server. Is there another way to register the wrapped exe as a server, i.e. from the command line (regsvr32) during the installation phase?
For registering the com server we use innosetup with the following line
[Run]
Filename: "{app}\openclerk.exe"; Parameters: "/regserver"; WorkingDir: "{app}" ; StatusMsg: "Registering openclerk.exe ..."

2. I am testing the app via a simple vbscript with a create object() call and then running the command exported by the COM server. While my app launches, it blocks forever, and then eventually the Windows Scripting Host times out with an error ("couldn't create ActiveX object"). Any suggestions on how to debug this?

usually you get this error because you miss some reference into py2exe
the way that we use to trace this error is to try catch all com method even the __init__ and use the logging system:

here you get an example:

    def SetIntegration(self, integrationObject, activeEditor=""):
        """
            set the integration object
        """
        try:
         
        except:
            print_exc_plus()
            return E_FAIL
        return S_O

def print_exc_plus():
    """
        Print the usual traceback information, followed by a listing of
        all the local variables in each frame.
    """
    logging.error("*"*20)
    for m in sys.exc_info():
        logging.error(str(m))
    logging.error("*"*20)
    tb = sys.exc_info( )[2]
    while tb.tb_next:
        tb = tb.tb_next
    stack = [  ]
    f = tb.tb_frame
    while f:
        stack.append(f)
        f = f.f_back
    stack.reverse( )
    traceback.print_exc()
    logging.error( "Locals by frame, innermost last")
    for frame in stack:
        logging.error("Frame %s in %s at line %s" % (frame.f_code.co_name,
                                             frame.f_code.co_filename,
                                             frame.f_lineno))
        for key, value in frame.f_locals.items():
            # we must _absolutely_ avoid propagating exceptions, and str(value)
            # COULD cause any exception, so we MUST catch any...:
            try:
                logging.error("\t%20s = %s"%(key ,str(value)))
            except:
                logging.error( "<ERROR WHILE PRINTING VALUE>")


Regards,
Matteo

I can find no obvious error in my code and the app does start up successfully, which tells me it's registered, but for some reason it locks up before it can run its command. (The app does pop up a dialog on startup, I don't know if that would have any effect or not.)

Thanks,
Kevin 


_______________________________________________
python-win32 mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/python-win32


Nessun virus nel messaggio.
Controllato da AVG - www.avg.com
Versione: 10.0.1392 / Database dei virus: 1520/3841 - Data di rilascio: 17/08/2011



_______________________________________________
python-win32 mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/python-win32
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Questions about deploying COM server via py2exe

Kevin Walzer-7
For registering the com server we use innosetup with the following line
[Run]
Filename: "{app}\openclerk.exe"; Parameters: "/regserver"; WorkingDir: "{app}" ; StatusMsg: "Registering openclerk.exe ..."
 
---
I’ve used a variation of this techinque, it seems to work fine. Thanks.
usually you get this error because you miss some reference into py2exe
the way that we use to trace this error is to try catch all com method even the __init__ and use the logging system:
----
I haven’t been able to figure out how to integrate your example into my own code. The COM/py2exe integration is wholly opaque to me. Here is my code, can you or anyone else suggest what I might be doing wrong?
 
from quickwho_main import quickwhoApp
import time
import tempfile
from win32com.server.exception import COMException
import winerror
import win32com.server.register
 
#expose basic functionality to COM
class QuickWho_Domain:
  _public_methods_ = ['GetDomain']
  _reg_progid_ = 'QuickWho.Application'
  _reg_clsid_= '{9F825846-F10B-47DD-91E8-88DA93C1A05E}'
 
  def GetDomain(self, domain):
      try:
         app.searchfield.delete(0, 'end')
         app.searchfield.insert(0, str(domain))
         app.getInfo()
         time.sleep(1)
         alltext=app.getData()
         tempfile = tempfile.gettempdir()+ '/urltext.txt'
         data = open(tempfile, 'r')
         finaltext = data.read()
         data.close()      
         return finaltext
      except:
          raise COMException(desc='Unable to retrieve domain data',
                            scode=winerror.E_FAIL)
 
try:
  win32com.server.register.RegisterClasses(QuickWho_Domain)
except:
  pass
 
app = quickwhoApp(None)
app.mainloop()
 
The idea is to use the COM method (GetDomain) to drive the app’s UI (which in turn fires to external executables via subprocess), parse the data, display it in the GUI , and then return the data to the calling application. Is this how COM is supposed to work? This is how the app works on the Mac in responding to AppleScript calls. Perhaps it’s not the right mechanism for Windows, although I don’t know of a better one that can be accessed from the MS desktop scripting languages, cf. VBScript.
 
Suggestions are appreciated. I’m about to give up on this, as I can’t grok it.
 
--Kevin

_______________________________________________
python-win32 mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/python-win32
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Questions about deploying COM server via py2exe

Matteo Boscolo
Hi Kevin,
run this script and it will be registered for debug ..

run the win32traceutil.py as mentioned in the following link :
http://www.boscolini.eu/Boscolini/index.php?option=com_content&view=article&id=62%3Apython-win32debug-tutorial&catid=38%3Aprogramming&Itemid=55&lang=en

now you get the trace in the win32traceutil.py .. so you can use print to debug your code

I do not know what the quickwhoApp dose, but I think that if you call the mainloop method all the events are stopped there so you are not able to access other method ..
if you send me the code I can give a look at ..


Regards,
Matteo


from quickwho_main import quickwhoApp
import time
import tempfile
from win32com.server.exception import COMException
import winerror
import win32com.server.register
 
#expose basic functionality to COM
class QuickWho_Domain:
  _public_methods_ = ['GetDomain']
  _reg_progid_ = 'QuickWho.Application'
  _reg_clsid_= '{9F825846-F10B-47DD-91E8-88DA93C1A05E}'


  def GetDomain(self, domain):
      try:
         app.searchfield.delete(0, 'end')
         app.searchfield.insert(0, str(domain))
         app.getInfo()
         time.sleep(1)
         alltext=app.getData()
         tempfile = tempfile.gettempdir()+ '/urltext.txt'
         data = open(tempfile, 'r')
         finaltext = data.read()
         data.close()     
         return finaltext
      except Exception ,ex:
          exMsg='Unable to retrieve domain data '+str(ex)
          raise COMException(desc=exMsg,
                            scode=winerror.E_FAIL)

if __name__=="__main__":
    print "*"*20
    import sys
    import win32com.server.register
    sys.argv.append('--debug')
    win32com.server.register.UseCommandLine(QuickWho_Domain)
    print "*"*20

try:
    app = quickwhoApp(None)
    app.mainloop()
except Exception ,ex:
    print "error !! " + str(ex)

Il 20/08/2011 05:29, Kevin Walzer ha scritto:
For registering the com server we use innosetup with the following line
[Run]
Filename: "{app}\openclerk.exe"; Parameters: "/regserver"; WorkingDir: "{app}" ; StatusMsg: "Registering openclerk.exe ..."
 
---
I’ve used a variation of this techinque, it seems to work fine. Thanks.
usually you get this error because you miss some reference into py2exe
the way that we use to trace this error is to try catch all com method even the __init__ and use the logging system:
----
I haven’t been able to figure out how to integrate your example into my own code. The COM/py2exe integration is wholly opaque to me. Here is my code, can you or anyone else suggest what I might be doing wrong?
 
from quickwho_main import quickwhoApp
import time
import tempfile
from win32com.server.exception import COMException
import winerror
import win32com.server.register
 
#expose basic functionality to COM
class QuickWho_Domain:
  _public_methods_ = ['GetDomain']
  _reg_progid_ = 'QuickWho.Application'
  _reg_clsid_= '{9F825846-F10B-47DD-91E8-88DA93C1A05E}'
 
  def GetDomain(self, domain):
      try:
         app.searchfield.delete(0, 'end')
         app.searchfield.insert(0, str(domain))
         app.getInfo()
         time.sleep(1)
         alltext=app.getData()
         tempfile = tempfile.gettempdir()+ '/urltext.txt'
         data = open(tempfile, 'r')
         finaltext = data.read()
         data.close()      
         return finaltext
      except:
          raise COMException(desc='Unable to retrieve domain data',
                            scode=winerror.E_FAIL)
 
try:
  win32com.server.register.RegisterClasses(QuickWho_Domain)
except:
  pass
 
app = quickwhoApp(None)
app.mainloop()
 
The idea is to use the COM method (GetDomain) to drive the app’s UI (which in turn fires to external executables via subprocess), parse the data, display it in the GUI , and then return the data to the calling application. Is this how COM is supposed to work? This is how the app works on the Mac in responding to AppleScript calls. Perhaps it’s not the right mechanism for Windows, although I don’t know of a better one that can be accessed from the MS desktop scripting languages, cf. VBScript.
 
Suggestions are appreciated. I’m about to give up on this, as I can’t grok it.
 
--Kevin

Nessun virus nel messaggio.
Controllato da AVG - www.avg.com
Versione: 10.0.1392 / Database dei virus: 1520/3844 - Data di rilascio: 19/08/2011



_______________________________________________
python-win32 mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/python-win32
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Questions about deploying COM server via py2exe

Kevin Walzer-7
Hi Matteo,
 
Thanks for the suggestions. I have integrated the win32trace module into my frozen app.  Here is my final code:
 
from quickwho_main import quickwhoApp
import time
import tempfile
from win32com.server.exception import COMException
import winerror
import win32com.server.register
import win32traceutil
 
import sys
sys.stdout = open('C:/Users/Kevin/Desktop/my_stdout.log', 'w')
sys.stderr = open('C:/Users/Kevin/Desktop/my_stderr.log', 'w')
 
#expose basic functionality to COM
class QuickWho_Domain:
  _public_methods_ = ['GetDomain']
  _reg_progid_ = 'QuickWho.Application'
  _reg_clsid_= '{9F825846-F10B-47DD-91E8-88DA93C1A05E}'
 
 
  def GetDomain(self, domain):
      try:
         app.searchfield.delete(0, 'end')
         app.searchfield.insert(0, str(domain))
         app.getInfo()
         time.sleep(1)
         alltext=app.getData()
         tempfile = tempfile.gettempdir()+ '/urltext.txt'
         data = open(tempfile, 'r')
         finaltext = data.read()
         data.close()     
         return finaltext
      except Exception ,ex:
          exMsg='Unable to retrieve domain data '+str(ex)
          raise COMException(desc=exMsg,
                            scode=winerror.E_FAIL)
 
 
print "*"*20
import win32com.server.register
sys.argv.append('--debug')
win32com.server.register.UseCommandLine(QuickWho_Domain)
print "*"*20
 
try:
    app = quickwhoApp(None)
    app.mainloop()
except Exception ,ex:
    print "error !! " + str(ex)
 
(I put the code into a frozen app because it isn’t practical to debug the app itself when run as a Python module—it won’t be deployed that way.)
 
 
I did get some debugging output, though not what I expected:
 
Exception in Tkinter callback
Traceback (most recent call last):
  File "Tkinter.pyc", line 1410, in __call__
  File "quickwho_main.pyc", line 159, in <lambda>
  File "quickwho_main.pyc", line 253, in getInfo
  File "subprocess.pyc", line 537, in check_output
  File "subprocess.pyc", line 672, in __init__
  File "subprocess.pyc", line 784, in _get_handles
  File "subprocess.pyc", line 823, in _make_inheritable
WindowsError: [Error 6] The handle is invalid
 
This appears to be related to the bug logged at http://bugs.python.org/issue3905. My app makes use of subprocess to obtain various bits of data that it then parses and displays in its UI. For what it’s worth,  injecting the trace module into my frozen app causes no output to appear at all in the app itself, and returns the error above; the trace module seems to trigger the suprocess bug. However, it seems to have no bearing at all on the failure of VBScript to create a COM object from my application, and the debugging output logged to my stdout/stderr file did not yield any insight on that.
 
I investigated whether running the mainloop() in the app might interfere with the application receiving the COM request from the Windows Script Host, but commenting out the mainloop only caused the app to crash (since Tkinter apps require a mainloop to run).
 
The bottom line of all this investigation is that I am no closer to understanding why my Tkinter app does not respond to the CreateObject request from VBS. It appears that those requests simply disappear into a black hole. It also appears that integrating a GUI toolkit with its own event loop in Python may not be very practical with a COM server (see http://trac.wxwidgets.org/ticket/12105 for some other issues with wxPython and COM).  Unfortunately, this means my best option is probably to move ahead without COM support.
 
Thanks again for your help.
 
--Kevin 

_______________________________________________
python-win32 mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/python-win32
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Questions about deploying COM server via py2exe

Matteo Boscolo
Hi Kevin,

Il 20/08/2011 20:30, Kevin Walzer ha scritto:
> nfortunately, this means my best option is probably to move ahead
> without COM support.
Try with the pyqt we use it with the main loop opened and it works very
well

here you get a basic example:

from PyQt4.QtCore import *
from PyQt4.QtGui import *

app = QApplication(sys.argv)
app.setQuitOnLastWindowClosed(False)

Regards,
Matteo

_______________________________________________
python-win32 mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/python-win32
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Questions about deploying COM server via py2exe

Mark Hammond-4
In reply to this post by Kevin Walzer-7
On 21/08/2011 4:30 AM, Kevin Walzer wrote:
> Hi Matteo,
> Thanks for the suggestions. I have integrated the win32trace module into
> my frozen app. Here is my final code:
...

> This appears to be related to the bug logged at
> http://bugs.python.org/issue3905. My app makes use of subprocess to
> obtain various bits of data that it then parses and displays in its UI.
> For what it’s worth, injecting the trace module into my frozen app
> causes no output to appear at all in the app itself, and returns the
> error above; the trace module seems to trigger the suprocess bug.

Yeah, but as mentioned in that bug, the issue is to do with your app
being a "gui" app rather than a console one - you can probably reproduce
the same problem wothout py2exe using pythonw.exe instead of python.exe.

Fortunately, it sounds like you can just use subprocess.PIPE and still
get at the output.


> However, it seems to have no bearing at all on the failure of VBScript
> to create a COM object from my application, and the debugging output
> logged to my stdout/stderr file did not yield any insight on that.
> I investigated whether running the mainloop() in the app might interfere
> with the application receiving the COM request from the Windows Script
> Host, but commenting out the mainloop only caused the app to crash
> (since Tkinter apps require a mainloop to run).
> The bottom line of all this investigation is that I am no closer to
> understanding why my Tkinter app does not respond to the CreateObject
> request from VBS. It appears that those requests simply disappear into a
> black hole. It also appears that integrating a GUI toolkit with its own
> event loop in Python may not be very practical with a COM server (see
> http://trac.wxwidgets.org/ticket/12105 for some other issues with
> wxPython and COM). Unfortunately, this means my best option is probably
> to move ahead without COM support.

Sadly the Tkinter main loop doesn't play well with many things.

Mark
_______________________________________________
python-win32 mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/python-win32
Loading...