2008-11-11 7 views
2

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

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

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

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

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

Это интерфейс defition в 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

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

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

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

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

Thanks, Inbar

0

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

[InterfaceType(ComInterfaceType.InterfaceIsDual)]