SAFEARRAY expose though .NET COM interop does not work with pywin32
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
Reported by: thriolsson
Original Ticket: pywin32/bugs/712
Here are some binaries too.
Original comment by: thriolsson
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?
Original comment by: thriolsson
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:
[ClassInterface(ClassInterfaceType.None)]
[Description("Interface for some container.")]
[Guid("7635C970-35D4-41E7-8856-5C9AAB35F5C5")]
[ComVisible(true)]
public class Item : IItem
{
This does not solve the issue, but it is a step on the way. See also https://sourceforge.net/p/pywin32/feature-requests/114/
Original comment by: thriolsson
This is now https://github.com/mhammond/pywin32/issues/873