扫一扫
分享文章到微信
扫一扫
关注官方公众号
至顶头条
作者:Paul DiLascia 来源:msdn中国 2007年11月19日
关键字: VC++ IRegistrar 查找 子菜单
以下是引用片段: STDAPI DllUnregisterServer(void) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); if (!COleObjectFactory::UnregisterAll()) return ResultFromScode(SELFREG_E_CLASS); return NOERROR; } |
COleObjectFactory::UnregisterAll 返回 TRUE,但我的 DLL 仍将被注册。我该如何编写此代码?
Ivan Pavlik
答:
很不幸,您碰到了 MFC 世界中的一个小难题。UnregisterAll 看起来确实是您要调用的用来取消注册您的 DLL 的函数。如果您查看一下在其中实现 UnregisterAll 的 olefact.cpp 的内部,您会发现它如下所示:
以下是引用片段: for (/* pFactory = all factories */) { pFactory->Unregister(); } |
即,它在您的模块的所有工厂上循环并为每个工厂调用 Unregister。到目前为止,一切正常。COleObjectFactory::Unregister 执行什么操作?下面的代码告诉了实情:
以下是引用片段: BOOL COleObjectFactory::Unregister() { return TRUE; } |
哎呀!如您所见,COleObjectFactory::Unregister 未执行任何操作!它只是返回 TRUE。这真是奇怪,因为 COleObjectFactory::Register 确实通过调用 ::CoRegisterClassObject 注册了您的 COM 类。另一方面,存在另一个函数 COleObjectFactory::Revoke,它通过调用 ::CoRevokeClassObject 来取消注册您的 COM 类。MFC 从您的 COleObjectFactory 析构函数自动调用 Revoke。那么,到底是怎么回事呢?
很遗憾,问题在于术语混淆,其源于为 DLL 和 EXE 注册 COM 类的不同方法。对于 DLL,您通过在 Windows 注册表中添加项(CLSID、ProgID 等)来注册您的类。对于 EXE,您必须在运行时使用 COM
当 Redmondtonians 将 COM 支持添加到 MFC 中时,他们已尽了最大努力来使事情变得尽可能容易,但他们并非总是能够获得很完美的结果。COleObjectFactory::Register 如下所示:
以下是引用片段: // 在 olefact.cpp 中 BOOL COleObjectFactory::Register() { if (!afxContextIsDLL) { ::CoRegisterClassObject(..., CLSCTX_LOCAL_SERVER, ..); } } |
您可立刻会看到它未对 DLL 执行任何操作,它只是使用 CLSCTX_LOCAL_SERVER 注册了 EXE(上下文 = 本地服务器,EXE 在本地
那么,没有执行任何操作的函数 COleObjectFactory::Unregister 有什么作用呢?可能 Redmondtonians 打算某一天也要使 Register/Unregister 用于 DLL。不过,到目前为止,他们还没有这一打算。要注册您的 DLL,您还需要另一个完全不同的函数:COleObjectFactory::UpdateRegistry。此函数具有一个布尔型参数,它告诉 MFC 您要注册还是要取消注册您的 COM 类。还有 UpdateRegistryAll,它在所有类工厂上循环,为每个类工厂调用 UpdateRegistry。因此,以下为实现您的 DllUnregisterServer 的正确方法:
以下是引用片段: STDAPI DllUnregisterServer(void) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); return COleObjectFactory::UpdateRegistryAll(FALSE) ? S_OK : SELFREG_E_CLASS; } |
除了您应当将 TRUE(而不是 FALSE)传递给 UpdateRegistryAll 之外,DllRegisterServer 应与 UpdateRegistryAll 相同。
UpdateRegistry 的默认实现已尽量在 HKCR/CLSID–InprocServer32、ProgID、Insertable、ThreadingModel 等中添加或删除了相应的注册表项,但有时您需要特定于您的 COM 类的其他注册表项。例如,您可能需要注册类别,它是旧式“可插入”注册表项的某种扩展(这就意味着,在
在 1999 年 11 月和 12 月发行的两期 Microsoft Systems Journal(现名为 MSDN®杂志)中,我曾介绍过如何使用活动模板库 (ATL) IRegistrar 接口为 Internet Explorer 创建一个带对象。(带对象需要注册一个特殊的类别 CATID_DeskBand。)IRegistrar 确实是一个非常酷的工具,它允许您编写注册脚本(.RGS 文件)来添加注册表项,而不是调用 RegOpenKey、RegSetValue 及其他注册表函数。图 1 显示了一个典型脚本。
如您所见,IRegistrar 允许您定义变量,例如 %ClassName% 和 %ThreadingModel%,然后在运行时用实际值替换这些变量。通过使用 IRegistrar,您将永远不再需要调用注册表 API 了。您可编写一个与实际注册表项更相似的脚本,您甚至还可以使用同一脚本来注册或取消注册您的 DLL。对,IRegistrar 足可以取消注册。在我所能找到的地方,都没有 IRegistrar 的正式文档说明,但却给出了代码(可在 atliface.h 中找到)。如果您未使用 IRegistrar 来注册和取消注册您的 COM DLL,您确实应该试一试它 - 它将为您节省大量的工作。有关详细
如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。
现场直击|2021世界人工智能大会
直击5G创新地带,就在2021MWC上海
5G已至 转型当时——服务提供商如何把握转型的绝佳时机
寻找自己的Flag
华为开发者大会2020(Cloud)- 科技行者