65.9K
CodeProject 正在变化。 阅读更多。
Home

COM 宏架构拓扑 - 客户端

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.54/5 (8投票s)

2001年7月25日

6分钟阅读

viewsIcon

119841

关于 COM 架构、COM 客户端和注册表的文章

目的

本文介绍如何实现一个简单的客户端应用程序。它将使用 MFC 架构和 ATL 以 C++ 开发。

要求

所有这些示例代码均使用 C++ 编写,在 Windows 2000 下使用 Visual C++ 6.0 (sp4)。
它们还使用了 Active-X Template Library (ATL v3.0)。

本系列中的其他文章

本文是“COM 宏架构拓扑”系列的一部分。以下是其他文章的链接

简单的客户端应用程序

最终我们要实现的目标

最终的客户端应用程序将是一个简单的基于 MFC 对话框的应用程序。它将使用 MFC (Microsoft Foundation Classes) 框架中的 Afx???() 函数。此外,它看起来会像这样 (或类似的样子)

Client / At the end ...

创建项目

为了创建客户端应用程序,您需要按照以下步骤操作
  • 启动 Visual C++ IDE,选择 文件新建,然后按如下方式填写
Client / New
  • 您想要创建一个基于对话框的应用程序
  • 单击下一步
Client / MFC Appwizard - Step 1 of 4
  • 取消选中ActiveX 控件支持选项
  • 您可以更改标题
  • 单击下一步
Client / MFC Appwizard - Step 2 of 4
  • 保留默认设置。
  • 单击下一步
Client / MFC Appwizard - Step 3 of 4
  • 单击完成
Client / MFC Appwizard - Step 4 of 4

之后,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)。
Client / Open the dialog box in the resource editor.

起初,您的对话框资源只有 2 个推送按钮 (OKCancel) 和一个静态文本控件 (TODO: Place dialog controls here.)

Client / The dialog box resource - As the beginning.

通过选择静态文本控件并按 Delete 键删除它。

Controls toolbar 中选择推送按钮控件工具

Client / Controls toolbar - pushbutton.
在对话框上创建一个新的推送按钮
  • 右键单击对话框中的任意位置,
  • 按住鼠标右键并移动鼠标以初始化推送按钮的大小,
  • 然后释放鼠标右键。
像这样更改按钮的标题和 ID
  • 左键单击您的推送按钮,
  • 从弹出菜单中选择 Properties
  • 然后
    • 更改 ID: IDBUT_MACROTOPOEXE_DISP_SHOWHELLO
    • 更改 Caption: ShowHello()...
如果您在此阶段构建并运行客户端应用程序,结果可能会像这样

Client / The dialog box resource - As the beginning.

要将推送按钮绑定到方法,请双击它。将出现一个“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.exemacrotoposerver_dll_psdll.dllmacrotoposerver_dllmerged.dll) 获取类型信息。

它尝试从应该实现它的 COM 对象 CoMacroTopo 获取 IMacroTopoDisp 的接口指针。如果失败,将引发一个COM 异常 (使用 _com_error 类)。

这段代码非常简短,但实际上 #import 指令已经为您生成了包装代码。查看您的“.\Debug”目录 (如果您在Debug模式下工作),您会找到 2 个文件
  • macrotoposerver_exe.tlh 是一个头文件,其中包含 COM 服务器中存储的类型库中的类型信息的 C++ 版本。
  • macrotoposerver_exe.tli 是包含内联接口成员函数的文件的文件,这些函数作为 COM 对象实现的远程接口方法的包装器。
现在,如果您想为 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++ 文档。
© . All rights reserved.