2008-10-12 21 views
6

Debido a las limitaciones de la compañía fuera de mi control, tengo el siguiente escenario:Derivación de interfaces COM en .NET

biblioteca

COM que define la interfaz siguiente (sin Coclase, sólo la interfaz):

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

Tengo un COM (escrito con C++) que implementa ambas interfaces y proporciona nuestra aplicación (s) con dicho servicio. Todo está bien, creo.

Estoy tratando de construir un nuevo IProvider y IService en .NET (C#).

he construido un ensamblado de interoperabilidad primario para la biblioteca COM, e implementó el siguiente 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 
} 

Cuando intento deslizarse esto en el tiempo de ejecución existente, soy capaz de crear el objeto NewProvider de COM (C++) y QueryInterface para IServiceProvider. Cuando intento llamar a un método en IServiceProvider, se lanza un System.ExecutionEngineException.

La única otra cosa que puedo encontrar, es mirando los archivos .tlh creados por #import, muestra que la clase heredada COM IExistingProvider muestra correctamente que se deriva de IServiceProvider. Sin embargo, la clase .NET muestra una base de IDispatch. No estoy seguro de si esto es un signo, una indicación, útil, algo más.

+0

Cuando dice que ha "construido" un ensamblado de interoperabilidad primario, quiere usted decir desde cero ? ¿No fue posible simplemente agregar la biblioteca COM como referencia? – ilitirit

+0

Creé el PIA desde TLBIMP.exe. ¿Le gustaría ver una línea de comando de ejemplo para ello? Utilicé TLBIMP, creando mi propio Interop.Services.dll, y luego hice referencia a eso. Recientemente adquirí ".NET y COM - La Guía completa de interoperabilidad". – DevSolo

+0

¿Hay alguna razón por la que no importó la biblioteca directamente en Visual Studio? ¿O no está utilizando Visual Studio? – ilitirit

Respuesta

5

Podría ser un problema con el nombre IServiceProvider. Verifique que no haya importado una interfaz con el mismo nombre.

Al crear una biblioteca de interfaz COM utilizando el IDL, y luego tratar de importarlo de otro cliente, me sale la advertencia:

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

De lo contrario, puede intentar cambiar el nombre a IServiceProvider2. Eso es lo que hice, y todo funciona bien. Estoy usando Visual Studio 2008.

Si este código se ejecuta correctamente en su máquina (funciona perfectamente en la mía), entonces el problema podría estar en su implementación.

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++ Cliente:

#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 en realidad se define en el espacio de nombres del sistema; es probable que de allí provengan las colisiones de nombres. – Eli

1

Es posible que deba especificar atributos adicionales en su clase para que se consoliden correctamente. Me gustaría ver los atributos disponibles here y tal vez mirar this tutorial si aún no lo ha hecho.

+0

1 + Mierda el artículo de los proyectos de código debería ser un libro extraño. ¡Es enorme! – Terrance

Cuestiones relacionadas