简体   繁体   中英

Instantiating C# Class Members in C++ using COM

I would like to create a C# class object in C++ and set its member fields. Although I am able to create a C++ class object, I am unable to access it's members and set member field values.

/// <summary>
/// Class for AQS Entity
/// </summary>
[ClassInterface(ClassInterfaceType.None)]
[Guid("70F12A44-B91D-474D-BD70-32B1ACE041D6")]
[ProgId("AQSEntity")]
public class AQSEntity : IEntity
{

    public AQSEntity()
    {
        sRecoveryDBName = String.Empty;
        arrSourceMailboxesEntity = null;
        sQueryString = String.Empty;
    }

    [MarshalAs(UnmanagedType.BStr)]
    public string sRecoveryDBName = string.Empty;

    [MarshalAs(UnmanagedType.ByValArray)]
    public MailBoxCollection arrSourceMailboxesEntity;

    [MarshalAs(UnmanagedType.BStr)]
    public string sQueryString;


}

and the IEntity class is defined below

[Guid("5C71057E-9FD9-47D5-B022-8D5F9C7007D3")]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IEntity
{
}

In C++,

IEntity* pTest1 = NULL;
hr = CoCreateInstance(__uuidof(**AQSEntity**),NULL,CLSCTX_INPROC_SERVER,__uuidof(IEntity),(void**)&pTest1);

I want to access members of AQSEntity class in C++. But I am unable to access them.

pTest1-> sQueryString

gives error.

'sQueryString' : is not a member of 'AsigraExchange::IEntity' C:\\PROJECTS\\COM\\COMClient\\COMClient.cpp 168

Can anyone please suggest where I am wrong.

Thanks, Gagan

Everything behaves exactly as it should :)

In your C++ project, you are allowed to access all the methods declared on your IEntity interface, which there are none.

Your implementation, ie AQSEntity class, should implement all the IEntity members. The methods which are now declared in that class are member of the class, they are not related to IEntity in any way.

This means you need to declare all the required methods inside IEntity interface and then implement them in AQSEntity . Notice that you are also exposing the fields of the class, not the methods. You will have to define methods (or properties, which will get converted to methods on C++ side) and then implement them. Something like:

public interface IEntity
{
    public string RecoveryDBName { get; }
}

You also have to specify [MarshalAs] attributes in the interface, although UnmanagedType.BStr is default for strings, so you can omit them.

EDIT:

based on comments, it seems that IEntity is just a marker interface, not intended to be exposed as an API (attributes might be better option here, as IEntity won't be used on client side anyway).

In this case there are two options:

1) better approach, although it requires more work: derive IAQSEntity interface from IEntity , declare methods on it, and implement that on AQSEntity class

2) less work, but more brittle: Mark AQSEntity as ClassInterfaceType.AutoDual instead of ClassInterfaceType.None - this will expose the members to COM clients, but will be much harder to version and it will also expose the base type members.

Here's what I would choose:

[ClassInterface(ClassInterfaceType.None)]
...
[Entity]  // instead of IEntity marker interface
public class AQSEntity : IAQSEntity
{
    public string RecoveryDbName { get; }
}

[Guid("...")]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IAQSEntity // no base interface IEntity!
{
    string RecoveryDbName { get; }        
}

The only drawback of using Entity attribute instead of IEntity marker interface is if you want to use the interface as constraint for generics

Your interface does indeed not contain any members. You need to put the members into the interface and then implement that interface in your class.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM