|
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 |
|
Hi Kevin ,
Il 18/08/2011 17:10, Kevin Walzer ha scritto: Hi all,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 ..."
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
_______________________________________________ python-win32 mailing list [hidden email] http://mail.python.org/mailman/listinfo/python-win32 |
|
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.
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 |
|
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:
_______________________________________________ python-win32 mailing list [hidden email] http://mail.python.org/mailman/listinfo/python-win32 |
|
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 |
|
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 |
|
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 |
| Powered by Nabble | Edit this page |
