2008-10-12 8 views
6

Aufgrund Unternehmen Zwänge aus meiner Kontrolle, habe ich folgendes Szenario:Ableitung COM-Schnittstellen in .NET

Ein COM-Bibliothek, die die folgende Schnittstelle (keine CoClass, nur die Schnittstelle) definiert:

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

Ich habe eine COM (geschrieben w/C++), die beide Schnittstellen implementiert und bietet unsere Anwendung (en) mit diesem Dienst. Alles ist gut, denke ich.

Ich versuche, eine neue IProvider und IService in .NET (C#) zu bauen.

ich eine primäre Interop-Assembly für die COM-Bibliothek erstellt habe, und implementiert die folgenden 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 
} 

Wenn ich versuche, diese in die bestehenden Laufzeit zu rutschen, ich bin in der Lage, das NewProvider Objekt erstellen aus COM (C++) und QueryInterface für IServiceProvider. Wenn ich versuche, eine Methode auf dem IServiceProvider aufzurufen, wird System.ExecutionEngineException ausgelöst.

Die einzige andere Sache, die ich finden kann, ist durch Blick auf die TLI-Dateien von der #import erstellt, zeigt die Legacy COM IExistingProvider-Klasse zeigt richtig, dass es von IServiceProvider abgeleitet ist. Die .NET-Klasse zeigt jedoch eine Basis von IDispatch. Ich bin mir nicht sicher, ob dies ein Zeichen, eine Indikation, hilfreich oder etwas anderes ist.

+0

Wenn Sie sagen, Sie haben "gebaut" eine primäre Interop-Assembly, meinen Sie von Grund auf neu ? Ist es nicht möglich, die COM-Bibliothek als Referenz hinzuzufügen? – ilitirit

+0

Ich baute den PIA aus der TLBIMP.exe. Möchten Sie eine Beispielbefehlszeile dafür sehen? Ich habe TLBIMP verwendet, meine eigene Interop.Services.dll erstellt, dann verweisen Sie darauf. Ich habe vor kurzem ".NET und COM - The Complete Interoperability Guide" erworben. – DevSolo

+0

Gibt es einen Grund, warum Sie die Bibliothek nicht direkt in Visual Studio importiert haben oder Visual Studio nicht verwenden? – ilitirit

Antwort

5

Es könnte ein Problem mit dem Namen IServiceProvider sein. Überprüfen Sie, ob Sie eine Schnittstelle mit demselben Namen bereits importiert haben.

Wenn ich eine COM-Schnittstelle Bibliothek mit Ihrer IDL erstellen und dann versuchen, es von einem anderen Client zu importieren, erhalte ich die Warnung:

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

Andernfalls können Sie versuchen, es zu IServiceProvider2 umbenannt. Das habe ich gemacht, und alles funktioniert gut. Ich verwende Visual Studio 2008.

Wenn dieser Code ordnungsgemäß auf Ihrem Computer ausgeführt wird (es funktioniert perfekt auf mir), dann könnte das Problem in Ihrer Implementierung sein.

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

#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 ist tatsächlich im System-Namespace definiert - das ist wahrscheinlich der Ursprung der Namenskonflikte. – Eli

1

Möglicherweise müssen Sie zusätzliche Attribute für Ihre Klasse angeben, damit sie ordnungsgemäß marshallen können. Ich würde durch verfügbare Attribute here schauen und vielleicht this tutorial betrachten, wenn Sie nicht bereits getan haben.

+0

1 + Mist der Codeprojekte Artikel sollte ein freakin Buch sein. Es ist riesig! – Terrance

Verwandte Themen