Sorry Giovanni my explanation of Python COM suffered from being rushed.

As you said Dispatch() uses late binding unless makepy has run to create the cached wrapper modules in gen_py, when it then use early binding.

gencach.EnsureDispatch() forces early binding by effectively calling makepy for you at run time if the wrapper files do not exist.

I need to force early binding as I sink COM events and also want the effective makepy to run on the target machine so we use whatever version of a COM component the user has.

Explaining it has given me some ideas to try so I'll get back to you.


To answer your question
>> Does it work if
>> you add "import
>> win32com.gen_py.C866CA3A-32F7-11D2-9602-00C04F8EE628x0x5x0" in
>> your test file?

I get a syntax error on the first hyphen.

Steve

Steve Lee wrote:
Hi Giovanni and thanks for a quick response.

I forgot to say that the module files ARE created in that gen_py folder correctly AFAICS but gencache._GetModule() is not picking it up. It seems that Dispatch() also calls _GetModule() several times but I have not yet checked if it fails and Dispatch then gets the module another way.

(Is there any debugger that you can use for pyinstaller created programs? I'm going mad just putting in prints/MessageBoxs.)

Again if you leave the Python\...\gen_py or %temp%\gen_py on your system then the moduels get picked up there. That is probably a clue and perhaps a bug as I really only want it to look in the pyInstaller copy and this causes possible end user bugs.

I'm not fluent with win32com, I barely used Dispatch() once. Mind explaining
the difference between the two? Basically, I knew of two different ways:

 > - Using Dispatch() (fully dynamic)
> - Generate the wrapper with makepy.py, import it with "import Foo", and use the
 > classes it exports directly.
 >

OK in COM terms, automation/Dispatch interfaces work in 2 ways.

1 - Late Binding: given a function name you call GetIDsFromNames() to get the ID and then call Invoke() to call the function. Parameters are passed in by a reference parameter to a special structure. You have to do all the parameter block construction and type conversion and so it is pretty inefficient.

2 - Early Binding: we do as much as we can in an initial phase. You get all the information about the functions and types from a typelibrary and create wrapper functions to do the martialing and also skip the GetIDSFromNames stage.

In terms of Python the wrapper modules give you early binding. Dispatch() tries to generate them for you if they were not already created by makepy. If it fails it falls back to late binding (Dynamic). EnsureDispatch() however insists that the wrapper functions exist, also creating them if required. There are obviously other differences, one of which is causing the problem, but it is a lot of code to compare.

I never heard of EnsureDispath.

I almost suspect I am the only person using it :-(. It was at Mark Hammonds suggestion to fix the failure I was having using COM constants and sinking COM events (a COM callback).

Does it work if
you add "import win32com.gen_py.C866CA3A-32F7-11D2-9602-00C04F8EE628x0x5x0" in
your test file?

Unfortunately I can't use that for a very good reason. I use PowerPoint and that uses a different CLSID (that strange modulename above) for each version. I don't care what version the user has and if I did what you suggest or used makepy I would only support that single version. EnsureDispatch and DIspatch() take the progID which is a version independent identifier.

The rules of COM are that is should fall back to an older version so I should be able to specify the latest and get any older. PowerPoint has broken that by using a completely new CLSID not just the version number at the end (x0x5x0).

BTW I noticed a fix for this on the py2exe wiki that simply sets gencache.readonly = false casing dispatch to create the fields as discussed above. But that has no effect here as it is already false, a much better solution with your local gen_py.

I guess because Dispatch() really doesn't need any external module, but
directly find and inspect the .DLL.

Yes, as discussed above it falls back to late/dynamic binding. I need the wrappers.

One problem is that I don't have a development XP machine handy, and I don't know COM enough. Can you construct a different testcase which doesn't strictly require XP? I guess connecting to any older COM dll is good to reproduce...

Ok what *do* you have access to. I will have to try a simple object or create a test case. Can you install
http://prdownloads.sourceforge.net/powertalk/SAPITTS3.exe?download
or
http://fullmeasure.co.uk/powertalk/SAPITTS3.exe as SF seems to be slow.
That will install SAPI for you.

It's not that "mysterious" :) You can have a look at
support/rthooks/win32comgenpy.py which is the module that is run before your
code starts. You will see that it creates the local gen_py folder, and
monkey-patch it into win32com.__gen_path__.

Thanks I'll look. I scanned the notes and got rather lossed, so I must be missing some concepts somewhere.

AAAAHHHH I wonder if the problem is that _GetModule() does not look in win32com.__gen_path__ and Dispatch() false back to using __genpath__ after calling _GetModule() and EnsureDispatch does not? DOes that seem possible?


Steve
_______________________________________________
PyInstaller mailing list
[email protected]
http://lists.hpcf.upr.edu/mailman/listinfo/pyinstaller


_______________________________________________
PyInstaller mailing list
[email protected]
http://lists.hpcf.upr.edu/mailman/listinfo/pyinstaller

Reply via email to