PortClass中的COM
一般的Windows驱动我们采用的是WDM驱动架构,最近的Windows驱动架构WDF也是建立在WDM基础上的。这些基于WDM的一般设备驱动可以应付大部分的设备驱动,如串口,PCI,USB等通用设备驱动。但是微软的关于流的处理的一些服务及驱动采用的面向对象的设计方法,是基于COM进行开发的,典型的像ks.sys,portcls.sys等。
通过WINDOWS驱动的概念可知,mini端口驱动一般是向其端口提供一组回调函数,并通过端口驱动提供的特定的函数向端口驱动进行注册。同样在注册期间,mini端口会告诉端口驱动程序微型端口将需要的上下文结构的大小。端口驱动程序将函数表复制到某个私有位置,分配上下文结构并调用函数表中的初始化函数,将指针传递给上下文结构。
音频mini端口驱动使用和常见的mini端口驱动类似的方法,不过由mini端口驱动提供的函数表不再进行程序复制,再不再承承担上下文的责任,而是以COM的形式创建。COM形式的创建像C++的类一样,其以函数表以COM类的成员函数在编译时静态创建。
采用COM开发的原因是因为COM为创建抽象对象提供了一种可靠、高效、广为理解的形式主义。音频MiniPort模型利用了COM的行业经验。此外,COM通过将不安全的强制转换隔离到一些函数来增强代码安全性。对象可以在C或C++中实现和使用。也可以使用汇编,但这会妨碍可移植性。
在用户模式下,COM对象是使用函数CoCreateInstance()或类似函数创建的。使用这样的函数意味着对象所需的内存是以客户机不知道的方式分配的。在内核模式下,需要严格控制内存的分配。因此,使用了不同的对象创建方法。
在音频驱动程序模型中使用的COM方面包括接口的概念和IUnknown接口的定义。尽管有一种类似于进程内服务器的机制,但驱动程序开发人员不需要构建这样的服务器或访问注册表。Mini端口也被正式排除在支持聚合之外,尽管示例代码演示了一种支持聚合的简单方法。
COM创建
NTSTATUS
CreateMyObject
(
OUT PUNKNOWN * Unknown,
IN REFGUID ClassId,
IN PUNKNOWN OuterUnknown OPTIONAL,
IN POOL_TYPE PoolType
);
前三个参数与COM的CoCreateInstance()的参数相同。指向对象的IUnknown接口的指针通过Unknown传回,类GUID作为ClassId传递(仅在create函数创建多个类的对象时使用),OuterUnknown为聚合新对象的对象提供未知接口(通常为NULL)。最后一个参数指定要从中分配对象的池的类型。
另一个约定是为类提供一个新函数,该函数创建一个对象,初始化它,并传回一个指向调用者可能想要的接口的指针。因为初始化参数是类特定的,所以新函数的原型也是类特定的。
NTSTATUS
NewMyObject
(
OUT PMYINTERFACE * FavoredInterfacePointer,
IN PUNKNOWN OuterUnknown OPTIONAL,
IN POOL_TYPE PoolType,
// more parameters
);
这些函数提供了实例化(创建和初始化)对象的简单方法。
示例代码通过提供支持引用计数和聚合的类简化了COM对象实现。对象的作者提供获取对象接口所需的函数。辅助类(CUness)是用C++编写的。