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

Reply via email to