FAQ
Howdy All,
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.

In particular, I'm trying to interact with Microsoft Windows Installer
Service (known as MSI) - the typelibrary is named "Microsoft Windows
Installer Object Library" and the PROGID is
"WindowsInstaller.Installer".

Using win32com\client\makepy.py:
makepy -i "Microsoft Windows Installer Object Library"
Microsoft Windows Installer Object Library
{000C1092-0000-0000-C000-000000000046}, lcid33, major=1, minor=0
# Use these commands in Python code to auto generate .py support
from win32com.client import gencache
gencache.EnsureModule('{000C1092-0000-0000-C000-000000000046}',1033, 1, 0)
Looking in win32com\gen-py, the appropriate file _does_ exist:
000C1092-0000-0000-C000-000000000046x1033x1x0.py
and it does contain the correct class definitions.

Then, in my code:
i = win32com.client.Dispatch("WindowsInstaller.Installer")
i
<COMObject WindowsInstaller.Installer>
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Voila! There's the problem. According to the docs, this really
should be something more like:
<win32com.gen_py.Microsoft Windows Installer.Installer>

Furthermore, if I call a method which should create another object,
things get even worse:
db = i.OpenDatabase("d:\\temp\\test.msi", 0)
db
<COMObject <unknown>>
^^^^^^^^^^^^^^^^^^^^^
Again, this should be something more like:
<win32com.gen_py.Microsoft Windows Installer.Database>


However, if I try this with Microsoft Word, everything works great!
makepy -i "Microsoft Word 9.0 Object Library"
Microsoft Word 9.0 Object Library
{00020905-0000-0000-C000-000000000046}, lcid=0, major=8, minor=1
# Use these commands in Python code to auto generate .py support
from win32com.client import gencache
gencache.EnsureModule('{00020905-0000-0000-C000-000000000046}', 0, 8, 1)
w = win32com.client.Dispatch("Word.Application")
w
<win32com.gen_py.Microsoft Word 9.0 Object Library._Application>


*arrrgghhh*

Any bright ideas as to what's going wrong here?

----------
Sean Laurent
Engineer -Install
Sonic Foundry, Inc.
slaurentNOSPAM at sonicfoundryNOSPAM.com
----------

Search Discussions

  • Mark Hammond at Feb 24, 2001 at 1:44 am

    Sean Laurent wrote:

    Howdy All,
    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

    Mark.



    From noahnoah.org Sat Feb 24 02:09:48 2001
    From: noahnoah.org (Noah Spurrier (a))
    Date: 24 Feb 2001 01:09:48 GMT
    Subject: Need to unread or push back bytes to a file
    Message-ID: <9771ks0ic2@news2.newsguy.com>


    I need to push bytes back into a file object.
    Is there a buffered file wrapper for file objects?
    (Yes, I looked, but I gave up after almost five minutes of searching.)

    I'm reading from a pipe, but this could be the same for a file.
    I call an "expect" method which reads until a pattern is found,
    but read() with a pipe will read as much data as there is available
    in the pipe. When I have found a pattern match I want to return
    the stream with the extra character pushed-back.

    Another way to word this is that I want to the of a pattern, but
    not past the pattern.

    My only other option would be to read(1) character at a time
    and then search for the pattern. This will work, but I think a
    push-back would be more elegant and efficient.

    Yours,
    Noah

    ==================================
    Posted via http://nodevice.com
    Linux Programmer's Site
  • Sean Laurent at Feb 24, 2001 at 3:49 am

    On Sat, 24 Feb 2001 01:44:27 GMT, Mark Hammond 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-
  • Mark Hammond at Feb 24, 2001 at 2:58 pm

    Sean Laurent wrote:

    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)
    This should be fine - we then go and try the CoCreateInstance route and end up down the same path you traced.
    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...
    This is the crux of the whole problem. The object implements GetTypeInfo, but just fails to provide it. If this was available, then win32com would be able to find the CLSID of the object, and get the makepy generated class.
    Any thoughts? Am I beating a dead horse?
    Pretty much I fear - at least until MS upgrade their interfaces.

    Mark.
    --
    Nominate Your Favorite Programmers
    for the Perl and Python Active Awards!
    http://www.ActiveState.com/Awards/
  • Sean Laurent at Feb 26, 2001 at 6:32 pm

    On Sat, 24 Feb 2001 14:58:33 GMT, Mark Hammond wrote:
    This is the crux of the whole problem. The object implements GetTypeInfo, but just fails
    to provide it. If this was available, then win32com would be able to find the CLSID of the
    object, and get the makepy generated class.
    Any thoughts? Am I beating a dead horse?
    Pretty much I fear - at least until MS upgrade their interfaces.

    D'oh! As a developer, why do I I always find myself boxed into some
    corner or forced to come up with workarounds just because Micro$oft
    doesn't do something correctly? *ugh*

    Well, your kludge (described in an earlier message) is very beneficial
    and solves the problem. I greatly appreciate the help!

    ----------
    Sean Laurent
    Engineer -Install
    Sonic Foundry, Inc.

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
grouppython-list @
categoriespython
postedFeb 23, '01 at 8:54p
activeFeb 26, '01 at 6:32p
posts5
users2
websitepython.org

2 users in discussion

Sean Laurent: 3 posts Mark Hammond: 2 posts

People

Translate

site design / logo © 2022 Grokbase