2008-10-12 6 views
6

En raison des contraintes de l'entreprise hors de mon contrôle, je le scénario suivant:Dérivation interfaces COM dans .NET

Une bibliothèque COM qui définit l'interface suivante (pas coclass, juste l'interface):

[ 
    object, 
    uuid(xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx), 
    dual, 
    nonextensible, 
    helpstring("IService Interface"), 
    pointer_default(unique) 
] 
IService : IDispatch 
{ 
    HRESULT DoSomething(); 
} 

[ 
    object, 
    uuid(xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx), 
    dual, 
    nonextensible, 
    helpstring("IProvider Interface"), 
    pointer_default(unique) 
] 
IServiceProvider : IDispatch 
{ 
    HRESULT Init(IDispatch *sink, VARIANT_BOOL * result); 
    HRESULT GetService(LONG serviceIndicator, IService ** result); 
}; 


[ 
    uuid(xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx), 
    version(1.0), 
] 
library ServiceLibrary 
{ 
    importlib("stdole2.tlb"); 

    interface IService; 
    interface IServiceProvider; 
}; 

J'ai un COM (écrit w/C++) qui implémente les deux interfaces et fournit notre application (s) avec ce service. Tout va bien, je pense.

J'essaye de construire un nouveau IProvider et IService dans .NET (C#).

J'ai construit une Assemblée interop primaire pour la bibliothèque COM et mis en œuvre les C#:

[ComVisible(true)] 
[Guid("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")] 
public interface INewService : IService 
{ 
    // adds a couple new properties 
} 

[ComVisible(true)] 
[Guid("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")] 
public class NewService : INewService 
{ 
    // implement interface 
} 

[ComVisible(true)] 
[Guid("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")] 
public interface INewProvider : IServiceProvider 
{ 
    // adds nothing, just implements 
} 

[ComVisible(true)] 
[Guid("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")] 
public class NewProvider : INewProvider 
{ 
    // implement interface 
} 

Lorsque je tente de glisser cela dans l'exécution actuelle, je suis en mesure de créer l'objet NewProvider de COM (C++) et QueryInterface pour IServiceProvider. Lorsque j'essaie d'appeler une méthode sur le IServiceProvider, un System.ExecutionEngineException est levé. La seule autre chose que je peux trouver, est en regardant les fichiers .tlh créés par le # import, montre l'ancienne classe COM IExistingProvider montre correctement qu'il est dérivé de IServiceProvider. Cependant la classe .NET montre une base de IDispatch. Je ne sais pas si c'est un signe, une indication, utile, autre chose.

+0

Quand vous dites que vous avez "construit" une Assemblée interop primaire, voulez-vous dire à partir de zéro N'a-t-il pas été possible de simplement ajouter la bibliothèque COM comme référence? – ilitirit

+0

J'ai construit le PIA à partir du TLBIMP.exe. Aimeriez-vous voir un exemple de ligne de commande pour cela? J'ai utilisé TLBIMP, en créant mon propre Interop.Services.dll, puis référence cela. J'ai récemment acquis ".NET et COM - le Guide complet d'interopérabilité". – DevSolo

+0

Y a-t-il une raison pour laquelle vous n'avez pas importé la bibliothèque directement dans Visual Studio ou n'utilisez-vous pas Visual Studio? – ilitirit

Répondre

5

Il peut s'agir d'un problème avec le nom IServiceProvider. Vérifiez que vous n'avez pas déjà importé une interface portant le même nom.

Lorsque je crée une bibliothèque d'interface COM en utilisant votre IDL, et essayer ensuite importer d'un autre client, je reçois l'avertissement:

Warning 65 warning C4192: automatically excluding 'IServiceProvider' while importing type library 'ServiceLibrary.dll' 

Sinon, vous pouvez essayer de le renommer à IServiceProvider2. C'est ce que j'ai fait, et tout fonctionne bien. J'utilise Visual Studio 2008.

Si ce code fonctionne correctement sur votre machine (il fonctionne parfaitement sur le mien), le problème pourrait être dans votre implémentation.

IDL:

import "oaidl.idl"; 

[ 
    object, 
    uuid(9219CC5B-31CC-4868-A1DE-E18300F73C43), 
    dual, 
    nonextensible, 
    helpstring("IService Interface"), 
    pointer_default(unique) 
] 
interface IService : IDispatch 
{ 
    HRESULT DoSomething(void); 
} 

[ 
    object, 
    uuid(9219CC5B-31CC-4868-A1DE-E18300F73C44), 
    dual, 
    nonextensible, 
    helpstring("IProvider Interface"), 
    pointer_default(unique) 
] 
interface IServiceProvider2 : IDispatch 
{ 
    HRESULT Init(IDispatch *sink, VARIANT_BOOL * result); 
    HRESULT GetService(LONG serviceIndicator, IService ** result); 
}; 

[ 
    uuid(9219CC5B-31CC-4868-A1DE-E18300F73C45), 
    version(1.0), 
] 
library ServiceLibrary 
{ 
    importlib("stdole2.tlb"); 

    interface IService; 
    interface IServiceProvider2; 
}; 

C#:

using System.Runtime.InteropServices; 
using System.Windows.Forms; 
using ServiceLibrary; 
using IServiceProvider=ServiceLibrary.IServiceProvider2; 

namespace COMInterfaceTester 
{ 
    [ComVisible(true)] 
    [Guid("2B9D06B9-EB59-435e-B3FF-B891C63108B2")] 
    public interface INewService : IService 
    { 
     string ServiceName { get; } 
    } 

    [ComVisible(true)] 
    [Guid("2B9D06B9-EB59-435e-B3FF-B891C63108B3")] 
    public class NewService : INewService 
    { 
     public string _name; 

     public NewService(string name) 
     { 
      _name = name; 
     } 

     // implement interface 
     #region IService Members 

     public void DoSomething() 
     { 
      MessageBox.Show("NewService.DoSomething"); 
     } 

     #endregion 

     public string ServiceName 
     { 
      get { return _name; } 
     } 
    } 

    [ComVisible(true)] 
    [Guid("2B9D06B9-EB59-435e-B3FF-B891C63108B4")] 
    public interface INewProvider : IServiceProvider 
    { 
     // adds nothing, just implements 
    } 

    [ComVisible(true)] 
    [Guid("2B9D06B9-EB59-435e-B3FF-B891C63108B5")] 
    public class NewProvider : INewProvider 
    { 
     // implement interface 
     public void Init(object sink, ref bool result) 
     { 
      MessageBox.Show("NewProvider.Init"); 
     } 

     public void GetService(int serviceIndicator, ref IService result) 
     { 
      result = new NewService("FooBar"); 
      MessageBox.Show("NewProvider.GetService"); 
     } 
    } 
}  

C++ Client:

#include "stdafx.h" 
#include <iostream> 
#include <atlbase.h> 
#import "COMInterfaceTester.tlb" raw_interfaces_only 
#import "ServiceLibrary.dll" raw_interfaces_only 

using std::cout; 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    CoInitialize(NULL); //Initialize all COM Components 
    COMInterfaceTester::INewProviderPtr pNewProvider(__uuidof(COMInterfaceTester::NewProvider)); 
    ServiceLibrary::IServiceProvider2 *pNewProviderPtr; 

    HRESULT hr = pNewProvider.QueryInterface(__uuidof(ServiceLibrary::IServiceProvider2), (void**)&pNewProviderPtr); 

    if(SUCCEEDED(hr)) 
    {  
     VARIANT_BOOL result = VARIANT_FALSE; 
     int *p = NULL; 

     hr = pNewProviderPtr->Init((IDispatch*)p, &result); 

     if (FAILED(hr)) 
     { 
      cout << "Failed to call Init"; 
     } 

     ServiceLibrary::IService *pService = NULL; 
     hr = pNewProviderPtr->GetService(0, &pService); 

     if (FAILED(hr)) 
     { 
      cout << "Failed to call GetService"; 
     } 
     else 
     { 
      COMInterfaceTester::INewService* pNewService = NULL; 
      hr = pService->QueryInterface(__uuidof(COMInterfaceTester::INewService), (void**)&pNewService); 

      if (SUCCEEDED(hr)) 
      { 
       CComBSTR serviceName; 
       pNewService->get_ServiceName(&serviceName); 

       if (serviceName == "FooBar") 
       { 
        pService->DoSomething(); 
       } 
       else 
        cout << "Unexpected service"; 

       pNewService->Release(); 

      } 

      pService->Release(); 
     } 

     pNewProviderPtr->Release(); 
    } 
    else 
     cout << "Failed to query for IServiceProvider2"; 

    pNewProvider.Release(); 
    CoUninitialize(); //DeInitialize all COM Components 

} 
+1

IServiceProvider est en fait défini dans l'espace de noms System - c'est probablement d'où proviennent les collisions de noms. – Eli

1

Vous devrez peut-être spécifier des attributs supplémentaires sur votre classe pour le rendre correctement marshal. Je voudrais regarder à travers les attributs disponibles here et peut-être regarder this tutorial si vous ne l'avez pas déjà fait.

+0

1 + Crap l'article codeprojects devrait être un livre bizarre. C'est énorme! – Terrance

Questions connexes