2008-10-12 14 views
6

powodu ograniczeń firmy z mojej kontroli, mam następujący scenariusz:wynikających interfejsy COM w .NET

bibliotekę

COM, który określa następujące interfejs (nie CoClass, po prostu interfejs):

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

Mam COM (napisane w/C++), który implementuje oba interfejsy i zapewnia nasze aplikacje z tej usługi. Wszystko jest w porządku, myślę.

Próbuję zbudować nowy IProvider i IService w .NET (C#).

I został zbudowany Primary Interop Assembly dla biblioteki COM i realizowane następujące 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 
} 

Przy próbie poślizgu to do istniejącego środowiska wykonawczego, jestem w stanie utworzyć obiekt NewProvider od COM (C++) i QueryInterface dla IServiceProvider. Kiedy próbuję wywołać metodę na IServiceProvider, generowany jest System.ExecutionEngineException.

Jedyne, co mogę znaleźć, to patrząc na pliki .tlh utworzone przez #import, pokazuje starszą klasę COM IExistingProvider poprawnie pokazuje, że pochodzi ona od IServiceProvider. Jednak klasa .NET pokazuje bazę IDispatch. Nie jestem pewien, czy to znak, wskazówka, pomocna, coś jeszcze.

+0

Kiedy mówisz, że już "wbudowany" a Primary Interop Assembly, to znaczy od podstaw ? Czy nie było możliwe dodanie biblioteki COM jako punktu odniesienia? – ilitirit

+0

Zbudowałem PIA z TLBIMP.exe. Czy chcesz zobaczyć przykładowy wiersz poleceń? Użyłem TLBIMP, tworząc własny plik Interop.Services.dll, a następnie odwołuję się do tego. Niedawno poznałem ".NET i COM - przewodnik po pełnej interoperacyjności". – DevSolo

+0

Czy istnieje powód, dla którego nie zaimportowano biblioteki bezpośrednio do programu Visual Studio, czy też nie używasz programu Visual Studio? – ilitirit

Odpowiedz

5

Może to być problem z nazwą IServiceProvider. Sprawdź, czy nie zaimportowałeś jeszcze interfejsu o tej samej nazwie.

Kiedy utworzyć bibliotekę COM przy użyciu interfejsu swoją IDL, a następnie spróbuj zaimportować go z innego klienta, pojawia się ostrzeżenie:

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

W przeciwnym razie, można spróbować zmieniając jego nazwę na IServiceProvider2. Tak właśnie zrobiłem i wszystko działa dobrze. Używam Visual Studio 2008.

Jeśli ten kod działa poprawnie na twoim komputerze (działa to doskonale na moim), problem może tkwić w twojej implementacji.

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

#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 jest faktycznie zdefiniowany w obszarze nazw System - prawdopodobnie jest to miejsce, z którego pochodzą kolizje nazywania. – Eli

1

Być może będziesz musiał określić dodatkowe atrybuty na swojej klasie, aby mieć pewność, że są poprawne. Przejrzałbym dostępne atrybuty here i może spojrzeć na this tutorial, jeśli jeszcze tego nie zrobiłeś.

+0

1 + Crap artykuł codeprojekty powinien być kapryśna książka. To jest ogromne! – Terrance

Powiązane problemy