而到了20世纪90年代末期,随着商业逻辑处理的复杂化以及很多个性化的需求的出现,软件复杂度也开始提高,COM技术在应用技术领域也开始显得力不从心了。在这个时候就需要一种更灵活的、基于标准的技术来支撑应用软件的开发,.NET作为一个具有跨时代意义的应用软件的开发平台悄然而至。.NET以一种基于平台方式(应用软件依赖于某个平台,可移植性依赖于平台),又在一个更高的层次上实现了软件的复用。
3. 问题描述
为了保持.NET和COM技术的可互操作性,Microsoft提供一个专门的组件来解决这个问题,可以参考命名空间System.Runtime.InteropService。它不为.NET对原有的COM组件的调用提供了一种有效的方式,同时也为用.NET编写COM组件提供一种便利。
4. 步骤
Step 1构建.NET组件
n 新建一个.NET组件,如下图:
<?xml:namespace prefix = v /><?xml:namespace prefix = o />
n 设置这个.NET组件的COM可见性
设置工程属性:“生成”-> “为COM Interop注册”。
当然也可以为每个接口设置COM可见性,ComVisibleAttribute类提供了这样的控制。
Step 2定义组件接口
每个COM组件接口都有一个唯一的GUID,在.NET接口的定义中由Guid属性来指定
在这个例子中我定义了如下的接口:
[TypeLibType(4160)]
[Guid("F0485D81-59C1-44b1-9316-D474E26C026E")]
public interface IXMPReader
{
[DispId(0)]
string Metadata { get;set;}
[DispId(1)]
IXMPTemplate ReadTemplate(string xPath);
}
Step 3实现组件接口
每个COM组件接口的实现类也都有一个唯一的GUID,由Guid属性来定定义,
在IDL中对组件类的定义需要有一个Default(默认实现的接口声明), 在.NET组件中由ComDefaultInterface属性来定义。
在这个例子中我是这样实现了这个接口的,如下:
namespace XMPTemplate
{
[TypeLibType(4160)]
[Guid("AD665240-9E4D-4c30-9475-023EA44E41BD")]
[ComDefaultInterface(typeof(IXMPReader))]
[ComSourceInterfaces(typeof(IXMPReader))]
public class XMPReader : IXMPReader
{
private string _metadata="";
public string Metadata
{
get { return _metadata; }
set { _metadata = value; ; }
}
public IXMPTemplate ReadTemplate(string xPath)
{
XmlDocument document = new XmlDocument();
document.LoadXml(Metadata);
XmlNode node = document.SelectSingleNode(xPath);
XMPTemplate template = new XMPTemplate();
template.LoadXml(node.InnerXml);
return template;
}
}
Step 4部署
假设我们生成的.NET组件的名称是XMPTemplate.dll,访问路径为C:/ XMPTemplate.dll
n 利用Regasm工具来注册.NET组件
regasm C:/ XMPTemplate.dll
n 将这个.NET组件加入到全局程序集缓存中
Gacutil /I C:/ XMPTemplate.dll
Step 5 测试
n VC++调用
const wchar_t* progid = L"XMPTemplate.XMPReader"; CLSID clsid = CLSID_NULL; HRESULT hr = CLSIDFromProgID(progid,&clsid); IDispatch* pDispatch = NULL; CoCreateInstance(clsid,NULL,CLSCTX_INPROC,IID_IDispatch,(void**)&pDispatch); ATL::CComVariant varMetadata = tenant->GetMedata().c_str(); ATL::CComVariant varResult; DISPPARAMS params = {&varMetadata, NULL, 1, 0 }; pDispatch->Invoke(0, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPUT, ¶ms, &varResult, NULL, NULL);
varResult.Clear(); ATL::CComVariant varXPath = L"//"; DISPPARAMS paramsXPath ={&varXPath, NULL, 1, 0 }; pDispatch->Invoke(1, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, ¶msXPath, &varResult, NULL, NULL); pDispatch->Release(); |
5. 源代码
无