科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道基础软件VC++中IRegistrar、查找子菜单及其他

VC++中IRegistrar、查找子菜单及其他

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

使用 Visual C++® 6.0 生成具有自动化支持的 DLL 时,生成了一些注册函数,而不是取消注册我的 DLL 的函数。我编写了 DllUnregisterServer.

作者:Paul DiLascia 来源:msdn中国 2007年11月19日

关键字: VC++ IRegistrar 查找 子菜单

  • 评论
  • 分享微博
  • 分享邮件
问:当我使用 Visual C++® 6.0  生成具有自动化支持的 DLL 时,生成了一些注册函数,而不是取消注册我的 DLL 的函数。我编写了 DllUnregisterServer,如下所示:

以下是引用片段:
  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 系统调用 CoRegisterClassObject 来注册您的类。该问题因以下事实变得更加令人费解,即,对于 EXE,与注册相反的操作不是取消注册,而是撤销 (CoRevokeClassObject)。

  当 Redmondtonians 将 COM 支持添加到 MFC 中时,他们已尽了最大努力来使事情变得尽可能容易,但他们并非总是能够获得很完美的结果。COleObjectFactory::Register 如下所示:

以下是引用片段:
  // 在 olefact.cpp 中
  BOOL COleObjectFactory::Register()
  {
  if (!afxContextIsDLL) {
  ::CoRegisterClassObject(...,
  CLSCTX_LOCAL_SERVER, ..);
  }
  }

  您可立刻会看到它未对 DLL 执行任何操作,它只是使用 CLSCTX_LOCAL_SERVER 注册了 EXE(上下文 = 本地服务器,EXE 在本地计算机上运行)。在底层 C API 之后,Redmondtonians 对取消注册 EXE 的函数使用了同一名称 Revoke:COleObjectFactory::Revoke(将从您的类工厂的析构函数中自动对其进行调用)。

  那么,没有执行任何操作的函数 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 类的其他注册表项。例如,您可能需要注册类别,它是旧式“可插入”注册表项的某种扩展(这就意味着,在设计模式下,可将您的 COM 类拖放到某个表单中)。在这种情况下,您需要重写 UpdateRegistry 以添加或删除您自己的注册表项。

  在 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,您确实应该试一试它 - 它将为您节省大量的工作。有关详细信息,请参阅我于 1999 年 11 月发表的文章。

    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章