以下过程介绍如何使用 ATL 版本 2.1 或 ATL 版本 3.0 和 MSP 基类实现 MSP。 有关详细信息以及库和标头的列表,请参阅 TAPI 3 MSP 基类。 本主题中包含的内容假定开发人员对 ATL 和 COM 有一定的了解,并且具有使用 ATL 实现 COM DLL 的经验。
使用 ATL 2.1 或 ATL 3.0 实现和 MSP
为 MSP 创建 IDL 文件。 此文件定义 MSP 的 CLSID。 将 MSP“coclass”声明为实现 ITMSPAddress 接口,并将此接口声明为类对象上的默认接口。 对于 ITMSPAddress 的定义,请导入文件“msp.idl”。 将 MSP“coclass”包含在 MSP 的类型库中。 如果 MSP 支持专用 (自定义) 接口,请在此处定义它们并将其包含在类型库中。 下面的代码示例是如上所述的 IDL 文件,没有自定义接口。
import "msp.idl"; [ uuid(4DDB6D35-3BC1-11d2-86F2-006008B0E5D2), version(2.0), helpstring("Wave MSP 2.0 Type Library") ] library WAVEMSPLib { importlib("stdole32.tlb"); importlib("stdole2.tlb"); [ uuid(4DDB6D36-3BC1-11d2-86F2-006008B0E5D2), helpstring("Wave MSP Class") ] coclass WaveMSP { [default] interface ITMSPAddress; }; };
修改 TSP 以在Tapi3.dll请求时播发 MSP 的 CLSID。 确保 (1) TSP 可以在 TSPI 函数 TSPI_lineNegotiateTSPIVersion中协商TAPI_VERSION3_0或更高版本, (2) TSP LINEDEVCAPS 结构在 dwDevCapFlags 成员中设置了LINEDEVCAPFLAGS_MSP标志, (3) TSP 在 TSPI 函数 TSPI_lineMSPIdentify返回 MSP CLSID。 这应与 IDL 文件中指定的 CLSID 相同;例如,上一步中示例 IDL 文件中的第二个“uuid”行。
编译位于平台软件开发工具包 (SDK) 中的 MSPBase 示例应用程序,以创建 MSPBaseSample.lib 库。
将 MSP DLL 与 MSPBaseSample.lib 库链接。
包括 MSP 基类定义的 SDK 中的 Mspbase.h。
(实现 DLL 导出,例如 DllMain) 。 Microsoft Visual C++将生成这些内容。 在 DllMain 中,分别在 DLL_PROCESS_ATTACH 和 DLL_PROCESS_DETACH 上使用 MSPLOGREGISTER 和 MSPLOGDEREGISTER 宏为 DLL 启用日志记录功能。 在 MSPLOGDEREGISTER 调用中指定 DLL 的名称。
使用 Msplog.h 中定义的 LOG 宏以与基类相同的方式输出跟踪消息。 定义 MSPLOG 预处理器符号以在 DLL 中包含日志记录;使生成没有日志记录的 DLL 保留为未定义。
从 CMSPAddress 派生一个实现 MSP 地址的类。 声明全局 ATL 对象映射,当系统要求对 IDL 文件中指定的 CLSID 进行 CoCreate 时,该映射指示 ATL 创建地址类的实例。 此外,请从 ATL CComCoClass 模板派生地址类,并在地址类中包含 DECLARE_REGISTRY_RESOURCEID 声明。 构造相应的资源脚本和头文件,与任何其他 ATL COM DLL 一样。
为地址类实现所需的 CMSPAddress 替代。 对于 MSPAddressAddRef 和 MSPAddressRelease,请调用提供的帮助程序函数模板。 对于 GetCallMediaTypes,只需返回 一个 DWORD 位图,其中包含所有 MSP 支持的 TAPIMEDIAMODEs ORed。 对于 CreateMSPCall 和 ShutdownMSPCall,此时返回E_NOTIMPL并编译和链接 MSP。 现在,请验证是否可以从 TAPI 3 应用程序注册和实例化 MSP,但无法成功创建调用。
从 CMSPCallMultiGraph 派生类以实现 MSP 调用对象。 如果 filter-graph-per-stream 模型不符合要求,则可能需要从 CMSPCallBase 而不是 CMSPCallMultiGraph 派生;这将增加任务的复杂性, (编写本文时,所有 MSP 直接从 CMSPCallMultiGraph) 派生调用对象。 在 address 对象中,实现 CreateMSPCall 和 ShutdownMSPCall ,以使用提供的帮助程序函数模板创建和关闭特定类型的调用对象。 在调用对象中,重写 CreateStreamObject 以返回E_NOTIMPL。 以与相应地址方法相同的方式替代 MSPCallAddRef 和 MSPCallRelease 。 同样,你应该能够编译和链接 MSP;它现在应该能够创建和关闭调用,但这些调用不会执行任何有用的流式处理。
从 CMSPStream 派生类以实现 MSP 流对象。 在调用对象中,实现 CreateStreamObject 以创建和初始化流对象 (通常方法是调用 ATL CreateInstance,然后调用 ITStream 的 ATL _InternalQueryInterface,然后在流对象) 上调用 Init。 为了支持固定数量的流 (这很常见,对于不支持在调用) 上由其他终结点修改流配置的 MSP,请重写调用对象上的 Init、 CreateStream 和 RemoveStream 。 (调用 Init 最初创建所有流, CreateStream 和 RemoveStream 返回相应的 TAPI 错误代码,以防止应用程序) 创建或删除流。 否则,请重写调用的 Init 方法,以使用为调用请求的媒体类型创建流的一些初始默认配置。 在调用的 Init 方法中创建任何默认流对象时,请使用 InternalCreateStream 帮助程序方法。
实现流对象。 唯一需要的替代是 get_Name 方法,该方法仅返回流的友好名称。 此外,还需要重写其他几种方法。 具体要替代的方法取决于实现,以及你决定执行构造和析构筛选器图所涉及的各种任务。 这些任务包括创建适当的“传输”筛选器、编解码器等,并在适当的时候插入它们并从筛选器图中删除它们。 还必须使用终端对象上的 ITTerminalControl 接口将所选终端连接到流。 你可能想要替代流对象上的 SelectTerminal 和 UnselectTerminal ,以限制流将接受的终端配置;将每个流限制为单个终端将特别简化筛选器图的构造,但会牺牲应用程序功能,例如视频预览。 根据你的实现,你将在 StartStream、StopStream、PauseStream、Initialize、Shutdown、SelectTerminal 和 UnselectTerminal 方法中放置图形构造、析构和终端连接代码,或者放置在你自己的基于专用 TSP 通信的方法中。 请注意,未选择任何终端的流必须跟踪所需的图形状态; StartStream 调用后跟此类流上的 SelectTerminal 调用必须生成数据流。 重写其中大多数方法,以确保根据流的状态在每种情况下都发生正确的构造、析构、连接和断开连接。
实现 TSP 通信。 重写 CMSPAddress::ReceiveTSPAddressData 和/或 CMSPCallBase::ReceiveTSPCallData,和/或通过在地址对象上调用 PostEvent 或调用对象上的 HandleStreamEvent (从调用对象或流对象) 。
在地址对象上使用 PostEvent,或在调用对象上使用 HandleStreamEvent, (从调用对象或流对象) 通过Tapi3.dll将调用媒体事件发送到应用程序。 通常会在流对象(包括 ProcessGraphEvent、 StopStream、 StartStream、 PauseStream、 SelectTerminal 和 UnselectTerminal 方法)中重写的方法中执行此操作,具体取决于实现流的方式。
在现有对象上实现任何所需的专用接口或子流, (地址、调用和流) 。 通常没有。 请注意,在实现专用接口时,请从 IDL 文件指定类型库的 LIBID。 也就是说,应用程序程序员在使用自定义接口时必须使用 MSP 类型库。 在 MSP 基类中实现的标准 MSP 接口使用 Tapi3.dll LIBID,因此可供所有 TAPI 3 应用程序访问。
如果实现特定于 MSP 的静态或动态终端对象或默认静态终端的替换 (非典型) ,则可以使用提供的终端基类。 必须重写地址对象上的各种方法,以提供创建终端对象的替代方法或其他方法。
在 Address、Call、Stream 和 Terminal 对象上实现 IObjectSafety 接口。 若要使用 Dispatch Mapper 查询 MSP 对象上的接口,请将对象标记为安全,以便在这些接口上编写脚本。 为此,请在对象上实现 IObjectSafety 接口。 从 CMSPObjectSafetyImpl 派生 (Msputils.h) 中提供的帮助程序类,并将 IObjectSafety 添加到类的 ATL COM_MAP将使对象能够安全地在它们公开的所有接口上编写脚本。 请注意,在 MSP 对象上使用 Dispatch Mapper 可能是隐式的。 MSP 地址和 MSP 呼叫由 TAPI 地址和 TAPI 呼叫对象聚合。 如果在 TAPI 对象上使用 Dispatch Mapper 来查询聚合 MSP 对象公开的接口,则会查询聚合的 MSP 对象,以确保所请求的接口的安全性。