Menu

#712 SAFEARRAY expose though .NET COM interop does not work with pywin32

v1.0 (example)
open
nobody
None
7
2016-03-21
2016-01-26
No

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

1 Attachments

Discussion

  • Thomas Olsson

    Thomas Olsson - 2016-01-26

    Here are some binaries too.

     
  • Thomas Olsson

    Thomas Olsson - 2016-03-14

    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?

     
  • Thomas Olsson

    Thomas Olsson - 2016-03-21

    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/

     

    Last edit: Thomas Olsson 2016-03-21