2008-11-11 11 views
2

Je dois faire interagir un élément de code C# via COM avec toutes sortes d'implémentations. Pour faciliter la tâche aux utilisateurs de cette intégration, j'ai inclus les interfaces interactives dans IDL (dans le cadre d'une DLL existante pertinente, mais sans coclass ni implémentation), puis j'ai ajouté ce code à mon code C# en exécutant Tlbimp pour créer le définition des types.Utilisation de l'interface COM C++ en C# pour le client et le serveur

J'ai implémenté mon C#, en créant des objets COM basés sur les informations de registre de Windows et en convertissant l'objet dans l'interface dont j'ai besoin. J'ai ensuite créé une implémentation C# de l'interface dans un projet séparé et l'ai enregistrée. Le programme principal crée l'objet COM de test correctement, mais ne parvient pas à le lancer dans l'interface (obtient un objet nul en utilisant C# 'as', obtient une InvalidCastException de distribution explicite). Est-ce que quelqu'un peut suggérer pourquoi l'interface n'est pas identifiée comme implémentée par l'objet de test?

Ceci est la defition d'interface IDL (compilé en C++ dans 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'est le talon créé pour C# par Tlbimp:

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

Cela fait partie de la principale C# code, la création d'un objet COM par son ProgID et le jetant à l'interface 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"); 
    } 

} 

et e est est le code C# mise en œuvre, pour le tester fonctionne (et ce n'est pas):

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

Répondre

2

Encore une fois - merci pour les suggestions. J'ai pu enfin résoudre le problème par moi-même. J'ai essayé les suggestions ci-dessus et n'ai fait aucun progrès. Ensuite, j'ai changé l'espace de noms de l'interop dans le code 'testing' - il variait de celui du code principal en raison de l'utilisation d'arguments différents lors de l'utilisation de Tlbimp. Cela a résolu le problème.

Voici pourquoi: .Net crée l'objet COM, mais lorsqu'il détecte qu'il s'agit en fait d'un objet .Net, il contourne la couche COM et communique directement. Dans ce cas, queryInterface (avec l'interface GUID) n'est pas utilisé et l'interface diffère en raison de différents espaces de noms C#. Cela signifie que pour éviter l'intégration avec le code .Net, je devrai publier mon assembly d'interopérabilité d'origine en dehors de l'IDL.

Merci, Inbar

0

Je pense que vous avez besoin de ce sur l'interface

[InterfaceType(ComInterfaceType.InterfaceIsDual)]