COM 宏架构拓扑 - 客户端






4.54/5 (8投票s)
2001年7月25日
6分钟阅读

119841
关于 COM 架构、COM 客户端和注册表的文章
目的
本文介绍如何实现一个简单的客户端应用程序。它将使用 MFC 架构和 ATL 以 C++ 开发。
要求
所有这些示例代码均使用 C++ 编写,在 Windows 2000 下使用 Visual C++ 6.0 (sp4)。它们还使用了 Active-X Template Library (ATL v3.0)。
本系列中的其他文章
本文是“COM 宏架构拓扑”系列的一部分。以下是其他文章的链接
- 主文章 “COM 宏架构拓扑” (您可以在本文档中下载源代码)。
- COM 服务器 “COM 宏架构拓扑 (服务器)”。
- COM ID 和注册表项概览.
简单的客户端应用程序
最终我们要实现的目标
最终的客户端应用程序将是一个简单的基于 MFC 对话框的应用程序。它将使用 MFC (Microsoft Foundation Classes) 框架中的Afx???()
函数。此外,它看起来会像这样 (或类似的样子)
创建项目
为了创建客户端应用程序,您需要按照以下步骤操作- 启动 Visual C++ IDE,选择 文件,新建,然后按如下方式填写

- 您想要创建一个基于对话框的应用程序
- 单击下一步。

- 取消选中ActiveX 控件支持选项。
- 您可以更改标题。
- 单击下一步。

- 保留默认设置。
- 单击下一步。

- 单击完成。

之后,MFC 向导将创建这些文件
- 工作区:
macrotopoclient.dsw
- 项目:
macrotopoclient.dsp
- 应用程序代码在
macrotopoclient.h/cpp
- 对话框代码在
macrotopoclientDlg.h/cpp
COM 初始化和反初始化
您需要在客户端应用程序中初始化和反初始化 COM。这里因为我们正在构建一个 MFC 应用程序,所以我们将使用Afx???()
函数AfxOleInit()
用于初始化 COM。AfxOleTerm()
用于反初始化 COM。
找到我们客户端 MFC 应用程序 (例如
CMacrotopoclientApp
) 的 InitInstance()
方法,并添加这些行BOOL CMacrotopoclientApp::InitInstance() { // Initialise OLE libraries and COM. if (!AfxOleInit()) { AfxMessageBox("Error when Initialising COM."); return(FALSE); } ... CMacrotopoclientDlg dlg; m_pMainWnd = &dlg; int nResponse = dlg.DoModal(); ... AfxOleTerm(); // Since the dialog has been closed, return FALSE so that we exit the // application, rather than start the application's message pump. return(FALSE); }
当然,您也可以使用常规的 COM API 函数:
CoInitializeEx()
和 CoUninitialize()
。但是,您需要使用预处理器定义 _WIN32_DCOM
。用户界面
为了简化操作,我们将创建推送按钮并将它们绑定到对话框类的方法。这些方法将调用 COM 服务器。使用资源编辑器添加一个如下所示的按钮
- 在工作区视图中单击
ResourceView
。 - 打开 Dialog 文件夹,然后双击您的应用程序的对话框资源 (例如
IDD_MACROTOPOCLIENT_DIALOG
)。

起初,您的对话框资源只有 2 个推送按钮 (
OK
和 Cancel
) 和一个静态文本控件 (TODO: Place dialog controls here.
)
通过选择静态文本控件并按 Delete 键删除它。
在
Controls toolbar
中选择推送按钮控件工具
- 右键单击对话框中的任意位置,
- 按住鼠标右键并移动鼠标以初始化推送按钮的大小,
- 然后释放鼠标右键。
- 左键单击您的推送按钮,
- 从弹出菜单中选择
Properties
, - 然后
- 更改
ID
:IDBUT_MACROTOPOEXE_DISP_SHOWHELLO
, - 更改
Caption
:ShowHello()
...
- 更改

要将推送按钮绑定到方法,请双击它。将出现一个“
Add member function
”对话框。如果需要,您可以更改成员函数的名称,否则只需单击 OK。此对话框显示将用于推送按钮控件 (ID:
IDBUT_MACROTOPOEXE_DISP_SHOWHELLO
) 接收到 BN_CLICKED
控件消息的成员函数名称 (OnMacrotopoexeDispShowhello()
)。调用 COM 服务器
现在我们的对话框中有一个推送按钮,并且它的 Click 事件绑定到了我们对话框类 (例如CMacrotopoclientDlg
) 的一个方法。下一步是调用我们的 COM 服务器。要编写此代码,您将使用“#import
”语句///////////////////////////////////////////////////////////////////////////// // MacroTopoExe - Disptach & Custom. #import "../bin/macrotoposerver_exe.exe" void CMacrotopoclientDlg::OnMacrotopoexeDispShowhello() { try { using namespace MACROTOPOSERVER_EXELib; IMacroTopoDispPtr pDisp(__uuidof(CoMacroTopo)); pDisp->ShowHello(); } catch(_com_error &) { ::MessageBox(GetSafeHwnd(), _T("DCOM exception."), _T("OnMacrotopoexeDispShowhello()"), MB_OK | MB_ICONSTOP); } }上面的代码使用
#import
语句从 COM 服务器 (例如 macrotoposerver_exe.exe、macrotoposerver_dll_psdll.dll 或 macrotoposerver_dllmerged.dll) 获取类型信息。它尝试从应该实现它的 COM 对象
CoMacroTopo
获取 IMacroTopoDisp
的接口指针。如果失败,将引发一个COM 异常 (使用 _com_error
类)。这段代码非常简短,但实际上
#import
指令已经为您生成了包装代码。查看您的“.\Debug
”目录 (如果您在Debug模式下工作),您会找到 2 个文件- macrotoposerver_exe.tlh 是一个头文件,其中包含 COM 服务器中存储的类型库中的类型信息的 C++ 版本。
- macrotoposerver_exe.tli 是包含内联接口成员函数的文件的文件,这些函数作为 COM 对象实现的远程接口方法的包装器。
- 重复创建推送按钮,
- 将其单击事件绑定到对话框的新成员函数
- 使用上面的代码片段作为模板来调用另一个函数。
#import 语句
#import 语句是Visual C++ 编译器指令,并且像许多其他 Microsoft 工具一样,它与 COM 配合得非常好。此指令可以看作是 COM AppWizard,在这种意义上,它有助于 C++ 开发人员获取在类型库 (COM 服务器内部) 中描述的内容的 C++ 表示。类型库及其信息 (实际上是 COM 服务器元数据信息) 可以存在于扩展名为 TLB、EXE、DLL 和 OCX 的文件中。
#import
语句将在您的当前构建工作目录 (例如,如果您在 Debug 模式下工作,则是“.\Debug”) 中生成 2 个文件- TLH 文件扩展名是一个头文件,其中包含来自类型库 COM 服务器的类型信息的 C++ 版本。
所有类型信息都存在于 C++ 命名空间中,以避免逻辑名称 (或可读名称) 之间的冲突。
此文件中的接口智能指针被声明。
在此文件末尾,定义了一个#include "filename.tli"
语句,以包含#import
语句生成的第二个文件。 - TLI 文件扩展名是包含内联接口成员函数实现的文件的文件。这些成员函数作为 COM 对象实现的远程接口方法的包装器。
深入了解
如果您想更深入地了解 ATL,请参见 [Bi7] 和 [Bi10]。如果您对在客户端代码中使用 COM 对象的不同技术更感兴趣,请参见 [Bi3] 第 7 章。
#import
语句有许多 attributes
,例如 no_namespace
/ rename_namespace
,用于管理导入类型信息的命名空间,请参见 Visual C++ 文档。