COM Callable Wrappers and Runtime Callable WrappersCOM调用包装和运行时调用包装
COM集成的机制是这样的,COM客户端通过COM调用包装(COM Callable Wrapper/CCW)来访问.NET组件,而.NET客户端则通过运行时调用包装(Runtime Callable Wrapper/RCW)来访问COM对象。当然,这个.NET客户端本身也可以是一个.NET组件,COM客户端也可以是一个COM对象。
一个CCW的行为对于COM客户端来讲就像一个COM对象,正如COM客户端所期望的。如图4-1所示,一个CCW为COM客户端提供了一些像IUnknown和IDispatch接口,尽管它们并没有被此.NET组件实现。同样,这个CCW也可以在注册表中被找到,因为COM客户端总是预期能在那里找到它们所需要的组件。当CCW上的方法被调用时,CCW就会调用.NET组件上相应的方法,并且通过进行COM引用计数来处理垃圾收集的问题。
CCW也会处理数据类型的转换,这是因为.NET和COM中的数据类型是不一致的。一些数据类型可以直接地映射,因为它们在内存中的结构是一致的,而另外的都必须被转换。那些具有相同内存存储结构的数据类型被称为Blittable数据类型(比如,System.Int16、System.Int32、System.Int64)。.NET中的System.String类型会被转换为COM的BSTR类型,BSTR是非Blittable数据类型。
图4-1 一个COM调用包装
反过来,RCW(见图4-2)管理一个COM对象,向一个.NET客户端提供预期的功能。RCW对于COM对象来说是一个具有良好行为的客户端,并且为.NET客户端提供了纯.NET的功能。在.NET中,你不需要为每个COM接口释放引用,因为这会被RCW自动完成。然而,你仍然需要注意垃圾收集器不定期地释放内存的行为。因为你处理的是像COM对象这样的非托管资源,你必须通晓Dispose Pattern6。需要显式地释放COM对象上的引用的话,你可以使用Marshal类的ReleaseComObject方法。你可以在命名空间System.Runtime.InteropServices中找到这个类。
图4-2 一个运行时调用包装(RCW)
Default COM ConfigurationCOM的默认配置
首先让我们看一下.NET组件如何被COM客户端使用。这里是一个简单的示例,它没有使用任何特性来配置COM选项。在这个示例中,创建了两个服务组件类和一些用于传
递数据的类。在代码段4-1中,前面两个Customer类和CourseInfo类是两个简单的类型,它们可以作为参数传递。这些类型都只有私有的成员变量和公有的属性以用于访问这些变量。为了让这些类型可以在网络上传递,它们必须被标记以[Serializable]特性。
代码段4-1 可序列化的类型
[Serializable]
public class Customer
{
private string name;
private string company;
public Customer(string name, string company)
this.name = name;
this.company = company;
}
public string Name
get
return name;
public string Company
return company;
public class CourseInfo
private string number;
private string title;
private int length;
private DateTime date;
public CourseInfo(string number, string title, int length,
DateTime date)
this.number = number;
this.title = title;
this.length = length;
this.date = date;
public string Number
return number;
public string Title
return title;
public int Length
return length;
public DateTime Date
return date;
代码段4-2和4-3展示了服务组件类的实现。CourseManagement类实现了接口ICourseManagement,此接口定义了三个方法:GetCourse、SetCourse和GetCourseControl。GetCourse返回一个CourseInfo对象到客户端,而SetCourse则
用于传递一个CourseInfo对象到服务器。GetCourseControl返回一个到CustomerControl对象(它自己也是一个服务组件)的引用。方法SetCourse会显示一个消息框来测试这个组件。为了使用MessageBox类,你必须引用System.Windows.Forms程序集然后导入System.Windows.Forms命名空间。
代码段4-2 CourseManagement组件
public interface ICourseManagement
CourseInfo GetCourse();
void SetCourse(CourseInfo course);
CustomerControl GetCustomerControl();
[EventTrackingEnabled]
public class CourseManagement : ServicedComponent,
ICourseManagement
public CourseManagement()
public CourseInfo GetCourse()
CourseInfo course = new CourseInfo(
"MS-2557",
"Developing Component-based Applicatons", 5,
new DateTime(2003, 8, 18));
return course;
public void SetCourse(CourseInfo course)
MessageBox.Show("Course: {0}", course.Title);
public CustomerControl GetCustomerControl()
CustomerControl control = new CustomerControl();
return control;
事实查证:使用对话框
在真正的应用中,不要在运行于服务器上的服务组件中打开对话框(比如,消息框),这些对话框永远不会被看到和得到应答。错误记录和监视可以通过使用事件日志和性能监视器实现。只有当这个服务组件运行于客户端时,使用对话框来和用户交互才是可行的。
CustomerControl类,与CourseManagement类相比,它没有实现什么接口,这只是用于向你展示为COM客户端生成的代码上的区别。此外,它还被标记了[Private Component]特性,因为这个类型不需要被客户端应用程序实例化,其对象只能在企业服务应用程序内部创建。方法GetCustomer会返回一个新的Customer对象。
代码段4-3 CustomerControl组件
[PrivateComponent]
public class CustomerControl : ServicedComponent
public CustomerControl()
public Customer GetCustomer()
Customer c = new Customer("Stephane", "Addison Wesley");
return c;
发表于 @ 2006年12月27日 11:27:00|评论(loading...)|编辑