2013-04-29 3 views
1

Я хотел бы создать объект класса C# в C++ и установить его поля-члены. Хотя я могу создать объект класса C++, я не могу получить доступ к его членам и устанавливать значения полей элемента.Создание экземпляров класса C# в C++ с использованием COM

/// <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; 


} 

и класс IEntity определен ниже

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

В C++,

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

Я хочу, чтобы получить доступ к членам класса AQSEntity в C++. Но я не могу получить к ним доступ.

pTest1-> sQueryString

дает ошибку.

'sQueryString': не является членом 'AsigraExchange :: IEntity' C: \ Projects \ COM \ COMClient \ COMClient.cpp 168

Может кто-нибудь предложить, пожалуйста, где я не прав.

Спасибо, Gagan

+1

Вашего интерфейса полностью пуст. Добавьте к нему свойства и методы. Не добавляйте поля. –

+0

Существуют и другие классы, реализующие IEntity. Если я добавлю свойства и методы в IEntity, эти классы не смогут наследовать от IEntity. – Gags

ответ

2

Все ведет себя точно так, как это должно :)

В вашем проекте C++, вы имеете доступ ко всем методам, объявленных на интерфейсе IEntity, что их нет.

Ваша реализация, то есть AQSEntity класс, должна выполнять все члены IEntity. Методы, объявленные в этом классе, являются членами класса, они никак не связаны с IEntity.

Это означает, что вам необходимо объявить все необходимые методы внутри интерфейса IEntity, а затем реализовать их в AQSEntity. Обратите внимание, что вы также раскрываете поля класса, а не методы. Вам нужно будет определить методы (или свойства, которые будут преобразованы в методы на стороне C++), а затем реализовать их. Что-то вроде:

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

Вы также должны указать [MarshalAs] атрибуты в интерфейсе, хотя UnmanagedType.BStr по умолчанию для строк, так что вы можете опустить их.

EDIT:

на основе комментариев, кажется, что IEntity просто интерфейс маркера, не должен подвергаться как API (атрибуты могут быть лучшим вариантом здесь, как IEntity не будет использоваться на стороне клиента так или иначе).

В этом случае есть два варианта:

1) лучший подход, хотя и требует больше работы: получить IAQSEntity интерфейс от IEntity, объявить его методу, и осуществить это на AQSEntity класса

2) меньше работы, но более хрупкой: Mark AQSEntity как ClassInterfaceType.AutoDual вместо ClassInterfaceType.None - это выведет членов COM-клиентов, но будет намного сложнее в версии, и оно также выведет членов базового типа.

Вот что бы я выбрал:

[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; }   
} 

Единственный недостаток использования Entity атрибута вместо IEntity интерфейса маркеров, если вы хотите использовать интерфейс в качестве ограничения для дженерик

+0

Существуют и другие классы, реализующие IEntity. Если я добавлю свойства и методы в IEntity, эти классы не смогут наследовать от IEntity. – Gags

+0

Тогда вам понадобится интерфейс IAQS, полученный от объекта. COM в сторону, как бы вы могли получить доступ к членам 'AQSEntity' через' IEntity' в C#? никоим образом - это, по-видимому, интерфейс маркера в вашем случае. Другой вариант - использование класса ClassInterfaceType.AutoDual вместо класса ClassInterfaceType.None', но считается плохой практикой. –

+0

Я меняю свой дизайн в соответствии с предложениями в этом посте. Спасибо – Gags

0

Ваш интерфейс действительно не содержит каких-либо членов. Вам нужно поместить членов в интерфейс, а затем реализовать этот интерфейс в своем классе.

+0

Существуют и другие классы, реализующие IEntity. Если я добавлю свойства и методы в IEntity, эти классы не смогут наследовать от IEntity. Я добавляю поля в интерфейс – Gags

+0

Ну, это ваша проблема, а не техническая. Почему вы реализуете свой COM-интерфейс для других классов, чем тот, который вы хотите открыть для COM? Не делай этого. Тот факт, что вы не можете добавлять поля, должен сообщить вам что-то о вашем классе. Не используйте общедоступные поля. – nvoigt

Смежные вопросы