Kelie schrieb: > Hello, > > I wrote a simple script which uses comtypes. When I run it the first time, it > takes some time to generate the module(s) (in the comtypes/gen directory), > which > is normal.
comtypes creates the modules on the first time they are needed (which is usually when you call comtypes.client.CreateObject("MyProgId"). If possible, they are written into the comtypes\gen directory. > When I run the code again, the step of generating module(s) is > skipped. Because they are now found in the comtypes\gen directory. > But after I package the program into an executable with py2exe, it > re-generates the module(s) every time I run the exe. Apparently the modules in comtypes\gen have not been included into the exe, so comtypes needs to generate them again. Now, since in the exe the comtypes library is inside the zipfile (library.zip or so), comtypes cannot write the generated code into the zipfile; the code is only kept in memory. and it has to be generated again each time your exe runs. > Apparently it is not the > case using PyWin32, or at least I cannot notice the delay. PyWin32 generates the code (if any) into a writeable directory somewhere else - I will change comtypes to also use another directory in a future version as well so that generated code can be cached in the filesystem even for a py2exe'd program. > I'm not sure if this > is related to its dynamic IDispatch feature that Michael mentioned in this > post: > http://article.gmane.org/gmane.comp.python.comtypes.user/192. Not really. Michael wants comtypes to work without generating code at all (for some objects, at least). ---- Here's a walkthrough with a simple comtypes client program. This script creates a JScript interpreter and uses it to evaluate and print a JScript expression: <script> from comtypes.client import CreateObject if __name__ == "__main__": p = CreateObject(u"MSScriptControl.ScriptControl") p.Language = u"JScript" print repr(p.Eval(u"'foobar' + 42.0")) <script/> The first time you run it, the output is this: """ C:\>py25 js.py # Generating comtypes.gen._0E59F1D2_1FBE_11D0_8FF2_00A0D10038BC_0_1_0 # Generating comtypes.gen._00020430_0000_0000_C000_000000000046_0_2_0 # Generating comtypes.gen.stdole # Generating comtypes.gen.MSScriptControl u'foobar42' C:\> """ Running it again, the only output is (since code generation is skipped now): """ C:\>py25 js.py u'foobar42' C:\> """ Ok, write a trivial setup.py file for py2exe and let it create the exe. Run the exe several times; the code is generated each time: """ C:\>py25 setup.py py2exe ..... C:\>dist\js.exe # Generating comtypes.gen._0E59F1D2_1FBE_11D0_8FF2_00A0D10038BC_0_1_0 # Generating comtypes.gen._00020430_0000_0000_C000_000000000046_0_2_0 # Generating comtypes.gen.stdole # Generating comtypes.gen.MSScriptControl u'foobar42' C:\>dist\js.exe # Generating comtypes.gen._0E59F1D2_1FBE_11D0_8FF2_00A0D10038BC_0_1_0 # Generating comtypes.gen._00020430_0000_0000_C000_000000000046_0_2_0 # Generating comtypes.gen.stdole # Generating comtypes.gen.MSScriptControl u'foobar42' C:\> """ Ok, let's advise py2exe to include the comtypes.gen.MSScriptControl module: <script> from comtypes.client import CreateObject import comtypes.gen.MSSciptControl # so that py2exe includes this module in the exe if __name__ == "__main__": p = CreateObject(u"MSScriptControl.ScriptControl") p.Language = u"JScript" print repr(p.Eval(u"'foobar' + 42.0")) <script/> Make a new exe and run it: """ C:\>py25 setup.py py2exe ..... C:\>dist\js.exe u'foobar42' C:\js.exe u'foobar42' C:\> """ Now, the final refinement (what I usually do) is to make sure that the comtypes.gen.MSScriptControl is recreated when I have cleaned up my comtypes.gen directory. Looking into comtypes.gen.MSScriptControl, then into comtypes.gen._0E59F1D2_1FBE_11D0_8FF2_00A0D10038BC_0_1_0 I find that the type library is 'c:\Windows\System32\msscript.ocx'. So I can use comtypes.client.GetModule(typelib_path) to generate the module even without or BEFORE actually creating the COM object. The final script is this: <script> import sys if not hasattr(sys, "frozen"): from comtypes.client import GetModule GetModule(u"msscript.ocx") from comtypes.gen import MSScriptControl from comtypes.client import CreateObject if __name__ == "__main__": p = CreateObject(u"MSScriptControl.ScriptControl") p.Language = u"JScript" print repr(p.Eval(u"'foobar' + 42.0")) <script/> Explanation: The executables that py2exe creates have attached a 'frozen' attribute to the 'sys' module, which is not present in a normal Python interpreter. This is the easiest way to determine whether a script is running with Python or as exe. So, when running the script with Python, GetModule("msscript.ocx") is called which generates the comtypes.gen.MSScriptControl module unless it is already present. py2exe sees that comtypes.gen.MSScriptControl is imported and includes this module (plus that modules that this one references) into the exe. When the exe runs, the GetModule step is skipped because hasattr(sys, "frozen") is True, and the module is available in the library.zip file. Hope that explains what's happening and the purpose of the code (that also MR Michael Robellard already posted). -- Thanks, Thomas ------------------------------------------------------------------------- This SF.Net email is sponsored by the Moblin Your Move Developer's challenge Build the coolest Linux based applications with Moblin SDK & win great prizes Grand prize is a trip for two to an Open Source event anywhere in the world http://moblin-contest.org/redirect.php?banner_id=100&url=/ _______________________________________________ comtypes-users mailing list comtypes-users@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/comtypes-users