Hi,
I have a project where an API is exposed through COM. It is implemented in .NET.
I have made a simple sample project (attached) which exposes two interfaces:
[Guid("1C56509C-35D9-4712-839A-A6D5A366EC96")] [ComVisible(true)] [InterfaceType(ComInterfaceType.InterfaceIsDual)] [Description("An item.")] public interface IItem { [Description("Get the name.")] [DispId(0)] string Name { get; } } [Guid("C53A82A2-82A8-4185-97F9-4EF97796CAF5")] [ComVisible(true)] [InterfaceType(ComInterfaceType.InterfaceIsDual)] [Description("Interface for some container.")] public interface IContainer { [Description("Get the description.")] [DispId(0)] string Description { get; } [Description("One item.")] [DispId(1)] IItem GetOneItem(); [Description("Get the items.")] [DispId(2)] [return: MarshalAs(UnmanagedType.SafeArray)] IItem[] GetItems(); }
This corresponds to COM interfaces in the IDL language as:
[ odl, uuid(1C56509C-35D9-4712-839A-A6D5A366EC96), version(1.0), helpstring("An item."), dual, oleautomation, custom(0F21F359-AB84-41E8-9A78-36D110E6D2F9, "ComTestServer.IItem") ] interface IItem : IDispatch { [id(00000000), propget] HRESULT Name([out, retval] BSTR* pRetVal); }; [ odl, uuid(C53A82A2-82A8-4185-97F9-4EF97796CAF5), version(1.0), helpstring("Interface for some container."), dual, oleautomation, custom(0F21F359-AB84-41E8-9A78-36D110E6D2F9, "ComTestServer.IContainer") ] interface IContainer : IDispatch { [id(00000000), propget] HRESULT Description([out, retval] BSTR* pRetVal); [id(0x00000001), helpstring("One item.")] HRESULT GetOneItem([out, retval] IItem** pRetVal); [id(0x00000002), helpstring("Get the items.")] HRESULT GetItems([out, retval] SAFEARRAY(IItem*)* pRetVal); };
When the .NET assembly is registered (either as part of the build process or though "regasm /codebase") it is easy to create instances of the classes in the sample:
import win32com.client
c = win32com.client.Dispatch("ComTestServer.Connection")
c.Description
'Some container'
r = c.GetOneItem()
r.Name
'One item'
So far so good.
However, when I try to access the array returnd by GetItems(), I run into problems.
As expected, I get a tuple with two elements, but the elements are of type IUnknown and I fail to convert them to either IDispatch or IItem.
x = c.GetItems()
i = x[0];
i
<PyIUnknown at="" 0x02E56428="" with="" obj="" at="" 0x03DDFFF0="">
I have verified that I di get a proper SAFEARRAY from .NET both by using this in VBA and in a C++ program. With pywin32 it does not work though.
Any ideas?
I have tried to set the return type of the list in .NET to
[return: MarshalAs(UnmanagedType.SafeArray, SafeArraySubType =VarEnum.VT_DISPATCH)]
but the result is the same.
/Thomas O
Here are some binaries too.
Not much response on this bug report. I would be happy to help out in order to solve this. I have a lot of experience of C++ and COM, but I am not an expert on Python.
If someone could give me a hint how to set up a build environment for pywin32 so that I can debug the C++ part in Visual Studio, I could probably solve this.
Is there any helpful documentation or hints how to built pywin32 and make it possible to debug in VS?
Actually, my .NET example was not a very good illustration. The interface returned does not implement IDispose. For this to work correctly, the class that implements the interface must have "ComVisible(true)" like this:
This does not solve the issue, but it is a step on the way. See also https://sourceforge.net/p/pywin32/feature-requests/114/
Last edit: Thomas Olsson 2016-03-21