由于公司的限制,我有以下情况:
定义以下接口的COM库(没有CoClass,只是接口):
[
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;
};
我有一个COM(用C ++编写),它实现了两个接口,并为我们的应用程序提供了所述服务。一切都很好,我想。
我正在尝试在.NET(C#)中构建新的IProvider
和IService
。
我为COM库构建了一个主Interop程序集,并实现了以下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
}
当我尝试将其放入现有运行时时,我能够从COM(C ++)创建NewProvider
对象,并为IServiceProvider创建QueryInterface
。当我尝试在IServiceProvider上调用方法时,抛出System.ExecutionEngineException
。
我能找到的唯一另一件事是查看#import创建的.tlh文件,显示遗留的COM IExistingProvider类正确显示它是从IServiceProvider派生的。但是,.NET类显示了IDispatch的基础。我不确定这是一个标志,指示,有用还是别的。
答案 0 :(得分:5)
名称 IServiceProvider 可能存在问题。检查您是否尚未导入具有相同名称的接口。
当我使用您的IDL创建COM接口库,然后尝试从其他客户端导入它时,我收到警告:
Warning 65 warning C4192: automatically excluding 'IServiceProvider' while importing type library 'ServiceLibrary.dll'
否则,您可以尝试将其重命名为IServiceProvider2。这就是我所做的,一切正常。我正在使用Visual Studio 2008。
如果此代码在您的计算机上正常运行(它在我的计算机上运行正常),则问题可能出在您的实现中。
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 ++客户端:
#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 :(得分:1)
您可能必须在类上指定其他属性才能正确编组。我会查看可用的属性here,如果您还没有这样做,可以查看this tutorial。