c# c++ .net interface com

c# - Derivar interfaces COM en.NET



c++ (2)

Debido a restricciones de la compañía fuera de mi control, tengo la siguiente situación:

Una biblioteca COM que define la siguiente interfaz (no CoClass, solo 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 (s) aplicación (es) con dicho servicio. Todo está bien, creo.

IProvider crear un nuevo IProvider e IService en .NET (C #).

Creé un ensamblado de interoperabilidad primaria 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 deslizar esto en el tiempo de ejecución existente, puedo crear el objeto NewProvider partir de COM (C ++) y QueryInterface para IServiceProvider. Cuando intento llamar a un método en IServiceProvider, se lanza 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.


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


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

Cuando creo una biblioteca de interfaz COM utilizando su IDL, y luego trato de importarlo desde otro cliente, aparece la advertencia:

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

De lo contrario, puede intentar cambiarle 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; };

DO#:

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"); } } }

Cliente C ++:

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