win32com and makepy

Sean Laurent slaurent at sonicfoundry.com
Fri Feb 23 22:49:25 EST 2001


On Sat, 24 Feb 2001 01:44:27 GMT, Mark Hammond <MarkH at ActiveState.com>
wrote:

>> I'm having a strange problem with win32com.client.Dispatch().  I used
>> win32com\client\makepy.py to successfully generate Python sources.
>> Unfortunately, after I call win32com.client.Dispatch(), the object I
>> get back is of type "COMObject" instead of one of the generated
>> classes.
>
>This comes up fairly regularly, and unfortunately it depends on the object in question.
>
>The simplest work around is to use the classes in that generated module directly.  Eg:
>
>mod = gencache.EnsureModule('{000C1092-0000-0000-C000-000000000046}',1033, 1, 0)
>
>i = mod.WhateverTheClassNameIs()
>
>And to make life more painful:
>
>>>>> db = i.OpenDatabase("d:\\temp\\test.msi", 0)
>
>Will need to done like:
>
>db = i.OpenDatabase("d:\\temp\\test.msi", 0)
>db = mod.Database(db) # Assuming "Database" is the class name


Ah hah!  *light bulb goes off*

Interestingly enough, I tried:
     >>>> i = mod.Installer()
then I tried:
     >>>> db = i.OpenDatabase( ... )
At this point, "db" _is_ the correct type - no need to do:
     >>>> db = mod.Database(db)

All things considered, this isn't any more painful than calling
client.Dispatch().

I finally took a look at your "Advanced Python and COM" presentation
from the 8th International Python Conference... and it seems that the
following is also a viable alternative:
     >>>> gencache.EnsureModule(blahblahblah)
     >>>> klass = gencache.GetClassForProgID(blah)
     >>>> i = klass()
     >>>> db = i.OpenDatabase(blahblah)

The only advantage to that technique (in my mind), is that it is
indepedent of the actual class name in the cached module.  In reality,
I suppose there isn't any need to be independent of the class name.
If Microsoft (in their infinite wisdom) changes the structure of the
type library such that the class name changes... they would probably
also change enough other stuff that the whole script would have to be
reworked anyway.


As a side note, I'm still puzzled as to why the original code didn't
work:
     >>>> gencache.EnsureModule(blahblah)
     >>>> i = win32com.client.Dispatch("WindowsInstaller.Installer")

I spent some time stepping through the code and I found that the code
was bailing in win32com.client.dynamic._GetGoodDispatch() at the line
reading:
     IDispatch = pythoncom.connect(IDispatch)

     com_error: (-2147221021, 'Operation unavailable', None, None)

So, I decided to spoonfeed the call to Dispatch and hand it the
classID of the interface in question.  I cut and paste the ClassID
directly from the script generated by makepy.  With this, I followed
the debugger to __WrapDispatch() in win32com.client.__init__, where it
called:
     klass = gencache.GetClassForCLSID(resultCLSID)

Looking at gencache.GetClassForCLSID(), it calls
CLSIDToClass.HasClass().  And this is where things suddenly became
interesting.  Through the debugger I looked at the entries in the
mapCLSIDToClass dictionary - indeed there were a _number_ of entries,
but not the CLSID I needed.

At this point, I sat down with OLEVIEW and I discovered something
interesting.  The generated code set a CLSID of:

{000C1092-0000-0000-C000-000000000046}

While this is the ID of the type library, it is neither the CLSIDnor
the AppID (which carry the same value) for the actual "Microsoft
Windows Installer" object.  Unfortunately, this turned out to be a
dead end - I tried changing the ClassID in the generated file, but
this didn't help.  (As you may have already guessed!)


The other bizarre thing I found was in __WrapDispatch() in
win32com.client.__init__.  In this function, you find the following
code:
     if resultCLSID is None:
          try:
               typeinfo = dispatch.GetTypeInfo()

In this case, we don't have a CLSID, so this code gets called.  Yet it
bails with:  "com_error: (-2147467262, 'No such interface supported',
None, None)"  which seems a bit bizarre, since dispatch is of type
PyIDispatch - which should support this method...

Any thoughts?  Am I beating a dead horse?  Or what's the word?

-Sean Laurent-



More information about the Python-list mailing list