Использование C ++ COM-интерфейса в C # для клиента и сервера - PullRequest
2 голосов
/ 11 ноября 2008

Мне нужно, чтобы часть кода C # взаимодействовала через COM со всеми видами реализаций.

Чтобы было проще для пользователей этой интеграции, я включил взаимодействующие интерфейсы в IDL (как часть соответствующей существующей DLL, но без coclass или реализации), а затем включил это в свой код C #, запустив Tlbimp для создания типов определение.

Я реализовал свой C #, создав COM-объекты на основе информации реестра Windows и приведя объект в нужный мне интерфейс.

Затем я создал реализацию интерфейса на C # в отдельном проекте и зарегистрировал его. Основная программа правильно создает тестовый COM-объект, но не может привести его к интерфейсу (получает нулевой объект при использовании C # «as», получает InvalidCastException явного преобразования).

Может кто-нибудь подсказать, почему интерфейс не идентифицирован как реализованный объектом тестирования?

Это определение интерфейса в IDL (скомпилировано в C ++ в VS 2005):

    [
    object,
    uuid(B60C546F-EE91-48a2-A352-CFC36E613CB7),
    dual,
    nonextensible,
    helpstring("IScriptGenerator Interface"),
    pointer_default(unique)
]
interface IScriptGenerator : IDispatch{

    [helpstring("Init the Script generator")] 
        HRESULT Init();
    [helpstring("General purpose error reporting")] 
        HRESULT GetLastError([out] BSTR *Error);
};

Это заглушка, созданная для C # Tlbimp:

[TypeLibType(4288)]
[Guid("B60C546F-EE91-48A2-A352-CFC36E613CB7")]
  public interface IScriptGenerator
  {
    [DispId(1610743813)]
    void GetLastError(out string Error);
    [DispId(1610743808)]
    void Init();
  }

Это часть основного кода C #, создающая COM-объект по его ProgID и преобразующая его в интерфейс IScriptGenerator:

public ScriptGenerator(string GUID)
{
  Type comType = Type.GetTypeFromProgID(GUID);
  object comObj = null;
  if (comType != null)
  {
    try
    {
      comObj = Activator.CreateInstance(comType);
    }
    catch (Exception ex)
    {
      Debug.Fail("Cannot create the script generator COM object due to the following exception: " + ex, ex.Message + "\n" + ex.StackTrace);
      throw ex;
    }
  }
  else
    throw new ArgumentException("The GUID does not match a registetred COM object", "GUID");

  m_internalGenerator = comObj as IScriptGenerator;
  if (m_internalGenerator == null)
  {
    Debug.Fail("The script generator doesn't support the required interface - IScriptGenerator");
    throw new InvalidCastException("The script generator with the GUID " + GUID + " doesn't support the required interface - IScriptGenerator");
  }

}

И это код реализации C #, чтобы проверить, работает ли он (и нет):

  [Guid("EB46E31F-0961-4179-8A56-3895DDF2884E"),
  ProgId("ScriptGeneratorExample.ScriptGenerator"),
  ClassInterface(ClassInterfaceType.None),
  ComSourceInterfaces(typeof(SOAAPIOLELib.IScriptGeneratorCallback))]
  public class ScriptGenerator : IScriptGenerator
  {
   public void GetLastError(out string Error)
    {
      throw new NotImplementedException();
    }
    public void Init()
    {
      // nothing to do
    }
  }

Ответы [ 2 ]

2 голосов
/ 12 ноября 2008

Снова - спасибо за предложения.

Мне удалось наконец решить проблему самостоятельно. Я попробовал вышеупомянутые предложения и не добился никакого прогресса. Затем я изменил пространство имен взаимодействия в «тестовом» коде - оно отличалось от пространства в основном коде из-за разного использования аргументов при использовании Tlbimp. Это решило проблему.

Вот мое предположение, почему: .Net создает COM-объект, но когда он обнаруживает, что это фактически объект .Net, он обходит уровень COM и обменивается данными напрямую. В этом случае queryInterface (с GUID интерфейса) не используется, и интерфейс отличается из-за разных пространств имен C #.

Это означает, что для предотвращения интеграции с кодом .Net мне нужно будет опубликовать мою исходную сборку взаимодействия в стороне от IDL.

Спасибо, Инбар

0 голосов
/ 12 ноября 2008

Я думаю, вам нужно это на интерфейсе

[InterfaceType(ComInterfaceType.InterfaceIsDual)]
...