[python-win32] Calling COM Interface from Python Script

cpede cpede at outlook.dk
Sun Sep 28 00:36:32 CEST 2014


I'm trying to call a COM Interface using Python Script.

I got the installation of Python from ActivePython, and I'm trying to script 
parts of my code using the Script Engine. This normally works with VBScript 
and JScript, but now I want to extend this with PythonScript.

The Script Engine is called through a COM interface that I have defined. It 
seems that most things works, but when I call a method with both a Set and 
Get defined, Python fails to locate the correct version of the method.

In my ODL file I have defined a method called Property, which has a propget 
and propput flag, with the same name and id, like this:

[propget,id(100)] HRESULT Property([in]BSTR* name,[out,retval]VARIANT* val);
[propput,id(100)] HRESULT Property([in]BSTR* name,[in]VARIANT val);
When called from JScript I can do like this:

Session.Property("Test",2);
In the Scripting Engine "oledisp1.cpp" in COleDispatchImpl::Invoke line 
1309, this call is interpret as a DISPATCH_METHOD method, and then corrected 
to DISPATCH_PROPERTYPUTREF, based on a test on the arguments in this part of 
the code:

// treat member calls on properties just like property get/set
if ((wFlags == DISPATCH_METHOD) &&
    ((pEntry->pfn == NULL && pEntry->pfnSet == NULL) ||
     (pEntry->pfn == NULL && pEntry->pfnSet != NULL) ||
     (pEntry->pfn != NULL && pEntry->pfnSet != NULL)))
{
    // the entry describes a property but a method call is being
    //  attempted -- change it to a property get/set based on the
    //  number of parameters being passed.
    wFlags &= ~DISPATCH_METHOD;
    UINT nExpectedArgs = pEntry->lpszParams != NULL ?
        (UINT)lstrlenA(pEntry->lpszParams) : 0;
    if (pDispParams->cArgs <= nExpectedArgs)
    {
        // no extra param -- so treat as property get
        wFlags |= DISPATCH_PROPERTYGET;
    }
    else
    {
        // extra params -- treat as property set
        wFlags |= DISPATCH_PROPERTYPUTREF;
        pDispParams->cNamedArgs = 1;
    }
}
When the same method is called from Python, the COleDispatchImpl::Invoke is 
initially called with the flag DISPATCH_PROPERTYGET.

This is of cause wrong, since the call must be interpret as a 
DISPATCH_PROPERTYPUTREF, then the method call fails with wrong number of 
arguments.

Why are Python Script misinterpreting this method call?

Is Python Script not able to handle propget and propput methods as defined 
in the OLD file?

Can I in the call to the method in Python Script somehow tell that it is the 
propput version of the method I want to call?

Update 1

The above code calls the following macro:

DISP_PROPERTY_PARAM_ID(CMyScriptingObject,"Property",100,GetProperty,SetProp
erty,VT_VARIANT,VTS_BSTR)
Here a Set and a Get (in this case SetProperty and GetProperty) methods are 
created. I now found out, that if I implicitly calls the SetProperty method, 
it works:

Session.SetProperty("Test",2)
Intuitively I would then expect that GetProperty would work like this:

myProp = Session.GetProperty("Test")
However this calls fails with the following error:

[13:32:49] Python Test
[13:32:52] Scripting
     Python ActiveX Scripting Engine
     Error: Traceback (most recent call last):
       File "<Script Block >", line 20, in <module>
         myProp = Session.GetProperty("Test")
       File "C:\Python27\lib\site-
packages\win32comext\axscript\client\pyscript.py", line 105, in __getattr__
         return getattr(self._scriptItem_.dispatchContainer,attr)
       File "C:\Python27\lib\site-packages\win32com\client\dynamic.py", line 
522, in __getattr__
         raise AttributeError("%s.%s" % (self._username_, attr))
     AttributeError: Session.GetProperty
     In line 20 At column -1 Error Code: 0
     Source line: myProp = Session.GetProperty("Test")
It must be related to multiple arguments. However it could also be that I 
don't understand the syntax of Python compared to the simpler VBScript.

Update 2

Ok, now I used the PythonWin program to load the tool COM Makepy Utility on 
the registered tlb of my COM object. Here I can see:

# The method Property is actually a property, but must be used as a method 
to correctly pass the arguments
def Property(self, name=defaultNamedNotOptArg, val=pythoncom.Missing):
        return self._ApplyTypes_(100, 2, (3, 0), ((8, 1), (16396, 10)), 
u'Property', None,name
            , val)

# The method SetProperty is actually a property, but must be used as a 
method to correctly pass the arguments
def SetProperty(self, name=defaultNamedNotOptArg, 
val=defaultNamedNotOptArg):
        return self._oleobj_.InvokeTypes(100, LCID, 4, (3, 0), ((8, 1), (12, 
1)),name
            , val)
So, I guess that this is why I need to call SetProperty and why GetProperty 
does not exist. But the Property exist, but how do I call it?

-cpede



More information about the python-win32 mailing list