COM 宏架构拓扑 - 服务器





5.00/5 (15投票s)
2001年7月25日
27分钟阅读

170791
一篇关于 COM 架构、COM 服务器、COM DLL 服务器和注册表文章
概述
目的
本文展示了如何在 3 种不同的配置中实现 COM 服务器
尽管服务器看起来不同,但构建和实现 COM 对象及其接口到其中的步骤大多是通用的。
这里我不会解释如何将 COM 服务器制作成 Windows NT 服务。事实上,你可以像对待 COM 可执行服务器一样看待这个选项,只是
- 更多的功能以便向操作系统注册服务。
- 注册 COM 服务器时的一些限制。
- 使用 Windows API 时的一些限制。
要求
本文中的所有代码均用 C++ 编写,在 Windows 2000 下使用 Visual C++ 6.0 (sp4)。它们还使用了 Active-X 模板库 (ATL v3.0)。本系列中的其他文章
本文是“COM 宏架构拓扑”系列的一部分。以下是其他文章的链接- 主文章“COM 宏架构拓扑”
- 客户端应用程序“COM 宏架构拓扑 (客户端)”。
- COM ID 和注册表项概览.
COM 服务器
左键单击 gadget 并拖动以移动它。左键单击 gadget 的右下角并拖动以调整其大小。右键单击 gadget 以访问其属性。
本文中介绍的所有服务器都由一个名为CoMacroTopo
的 COM 类(或 CoClass)组成。它公开了两个 COM 接口IMacroTopoDisp
,这是一个调度接口。IMacroTopoCustom
,这是一个自定义接口。
ShowHello()
,它会显示一个带有“Hello”消息的消息框。Add(A, B) : C
,它将“A”和“B”(数字)相加并将结果返回给“C”。
ShowHelloCustom()
和 AddCustom()
。
- 选择服务器类型,例如可执行文件、2 个 DLL 或允许合并代理的 1 个 DLL。
- 编辑项目设置(有关允许合并代理的 1 个 DLL,请点击此处)。
- 创建 CoClass 定义。
- 向
IMacroTopoDisp
添加方法。 - 添加新接口
IMacroTopoCustom
。 - 生成项目。
- 注册服务器(可执行文件、2 个 DLL 或允许合并代理的 1 个 DLL)。
- 配置服务器的安全。
- 注销服务器(可执行文件、2 个 DLL 或允许合并代理的 1 个 DLL)。
本文未考虑“将文件复制到目标计算机”和“从目标计算机移除文件”的过程。显然,在实际情况中,您应该考虑它们:前者将在步骤 6 之后,后者将在步骤 9 之后。
可执行文件配置 
要将 COM 服务器构建为可执行文件,请遵循“通用”部分的步骤。步骤 1 - 选择服务器类型 
要创建服务器,您必须遵循以下步骤- 启动 Visual C++ IDE,选择文件、新建,然后按如下方式填写

- 您想创建一个可执行服务器,所以选择“服务器类型”选项,如下所示

之后,ATL COM 向导将创建以下文件
- 工作区:
macrotoposerver_exe.dsw
- 项目:
macrotoposerver_exe.dsp
- 初始化代码在
macrotoposerver_exe.cpp
和macrotoposerver_exe.h
中 - IDL 源在
macrotoposerver_exe.idl
中 - 以及代理/存根 DLL 的文件
macrotoposerver_exeps.mk
macrotoposerver_exeps.def
MACROTOPOSERVER_EXE.EXE
。步骤 2 至 6 和 8 - 通用部分 
遵循通用步骤:步骤 2、步骤 3、步骤 4、步骤 5、步骤 6 和步骤 8。步骤 7 - 注册您的服务器 
由于您使用了 ATL 向导生成项目,它会自动添加注册服务器的命令(在项目设置窗口的自定义生成选项卡中)。但是,它不对代理/存根 DLL 执行任何操作,因此您需要自己完成。您还必须考虑到,通常生成计算机与客户端或服务器计算机不同。
本地注意事项
要在生成计算机上手动注册,请按以下方式操作(按此顺序)- 注册代理/存根文件 (MACROTOPOSERVER_EXEPS.DLL)
- 打开 DOS 命令窗口并转到您的项目目录,
- 键入命令“>
regsvr32 macrotoposerver_exeps.dll
”。
- 注册 COM 服务器文件 (MACROTOPOSERVER_EXE.EXE)
- 打开 DOS 命令窗口并转到您的项目目录,
- 转到您的生成目录(例如
\Debug
) - 键入命令“>
MACROTOPOSERVER_EXE.EXE -RegServer
”。
远程注意事项
在这种情况下,您需要执行两次安装:一次在客户端计算机上,一次在服务器计算机上。以下是两者的说明- 在客户端计算机上
- 注册代理/存根文件 (MACROTOPOSERVER_EXEPS.DLL)
使用命令行“>regsvr32 MACROTOPOSERVER_EXEPS.DLL
”。
- 注册远程服务器条目。
通常我们不希望(也不需要)在客户端计算机上注册完整的服务器组件。在这种情况下,我们需要创建一个注册表文件来添加必要的键以启用我们的组件在服务器计算机上的远程访问。因此,创建一个扩展名为".reg"
的新文本文件(例如registry_client_exe.reg
)并添加以下行[HKEY_CLASSES_ROOT\CLSID\{12345678-0000-0000-0000-abababababab}] @="CoMacroTopo Class" "AppID"="{AppID_GUIDGEN_BY_ATL}" [HKEY_CLASSES_ROOT\AppID\{AppID_GUIDGEN_BY_ATL}] @="macrotoposerver_exe" "RemoteServerName"="myservercomputer"
"myservercomputer" 是安装了 COM 服务器的计算机名称。
AppID“{AppID_GUIDGEN_BY_ATL}”由 ATL 向导生成,您可以在资源文件中找到它(值不同),例如CoMacroTopo.rgs
或macrotoposerver_exe.rgs
。因此,请保持相同的值,因为它现在是您的可执行文件的一部分。
如果您的服务器中有多个 COM 类对象(此处只有一个 CoMacroTopo),您必须为每个CLSID
重复前 3 行。但是,请为“AppID”键保持相同的值。[HKEY_CLASSES_ROOT\CLSID\{<another COM Class ID>}] @="CoAnother Class" "AppID"="{AppID_GUIDGEN_BY_ATL}" ...
现在您必须将所有这些信息注册到注册表中。使用 Windows 资源管理器,双击您的文件。注册表会询问您是否要将此信息添加到当前注册表中(如果您拥有管理员权限,请单击“是”,就这样)。
- 注册代理/存根文件 (MACROTOPOSERVER_EXEPS.DLL)
- 在服务器计算机上
- 注册代理/存根文件 (MACROTOPOSERVER_EXEPS.DLL)
使用命令行“>regsvr32 MACROTOPOSERVER_EXEPS.DLL
”。
- 注册您的可执行文件中存储的服务器条目 (MACROTOPOSERVER_EXE.EXE)
使用命令行“>MACROTOPOSERVER_EXE.EXE -RegServer
”。
- 注册代理/存根文件 (MACROTOPOSERVER_EXEPS.DLL)
步骤 9 - 注销您的服务器 
本地注意事项
要手动注销,请按以下方式操作- 注销代理/存根文件 (MACROTOPOSERVER_EXEPS.DLL)
- 打开 DOS 命令窗口并转到您的项目目录,
- 键入命令“>
regsvr32 /u MACROTOPOSERVER_EXEPS.DLL
”
- 注销 COM 服务器文件 (MACROTOPOSERVER_EXE.EXE)
- 打开 DOS 命令窗口并转到您的项目目录,
- 转到您的生成目录,其中包含已注册的文件(例如
\Debug
) - 键入命令“>
MACROTOPOSERVER_EXE.EXE -UnregServer
”。
远程注意事项
要手动注销,请按以下方式操作- 在客户端计算机上
- 注销代理/存根文件 (MACROTOPOSERVER_EXEPS.DLL)
使用命令行“>regsvr32 /u MACROTOPOSERVER_EXEPS.DLL
”。
- 注销远程服务器条目。
您必须手动删除它们,使用您在注册步骤中使用的信息(用扩展名".reg"
创建的注册表文件)。
因此,启动注册表编辑器(REGEDIT.EXE),然后查找您之前添加的条目(至少 2 个),如下所示[HKEY_CLASSES_ROOT\AppID\{AppID_GUIDGEN_BY_ATL}] [HKEY_CLASSES_ROOT\CLSID\{CLSID_value}]
然后删除它们。
如果您的服务器中有多个 COM 类对象(此处只有一个 CoMacroTopo),您可能添加了多个CLSID。在这种情况下,您应该删除所有这些条目。
- 注销代理/存根文件 (MACROTOPOSERVER_EXEPS.DLL)
- 在服务器计算机上
- 注销代理/存根文件 (MACROTOPOSERVER_EXEPS.DLL)
使用命令行“>regsvr32 /u MACROTOPOSERVER_EXEPS.DLL
”。
- 通过以下方式注销服务器计算机注册表中存储的服务器条目
使用命令行“>MACROTOPOSERVER_EXE.EXE -UnregServer
”。
- 注销代理/存根文件 (MACROTOPOSERVER_EXEPS.DLL)
2 个 DLL 配置 
要将 COM 服务器构建为 2 个 DLL,请遵循“通用”部分的步骤。步骤 1 - 选择服务器类型 
要创建服务器,您必须遵循以下步骤- 启动 Visual C++ IDE,选择文件、新建,然后按如下方式填写
- 您想创建一个没有合并代理/存根代码的 DLL 服务器,所以选择“服务器类型”选项,如下所示

之后,ATL COM 向导将创建以下文件
- 工作区:
macrotoposerver_dll_psdll.dsw
- 项目:
macrotoposerver_dll_psdll.dsp
- 初始化代码在
macrotoposerver_dll_psdll.cpp
和macrotoposerver_exe.h
中 - IDL 源在
macrotoposerver_dll_psdll.idl
中 - 以及代理/存根 DLL 的文件
macrotoposerver_dll_psdllps.mk
macrotoposerver_dll_psdllps.def
MACROTOPOSERVER_DLL_PSDLL.DLL
。步骤 2 至 6 和 8 - 通用部分 
遵循通用步骤:步骤 2、步骤 3、步骤 4、步骤 5、步骤 6 和步骤 8。步骤 7 - 注册您的服务器 
由于您使用了 ATL 向导生成项目,它会自动添加注册服务器的命令(在项目设置窗口的自定义生成选项卡中)。但是,它不对代理/存根 DLL 执行任何操作,因此您需要自己完成。您还必须考虑到,通常生成计算机与客户端或服务器计算机不同。
本地进程内注意事项
要在生成计算机上手动注册,请按以下方式操作(按此顺序)- 注册代理/存根文件 (MACROTOPOSERVER_DLL_PSDLLPS.DLL)
- 打开 DOS 命令窗口并转到您的项目目录,
- 键入命令“>
regsvr32 MACROTOPOSERVER_DLL_PSDLLPS.DLL
”
- 注册 COM DLL 服务器文件 (MACROTOPOSERVER_DLL_PSDLL.DLL)
- 打开 DOS 命令窗口并转到您的项目目录,
- 转到您的生成目录(例如
\Debug
) - 键入命令“>
regsvr32 MACROTOPOSERVER_DLL_PSDLL.DLL
”
远程注意事项
在这种情况下,您需要执行两次安装:一次在客户端计算机上,一次在服务器计算机上。以下是两者的说明- 在客户端计算机上
- 注册代理/存根文件 (MACROTOPOSERVER_DLL_PSDLLPS.DLL)
使用命令行“>regsvr32 MACROTOPOSERVER_DLL_PSDLLPS.DLL
”。
- 注册远程服务器条目。
通常我们不希望(也不需要)在客户端计算机上注册完整的服务器组件。在这种情况下,我们需要创建一个注册表文件来添加必要的键以启用我们的组件在服务器计算机上的远程访问。因此,创建一个扩展名为".reg"
的新文本文件(例如registry_client_exe.reg
)并添加以下行[HKEY_CLASSES_ROOT\CLSID\{12345678-0000-0000-0000-abababababab}] @="CoMacroTopo Class" "AppID"="{AppID_GUIDGEN_BY_YOU}" [HKEY_CLASSES_ROOT\AppID\{AppID_GUIDGEN_BY_YOU}] @="MacroTopoServer_2dlls" "RemoteServerName"="myservercomputer"
"myservercomputer" 是安装了 COM 服务器的计算机名称。
如果您服务器中有多个 COM 类对象(此处只有一个 CoMacroTopo),您必须为每个CLSID
值重复前 3 行。但是,请保持“AppID_GUIDGEN_BY_YOU”键的值相同。[HKEY_CLASSES_ROOT\CLSID\{<another COM Class ID>}] @="CoAnother Class" "AppID"="{AppID_GUIDGEN_BY_YOU}" ...
现在您必须将所有这些信息注册到注册表中。使用 Windows 资源管理器,双击您的文件。注册表会询问您是否要将此信息添加到当前注册表中(如果您拥有管理员权限,请单击“是”,就这样)。
- 注册代理/存根文件 (MACROTOPOSERVER_DLL_PSDLLPS.DLL)
- 在服务器计算机上
- 注册代理/存根文件 (MACROTOPOSERVER_DLL_PSDLLPS.DLL)
使用命令行“>regsvr32 MACROTOPOSERVER_DLL_PSDLLPS.DLL
”。
- 注册您的服务器文件(MACROTOPOSERVER_DLL_PSDLL.DLL)中存储的服务器条目
使用命令行“>regsvr32 MACROTOPOSERVER_DLL_PSDLL.DLL
”。
- 注册指示使用 DLL 代理应用程序的服务器条目。
您需要创建一个注册表文件来添加必要的键以启用 DLL 代理应用程序对我们组件的管理。因此,创建一个扩展名为".reg"
的新文本文件(例如registry_server_exe.reg
)并添加以下行[HKEY_CLASSES_ROOT\CLSID\{12345678-0000-0000-0000-abababababab}] "AppID"="{AppID_GUIDGEN_BY_YOU}" [HKEY_CLASSES_ROOT\AppID\{AppID_GUIDGEN_BY_YOU}] @="MacroTopoServer_2dlls" "DllSurrogate"=""
主要目的是允许我们的 COM DLL 服务器使用代理应用程序启动。此处,值为一个空字段 "",表示 COM 将使用系统提供的默认代理(例如,Windows NT 4.0 和 Windows 2000 上的默认代理是 DLLHOST.EXE)。
如果您服务器中有多个 COM 类对象(此处只有一个 CoMacroTopo),您必须为每个CLSID
重复前 3 行。但是,请为“AppID_GUIDGEN_BY_YOU”键保持相同的值。[HKEY_CLASSES_ROOT\CLSID\{<another COM Class ID>}] @="CoAnother Class" "AppID"="{AppID_GUIDGEN_BY_YOU}" ...
现在您必须将所有这些信息注册到注册表中。使用 Windows 资源管理器,双击您的文件。注册表会询问您是否要将此信息添加到当前注册表中(如果您拥有管理员权限,请单击“是”,就这样)。
- 注册代理/存根文件 (MACROTOPOSERVER_DLL_PSDLLPS.DLL)
本地代理注意事项
您也可以寻找一种变体配置,该配置在客户端应用程序的同一台计算机上使用我们的 COM DLL 服务器,但不在客户端进程之外。尽管如此,DLL 永远无法在没有父进程的情况下运行。COM 提供了一个默认的 DLL 代理应用程序,它可以加载我们的 COM DLL 服务器并为其提供进程环境。
为了做到这一点,您只需执行与上面(远程注意事项)部分相同的操作,然后按照以下说明进行操作“在服务器计算机上”。
当然,您必须在服务器计算机上执行它们,即,在这种情况下,与您的客户端计算机相同(此处我们关注本地代理注意事项)。
现在,您必须更改客户端代码,并显式要求在单独的进程空间(在同一台计算机上但在不同的进程中)中使用 DLL 代理应用程序创建 COM DLL 服务器。
为了指示 COM 您想在不同的进程空间中创建对象,您必须在 CoCreateInstance() 调用、CoCreateInstanceEx() 调用或 ATL 接口智能指针构造函数中使用标志 CLSCTX_LOCAL_SERVER(仅此标志),如下所示
... IMacroTopoDispPtr pDisp(__uuidof(CoMacroTopo), NULL, CLSCTX_LOCAL_SERVER); long lA(500), lB(114); long lResultat = pDisp->Add(lA,lB); ...关于 COM DLL 服务器和 DLL 代理应用程序之间关系的说明。COM DLL 服务器默认加载到自己的代理进程中。如果出于某些原因,您需要将其他 COM DLL 服务器加载到现有代理进程中,从而支持多个 COM DLL 服务器,则有两个要求
- COM DLL 服务器必须具有相同的AppID 值。
- COM DLL 服务器的安全上下文必须相同。这意味着它们具有匹配的安全标识。
步骤 9 - 注销您的服务器 
本地进程内注意事项
要手动注销,请按以下方式操作- 注销代理/存根文件 (MACROTOPOSERVER_DLL_PSDLLPS.DLL)
- 打开 DOS 命令窗口并转到您的项目目录,
- 键入命令“>
regsvr32 /u MACROTOPOSERVER_DLL_PSDLLPS.DLL
”
- 注销 COM DLL 服务器文件 (MACROTOPOSERVER_DLL_PSDLL.DLL)
- 打开 DOS 命令窗口并转到您的项目目录,
- 转到您的生成目录,其中包含已注册的文件(例如
\Debug
) - 键入命令“>
regsvr32 /u MACROTOPOSERVER_DLL_PSDLL.DLL
”
远程注意事项
要手动注销,请按以下方式操作- 在客户端计算机上
- 注销代理/存根文件 (MACROTOPOSERVER_DLL_PSDLLPS.DLL)
使用命令行“>regsvr32 /u MACROTOPOSERVER_DLL_PSDLLPS.DLL
”。
- 注销远程服务器条目。
您必须手动删除它们,使用您在注册步骤中使用的信息(用扩展名".reg"
创建的注册表文件)。
因此,启动注册表编辑器(REGEDIT.EXE),然后查找您之前添加的条目(至少 2 个),如下所示[HKEY_CLASSES_ROOT\AppID\{AppID_GUIDGEN_BY_YOU}] [HKEY_CLASSES_ROOT\CLSID\{CLSID_value}]
然后删除它们。
如果您的服务器中有多个 COM 类对象(此处只有一个 CoMacroTopo),您可能添加了多个CLSID。在这种情况下,您应该删除所有这些条目。
- 注销代理/存根文件 (MACROTOPOSERVER_DLL_PSDLLPS.DLL)
- 在服务器计算机上
- 注销代理/存根文件 (MACROTOPOSERVER_DLL_PSDLLPS.DLL)
使用命令行“>regsvr32 /u MACROTOPOSERVER_DLL_PSDLLPS.DLL
”。
- 注销服务器计算机注册表中存储的 COM DLL 服务器条目
使用命令行“>regsvr32 /u MACROTOPOSERVER_DLL_PSDLL.DLL
”。
- 注销代理服务器条目。
您必须手动删除它们,使用您在注册步骤中使用的信息(用扩展名".reg"
创建的注册表文件)。
因此,启动注册表编辑器(REGEDIT.EXE),然后查找您之前添加的 AppID_GUIDGEN_BY_YOU 条目[HKEY_CLASSES_ROOT\AppID\{AppID_GUIDGEN_BY_YOU}]
然后删除它。您不需要删除 CLSID_value 键(或键)[HKEY_CLASSES_ROOT\CLSID\{CLSID_value}]
因为当您注销 COM DLL 服务器时,它会自动为您完成。
- 注销代理/存根文件 (MACROTOPOSERVER_DLL_PSDLLPS.DLL)
本地代理注意事项
为了做到这一点,您只需按照上面(远程注意事项)部分所述执行操作,然后按照以下说明进行操作“在服务器计算机上”。当然,您必须在服务器计算机上执行它们,即,在这种情况下,与您的客户端计算机相同(此处我们关注本地代理注意事项)。
单个 DLL 配置(或合并) 
要将 COM 服务器构建为单个 DLL,您必须遵循“通用”部分的步骤(1 个 DLL)。步骤 1 - 选择服务器类型 
要创建服务器,您必须遵循以下步骤- 启动 Visual C++ IDE,选择文件、新建,然后按如下方式填写

- 您想创建一个合并了代理/存根代码的 DLL 服务器,所以选择“服务器类型”选项,如下所示

之后,ATL COM 向导将创建以下文件
- 工作区:
macrotoposerver_dllmerged.dsw
- 项目:
macrotoposerver_dllmerged.dsp
- 初始化代码在
macrotoposerver_dllmerged.cpp
和macrotoposerver_exe.h
中 - IDL 源在
macrotoposerver_dllmerged.idl
中 - 以及代理/存根 DLL 的文件
macrotoposerver_dllmergedps.mk
macrotoposerver_dllmergedps.def
因此,尽管您要求合并代理/存根代码,但您仍然获得了构建代理/存根 DLL 文件所需的代码。
最终的 COM 服务器名称是
MACROTOPOSERVER_DLLMERGED.DLL
。步骤 2 - 编辑项目设置 
您必须遵循通用步骤 2 - 编辑项目设置中的说明。尽管您已选中“允许合并代理/存根代码”复选框,但这不足以使用合并的代码构建 COM DLL 服务器。
因此,在项目设置中,请按以下方式操作
- 选择“所有配置”,确保选中了项目节点。
- 在 C++ 选项卡中
- 在预处理器定义中,转到末尾,追加一个逗号并添加 _MERGE_PROXYSTUB

- 选择 dlldatax.c 文件,并始终针对所有配置。
- 在常规选项卡中
- 取消选中排除文件生成。

- 现在,转到 C++ 选项卡
- 在类别下拉列表框中选择预编译头文件。
- 选择 **不使用预编译头文件** 选项。
- 然后按确定。

文件 dlldatax.c 包含 dlldata.c 以及名为“your_idl_filename_p.c”的文件。前者包含 COM DLL 服务器必需的 COM 入口点代码,例如 DllGetClassObject。后者包含用于封送(即代理/存根代码)IDL 文件中定义的所有接口的代码。这些文件由 MIDL 编译器(Microsoft IDL 编译器)生成,该编译器随 Win32 SDK 一起提供。
步骤 3 至 6 和 8 - 通用部分 
遵循通用步骤:步骤 3、步骤 4、步骤 5、步骤 6 和步骤 8。步骤 7 - 注册您的服务器 
由于您使用了 ATL 向导生成项目,它会自动添加注册服务器的命令(在项目设置窗口的自定义生成选项卡中)。但是,它不对代理/存根 DLL 执行任何操作,因此您需要自己完成。您还必须考虑到,通常生成计算机与客户端或服务器计算机不同。
本地进程内注意事项
要在生成计算机上手动注册,请按以下方式操作- 注册 COM DLL 服务器文件 (MACROTOPOSERVER_DLLMERGED.DLL)
- 打开 DOS 命令窗口并转到您的项目目录,
- 转到您的生成目录(例如
\Debug
) - 键入命令“>
regsvr32 MACROTOPOSERVER_DLLMERGED.DLL
”
在此,代理/存根代码同时注册。
远程注意事项
在这种情况下,您需要执行两次安装:一次在客户端计算机上,一次在服务器计算机上。以下是两者的说明- 在客户端计算机上
- 注册代理/存根文件 (MACROTOPOSERVER_DLLMERGEDPS.DLL)
使用命令行“>regsvr32 MACROTOPOSERVER_DLLMERGEDPS.DLL
”。
- 注册远程服务器条目。
通常我们不希望(也不需要)在客户端计算机上注册完整的服务器组件。在这种情况下,我们需要创建一个注册表文件来添加必要的键以启用我们的组件在服务器计算机上的远程访问。因此,创建一个扩展名为".reg"
的新文本文件(例如registry_client_exe.reg
)并添加以下行[HKEY_CLASSES_ROOT\CLSID\{12345678-0000-0000-0000-abababababab}] @="CoMacroTopo Class" "AppID"="{AppID_GUIDGEN_BY_YOU}" [HKEY_CLASSES_ROOT\AppID\{AppID_GUIDGEN_BY_YOU}] @="MacroTopoServer_dllmerged" "RemoteServerName"="myservercomputer"
"myservercomputer" 是安装了 COM 服务器的计算机名称。
如果您服务器中有多个 COM 类对象(此处只有一个 CoMacroTopo),您必须为每个CLSID
值重复前 3 行。但是,请保持“AppID_GUIDGEN_BY_YOU”键的值相同。[HKEY_CLASSES_ROOT\CLSID\{<another COM Class ID>}] @="CoAnother Class" "AppID"="{AppID_GUIDGEN_BY_YOU}" ...
现在您必须将所有这些信息注册到注册表中。使用 Windows 资源管理器,双击您的文件。注册表会询问您是否要将此信息添加到当前注册表中(如果您拥有管理员权限,请单击“是”,就这样)。
- 注册代理/存根文件 (MACROTOPOSERVER_DLLMERGEDPS.DLL)
- 在服务器计算机上(按此顺序)
- 注册您的服务器文件(MACROTOPOSERVER_DLLMERGED.DLL)中存储的服务器条目
使用命令行“>regsvr32 MACROTOPOSERVER_DLLMERGED.DLL
”。
- 注册指示使用 DLL 代理应用程序的服务器条目。
您需要创建一个注册表文件来添加必要的键以启用 DLL 代理应用程序对我们组件的管理。因此,创建一个扩展名为".reg"
的新文本文件(例如registry_server_exe.reg
)并添加以下行[HKEY_CLASSES_ROOT\CLSID\{12345678-0000-0000-0000-abababababab}] "AppID"="{AppID_GUIDGEN_BY_YOU}" [HKEY_CLASSES_ROOT\AppID\{AppID_GUIDGEN_BY_YOU}] @="MacroTopoServer_dllmerged" "DllSurrogate"=""
主要目的是允许我们的 COM DLL 服务器使用代理应用程序启动。此处,值为一个空字段 "",表示 COM 将使用系统提供的默认代理(例如,Windows NT 4.0 和 Windows 2000 上的默认代理是 DLLHOST.EXE)。
如果您服务器中有多个 COM 类对象(此处只有一个 CoMacroTopo),您必须为每个CLSID
重复前 3 行。但是,请为“AppID_GUIDGEN_BY_YOU”键保持相同的值。[HKEY_CLASSES_ROOT\CLSID\{<another COM Class ID>}] @="CoAnother Class" "AppID"="{AppID_GUIDGEN_BY_YOU}" ...
现在您必须将所有这些信息注册到注册表中。使用 Windows 资源管理器,双击您的文件。注册表会询问您是否要将此信息添加到当前注册表中(如果您拥有管理员权限,请单击“是”,就这样)。
- 注册您的服务器文件(MACROTOPOSERVER_DLLMERGED.DLL)中存储的服务器条目
本地代理注意事项
您也可以寻找一种变体配置,该配置在客户端应用程序的同一台计算机上使用我们的 COM DLL 服务器,但不在客户端进程之外。尽管如此,DLL 永远无法在没有父进程的情况下运行。COM 提供了一个默认的 DLL 代理应用程序,它可以加载我们的 COM DLL 服务器并为其提供进程环境。
为了做到这一点,您只需按照上面(远程注意事项)部分所述执行操作,然后按照以下说明进行操作“在服务器计算机上”。
当然,您必须在服务器计算机上执行它们,即,在这种情况下,与您的客户端计算机相同(此处我们关注本地代理注意事项)。
您还必须为您的客户端应用程序注册代理/存根 DLL 文件
- 注册代理/存根文件 (MACROTOPOSERVER_DLLMERGEDPS.DLL)
使用命令行“>regsvr32 MACROTOPOSERVER_DLLMERGEDPS.DLL
”。
现在,您必须更改客户端代码,并显式要求在单独的进程空间(在同一台计算机上但在不同的进程中)中使用 DLL 代理应用程序创建 COM DLL 服务器。
为了指示 COM 您想在不同的进程空间中创建对象,您必须在 CoCreateInstance() 调用、CoCreateInstanceEx() 调用或 ATL 接口智能指针构造函数中使用标志 CLSCTX_LOCAL_SERVER(仅此标志),如下所示
... IMacroTopoDispPtr pDisp(__uuidof(CoMacroTopo), NULL, CLSCTX_LOCAL_SERVER); long lA(500), lB(114); long lResultat = pDisp->Add(lA,lB); ...关于 COM DLL 服务器和 DLL 代理应用程序之间关系的说明。COM DLL 服务器默认加载到自己的代理进程中。如果出于某些原因,您需要将其他 COM DLL 服务器加载到现有代理进程中,从而支持多个 COM DLL 服务器,则有两个要求
- COM DLL 服务器必须具有相同的AppID 值。
- COM DLL 服务器的安全上下文必须相同。这意味着它们具有匹配的安全标识。
步骤 9 - 注销您的服务器 
本地进程内注意事项
要手动注销,请按以下方式操作- 注销 COM DLL 服务器文件 (MACROTOPOSERVER_DLLMERGED.DLL)
- 打开 DOS 命令窗口并转到您的项目目录,
- 转到您的生成目录,其中包含已注册的文件(例如
\Debug
) - 键入命令“>
regsvr32 /u MACROTOPOSERVER_DLLMERGED.DLL
”
- 在客户端计算机上
- 注销代理/存根文件 (MACROTOPOSERVER_DLLMERGEDPS.DLL)
使用命令行“>regsvr32 /u MACROTOPOSERVER_DLLMERGEDPS.DLL
”。
- 注销远程服务器条目。
您必须手动删除它们,使用您在注册步骤中使用的信息(用扩展名".reg"
创建的注册表文件)。
因此,启动注册表编辑器(REGEDIT.EXE),然后查找您之前添加的条目(至少 2 个),如下所示[HKEY_CLASSES_ROOT\AppID\{AppID_GUIDGEN_BY_YOU}] [HKEY_CLASSES_ROOT\CLSID\{CLSID_value}]
然后删除它们。
如果您服务器中有多个 COM 类对象(此处只有一个 CoMacroTopo),您可能添加了多个CLSID。在这种情况下,您应该删除所有这些条目。
- 注销代理/存根文件 (MACROTOPOSERVER_DLLMERGEDPS.DLL)
- 在服务器计算机上
- 注销服务器计算机注册表中存储的 COM DLL 服务器条目
使用命令行“>regsvr32 /u MACROTOPOSERVER_DLLMERGED.DLL
”。
- 注销代理服务器条目。
您必须手动删除它们,使用您在注册步骤中使用的信息(用扩展名".reg"
创建的注册表文件)。
因此,启动注册表编辑器(REGEDIT.EXE),然后查找您之前添加的 AppID_GUIDGEN_BY_YOU 条目[HKEY_CLASSES_ROOT\AppID\{AppID_GUIDGEN_BY_YOU}]
然后删除它。您不需要删除 CLSID_value 键(或键)[HKEY_CLASSES_ROOT\CLSID\{CLSID_value}]
因为当您注销 COM DLL 服务器时,它会自动为您完成。
- 注销服务器计算机注册表中存储的 COM DLL 服务器条目
本地代理注意事项
为了做到这一点,您只需按照上面(远程注意事项)部分所述执行操作,然后按照以下说明进行操作“在服务器计算机上”。当然,您必须在服务器计算机上执行它们,即,在这种情况下,与您的客户端计算机相同(此处我们关注本地代理注意事项)。
您必须注销代理/存根 DLL 文件
- 注销代理/存根文件 (MACROTOPOSERVER_DLLMERGEDPS.DLL)
使用命令行“>regsvr32 /u MACROTOPOSERVER_DLLMERGEDPS.DLL
”。
通用步骤
步骤 2 - 编辑项目设置 
在项目设置中,我通常会进行这些更改,以避免从命令行启动代理/存根 DLL 的 makefile- 选择“所有配置”,
- 在生成后步骤选项卡中
- 编写生成后描述,
- 创建一个新的生成后命令,例如“ nmake -f " + 代理/存根 DLL makefile(例如
macrotoposerver_exeps.mk
), - 然后按确定。

步骤 3 - 创建 CoClass 定义 
现在让我们插入我们的 COM 对象及其接口。- 选择插入和新 ATL 对象

- 双击“简单对象”(或单击下一步),然后在名称选项卡中
- 将短名称输入为 CoMacroTopo
- 将接口名称输入为 IMacroTopoDisp

- 在属性选项卡中
- 选择两者作为线程模型的值,
- 双重(默认)作为接口的值,
- 是(默认)作为聚合的值,
- 添加支持 ISupportErrorInfo,
- 然后按确定。

步骤 4 - 向 IMacroTopoDisp
添加方法 
现在让我们插入我们的方法。- 转到工作区窗口中的类视图选项卡,
- 选择
IMacrotTopDisp
项(根节点下的那个,而不是CCoMacroTopo
节点下的那个), - 使用鼠标右键,从弹出菜单中选择添加方法...。

- 将方法名称输入为 ShowHello
- 然后按确定。

让我们为第二个方法执行相同的操作
- 执行相同的步骤以打开“添加方法对话框”,
- 将方法名称输入为 Add
- 将参数输入为 [in] long A, [in] long B, [out, retval] long* C
- 然后按确定。

要编辑这些方法的代码实现,您必须
- 转到工作区窗口中的类视图选项卡,
- 打开
CCoMacroTopo
节点项, - 打开
IMacrotTopDisp
节点项, - 双击 ShowHello() 项。

像这样编写函数体
STDMETHODIMP CCoMacroTopo::ShowHello() { // Display a message box. ::MessageBox(NULL, _T("Hello world ;~) - Dispatch"), _T("CoMacroTopoServer - Executable"), MB_OK); return(S_OK); } Do the same for the <CODE>Add() method and write the function's body like that:
STDMETHODIMP CCoMacroTopo::Add(long A, long B, long *C) { // Add : A + B. *C = A + B; return(S_OK); }
步骤 5 - 添加新接口 IMacroTopoCustom

您将手动完成此操作,因为 ATL 向导无法完成(除非您要创建具有新接口的新 ATL CoCalss)。您必须做的第一件事是编辑 IDL 文件以添加新接口(有关更多信息,请参阅“学习 DCOM”[Bi3])。IDL 文件中最相关部分是...
[
object,
uuid(IID_GUIDGEN_BY_YOU),
helpstring("IMacroTopoCustom Interface")
]
interface IMacroTopoCustom : IUnknown
{
};
...
coclass CoMacroTopo
{
[default] interface IMacroTopoDisp;
interface IMacroTopoCustom;
};
您必须使用 GUID 生成器(GUIDGEN.EXE)来获取您的唯一 IID_GUIDGEN_BY_YOU(接口 ID)。我只提醒您,自定义接口无法从 VBScript 等自动化环境中使用。自定义接口不继承自 IDispatch。
编辑 CCoMacroTopo class
的声明文件(CoMacroTopo.h
)并在粗体中添加代码
class ATL_NO_VTABLE CCoMacroTopo : public CComObjectRootEx<CComMultiThreadModel>, public CComCoClass<CCoMacroTopo, &CLSID_CoMacroTopo>, public ISupportErrorInfo, public IDispatchImpl<IMacroTopoDisp, &IID_IMacroTopoDisp, &LIBID_MACROTOPOSERVER_EXELib> , public IMacroTopoCustom public: CCoMacroTopo() { } DECLARE_REGISTRY_RESOURCEID(IDR_COMACROTOPO) DECLARE_PROTECT_FINAL_CONSTRUCT() BEGIN_COM_MAP(CCoMacroTopo) COM_INTERFACE_ENTRY(IMacroTopoDisp) COM_INTERFACE_ENTRY(IDispatch) COM_INTERFACE_ENTRY(ISupportErrorInfo) COM_INTERFACE_ENTRY(IMacroTopoCustom) END_COM_MAP() ... };保存文件(“.idl”和“.h”)。Visual 将自动检测到这些更改,并更新工作区窗口类视图选项卡中的接口和 CoCLass 对象。因此,现在重复为接口添加方法(如您对
IMacroTopoDisp
接口所做的)的步骤。请注意,在添加方法之前,请记住选择接口节点项。这样做时,请像这样更改方法名称ShowHello()
为ShowHelloCustom()
,Add()
为AddCustom()
。
IMacroTopeDisp
相同的实现来实现它们。STDMETHODIMP CCoMacroTopo::ShowHelloCustom() { // Display a message box. ::MessageBox(NULL, _T("Hello world ;~) - Custom"), _T("CoMacroTopoServer - Executable"), MB_OK); return(S_OK); } STDMETHODIMP CCoMacroTopo::AddCustom(long A, long B, long *C) { // Add : A + B. *C = A + B; return(S_OK); }
步骤 6 - 编译与链接 
好的,现在您可以编译和链接- 我们的 COM 服务器(例如
MACROTOPOSERVER_EXE.EXE
) - 我们的代理/存根 DLL(例如
MACROTOPOSERVER_EXEPS.DLL
)
Microsoft IDL 编译器
代理/存根 DLL 生成
步骤 8 - 配置服务器的安全 
要构建和测试本文所述的 COM 服务器,如果您将它们用作本地服务器(进程内或进程外),则无需执行任何操作。但是,如果您将它们作为远程服务器进行测试,则至少需要启用它们以使用交互式用户帐户运行。这是为了在调用 ShowHello() 时显示对话框。要启用 COM 服务器使用交互式用户进行激活,请启动 DCOMCNFG.EXE 应用程序(您也可以使用 OLEVIEW.EXE)
- 滚动应用程序列表直到找到您的 COM 应用程序并选择它(例如
MacroTopoServer_dllmerged
)。 - 单击属性...

- 选择身份选项卡。

- 在用户帐户单选按钮中,选择交互式用户。
- 单击确定并关闭应用程序。

现在,您的组件将使用交互式用户帐户启动。这也意味着如果没有人连接,您的组件也无法启动。但是,这里我们只需要一个帐户来测试我们的组件。
其他要点
- CoClass 和接口名称
CoClass 和接口(人类可读)名称对于这 3 个服务器是相同的。COM 文档将这些名称称为逻辑名称(例如IMacroTopoDisp
)。但是,每个服务器都有自己独特的GUID 集合(用于库 ID、接口 ID 和 CoClass ID),它们是不同的。COM 文档将这些名称称为物理名称(例如{12345678-ABCD-FEDC-A1B2-F1F2F3F4F5D5}
)。有关COM GUID 的更多信息,请点击此处。
具有与其他接口或 CoClass 相同的逻辑名称可能会发生,但这没关系,因为您有不同的物理名称,因为 COM 会查找物理名称。有一个例外是 ProgID,因为 COM 会查找文本名称,但最终,这个逻辑名称与物理名称(即CLSID)相关联。
这是 COM 的主要概念之一:能够唯一标识您的 coclasses 和接口。
- COM 服务器作为 Windows NT 服务
- 目前,一台计算机上一次只能运行一个 Win32 服务实例。因此,COM 服务必须在启动时使用 REGCLS_MULTIPLEUSE 注册其类对象,以支持多个客户端。
- 作为服务运行的 COM 服务器有一些 API 限制,例如:它不能显示对话框或窗口。
- 目前,一台计算机上一次只能运行一个 Win32 服务实例。因此,COM 服务必须在启动时使用 REGCLS_MULTIPLEUSE 注册其类对象,以支持多个客户端。