如何在 SQL Server 进程之外运行基于 DLL 的 COM 对象

摘要

Microsoft SQL Server 6.5 或更高版本提供了通过一组 OLE 自动化存储过程或通过扩展存储过程加载和运行自定义组件对象模型(COM)对象的功能。 默认情况下,基于 DLL 的 COM 对象以进程服务器的形式加载,这意味着 COM 对象不仅在 SQL Server 进程内存地址空间内加载,还具有对此内存地址空间的完全访问权限。 因此,在 SQL Server 进程空间中加载的 COM 对象必须遵循与任何 DLL 文件相同的规则。 COM 对象可能会在 SQL Server 进程内覆盖内存或泄漏资源,从而导致不稳定。如果怀疑 COM 对象可能影响 SQL Server 进程的可靠性,可能需要使用本文中的步骤来实例化 SQL Server 进程空间之外的 COM 对象。 将 "位置透明度" 分布式组件对象模型(DCOM)规范的实现提供给操作系统,已提供了在 SQL Server 进程空间之外运行基于 DLL 的 COM 对象的功能。在主应用程序的地址空间之外运行基于 DLL 的 COM 对象的过程称为 remoting。 远程处理要求另一个可执行文件是替代 SQL Server 可执行文件的代理项进程。 DCOM 服务控制管理器(Rpcss)使用的默认可执行文件名为 Dllhost.exe。 DCOM 支持结构使用 Dllhost.exe 文件将 DLL 加载到其进程空间,然后使用代理/存根对将所请求的接口透明地封送回客户端,在这种情况下是 SQL Server。 此可执行文件可同时接受多个接口/方法请求。 接口使用完成后,DCOM 服务控制管理器(SCM)管理 Dllhost.exe 文件的清理和卸载。 COM 对象不应在实例化之间保留状态信息。为了使本文正常工作,系统必须运行启用 DCOM 的操作系统。 这可能是 Microsoft Windows NT 4.0 Service Pack 2 或更高版本、Microsoft Windows 98 或 Microsoft Windows 95 安装了 DCOM 加载项。 以下步骤可应用于在 SQL Server 进程空间中创建的任何基于 DLL 的 COM 对象,无论该对象是通过sp_OACreate还是扩展存储过程进行实例化。

更多信息

有关可用于在进程外实例化 COM 对象的两种基本方法的信息如下。

COM 客户端请求对象的远程处理

通过更改调用 COM 对象的方式,您可以请求在 SQL Server 地址空间之外创建对象。

  • 如果 COM 对象是使用sp_OACreate过程加载的,则默认情况下会在进程中加载 COM 对象。 但是,此过程有一个可选的第三个参数,您可以使用该参数指示创建对象的位置的上下文。 如果未指定此参数,则使用默认设置5(5),这意味着在进程内部或外部运行对象。 你需要将参数更改为4(4),这表示该组件作为本地可执行文件运行的 DCOM。 使用与以下示例类似的语法显式通知 DCOM 使用sp_OACreate存储过程来运行 COM 对象 "进程外":

       DECLARE @object int
       DECLARE @hr int
       EXEC @hr = sp_OACreate 'SQLOLE.SQLServer', @object OUT, 4
    
  • 如果在扩展存储过程内创建 COM 对象,则可以将CoCreateInstance或CoCreateInstanceEx的第三个参数更改为 CLSCTX_LOCAL_SERVER。 这将在以下使用CoCreateInstance的代码示例中显示:

       HRESULT hr = CoCreateInstance(CLSID_Test, NULL, CLSCTX_LOCAL_SERVER,
         IID_IUnknown, (void**)&piunknown);
    

修改注册表以强制对象的远程处理

如果无法修改 COM 客户端以请求在进程外创建对象,则存在两种不同的方法来强制对象在进程外创建。

  • 使用 Microsoft Visual c + + 附带的 OLE/COM 对象查看器(Oleview),并以 OLEComponent 的形式在 "所有对象" 下找到 ProgID。 选择 COM 对象,然后从 "对象" 菜单中选择 " CoCreateInstance 标志"。 请确保仅选中 "CLSCTX_LOCAL_SERVER"。 接下来,在 "实现" 和 " Inproc 服务器" 选项卡下,选择 "使用代理人进程" 并保留 "指向自定义代理的路径" 空白,这将允许加载 dllhost.exe 文件和在它的进程空间中引入 COM DLL。

  • 使用以下步骤手动更新注册表。 警告如果您使用注册表编辑器或使用其他方法错误地修改注册表,可能会出现严重问题。这些问题可能需要重新安装操作系统。Microsoft 无法保证可以解决这些问题。修改注册表的风险由您自己承担。

    1. 获取 COM 对象的类标识符(CLSID)。 CLSID 为128位数字,并被视为全局唯一标识符(GUID),用于唯一标识包含此 COM 对象的组件、模块或文件。 使用 OLE 自动化存储过程创建 COM 对象时,存储过程的第一个参数是编程标识符或 OLE 对象的 ProgID 用于派生 CLSID。 此字符串描述了 OLE 对象的类,其形式如下所示: OLEComponent.Object 你可以使用编程标识符查找 COM 对象的类标识符。 打开注册表编辑器(Regedit.exe),在 HKEY_CLASSES_ROOT 键下使用Find方法查找具有<OLEComponent>名称的键。 你将在其他级别找到它,但它应位于 HKEY_CLASSES_ROOT 正下方的级别。 找到该注册表项后,展开该注册表项名称的文件夹,您应该看到一个名为 "CLSID" 的子项。 单击该文件夹以查看该注册表项中的值。 屏幕右侧显示名为 "(默认)" 的标题。 该注册表项的数据应采用以下形式:   {59F929A0-74D8-11D2-8CBC-08005A390B09} 记下此值或将其复制到记事本。 包括括号。

    2. 在 HKEY_CLASSES_ROOT \CLSID 键下导航,找到具有此 GUID 编号的子项。 突出显示 HKEY_CLASSES_ROOT \CLSID 键后,可以使用注册表编辑器中的Find函数(在 "编辑" 菜单下),并将 GUID 粘贴到 "查找" 对话框中。 通过检查此项下方的 InprocServer32 子项(指向 COM DLL 文件的位置),确保已找到正确的接口。 如果存在 TypeLib 键,请检查此 GUID 值。 这应该与你在步骤1中记下的内容有所不同。 否则,你具有 TypeLib GUID,而不是 COM 对象的 GUID。 ProgID 子项的值将为 "OLEComponent"。 End 上的一个仅适用于此示例,并用于版本控制信息。

    3. 在 GUID 的 InprocServer32 子项下,确保有一个 ThreadingModel 值,并将其设置为 "完全" 或 "任意",以确保封送处理能够识别 COM 对象的线程模型,以便能够在 SQL Server 进程空间中执行 COM。 如果没有 ThreadingModel 值或它设置为 "单元",则 COM 对象实例化可能不一致。 注意 如果添加 ThreadingModel 值,请确保在实现之前测试 COM 对象。

    4. 突出显示 HKEY_CLASSES_ROOT \CLSID 键下的 GUID 号/子键。 在 "编辑" 菜单上,单击 "新建",然后选择 "字符串值"。 在 "名称" 列下,键入以下内容:

      AppID

    5. 按enter ,然后插入从步骤1中记下的类标识符或 GUID 号作为值。 GUID 应位于大括号内,如下例所示:   {59F929A0-74D8-11D2-8CBC-08005A390B09} 应用程序标识符 AppID 由 DCOM 用于将 DLL 与可执行文件关联。

    6. 在 HKEY_CLASSES_ROOT \AppID 下添加新子项,并将其名称设置为与前面步骤中插入的括号相同的类标识符或 GUID 编号。

    7. 突出显示 GUID 名称。 在 "编辑" 菜单上,单击 "新建",然后选择 "字符串值"。 在 "名称" 列下,键入以下内容:

      DllSurrogate 为此值保留 "数据" 列为空。 由于 data 列为空,因此会通知 DCOM 运行默认可执行文件 Dllhost.exe,并将 COM 对象加载到它的进程空间内。

    8. 关闭注册表编辑器。 单击“开始”,然后单击“运行”。 在 "运行" 对话框中,键入以下内容:

      DCOMCNFG 按enter键打开 "分布式 COM 配置属性" 对话框。 单击 "默认属性" 选项卡,确保已选中 "在此计算机上启用分布式 COM" 。 如果不是,请将其选中,然后单击 "应用"。

    9. 请确保运行 SQL Server 的 Microsoft Windows NT 用户帐户对此对象的注册表项具有 "完全控制" 权限。 如果权限不够或注册表项输入错误,则在创建 COM 对象时可能会出现以下错误:

      OLE 自动化错误信息 HRESULT:0x80040154 源: ODSOLE 扩展过程 说明:类未注册 OLE 自动化错误信息 HRESULT:0x80070005 源: ODSOLE 扩展过程 说明:访问被拒绝。 OLE 自动化错误信息 HRESULT:0x80080005 源: ODSOLE 扩展过程 说明:服务器执行失败

    10. 测试并查看它是否正在运行 Dllhost.exe 文件并在其进程空间中加载 COM 对象。 这要求 Microsoft Windows NT 资源工具包位于运行 SQL Server 的 Windows NT 计算机上。 打开命令提示符,然后从命令提示符运行 Tlist 文件,该文件显示所有进程及其关联的进程标识符或进程标识符(Pid)。 在运行sp_OACreate的 transact-sql 脚本中,在执行该调用之后,但在脚本结束之前,请使用以下语句延迟脚本完成,增加20秒:

      WAITFOR DELAY '000:00:20'
      

      运行脚本并立即导航到命令提示符并运行 Tlist 文件。 注意 Dllhost.exe PID。 重新运行 Tlist 并将 PID 作为参数传递。 此示例显示了在 Dllhost.exe 进程空间中加载的 Dll。 基于 DLL 的 COM 对象应列出为在此过程中运行。 在脚本返回后,运行 Tlist 将再次显示 Dllhost.exe 进程已不再运行。 在以下示例中输出 ADODB。连接对象在 SQL Server 进程空间之外创建。 当 COM 对象存在于 Dllhost.exe 进程空间中时,使用 Tlist 执行此快照。 请注意,模块 Msado15 (它是包含 COM 对象的模块)已加载。

      C:\>tlist dllhost
       275 dllhost.exe
         CWD:     C:\NT40\system32\ 
         CmdLine: C:\NT40\System32\dllhost.exe {00000514-0000-0010-8000-00AA006D2EA4}
      -Embedding
         VirtualSize:    19180 KB   PeakVirtualSize:    19180 KB
         WorkingSetSize:  1780 KB   PeakWorkingSetSize:  1780 KB
         NumberOfThreads: 3
          278 Win32StartAddr:0x01001920 LastErr:0x00000000 State:Waiting
          215 Win32StartAddr:0x00001b5e LastErr:0x00000000 State:Waiting
          253 Win32StartAddr:0x00001b60 LastErr:0x000000cb State:Waiting
         4.0.1381.105 shp  0x01000000  dllhost.exe
         4.0.1381.130 shp  0x77f60000  ntdll.dll
         4.0.1381.121 shp  0x77dc0000  ADVAPI32.dll
         4.0.1381.133 shp  0x77f00000  KERNEL32.dll
         4.0.1381.133 shp  0x77e70000  USER32.dll
         4.0.1381.115 shp  0x77ed0000  GDI32.dll
         4.0.1381.131 shp  0x77e10000  RPCRT4.dll
         4.0.1381.117 shp  0x77b20000  ole32.dll
           6.0.8267.0 shp  0x78000000  MSVCRT.dll
                           0x1f310000  msado15.dll
          2.30.4265.1 shp  0x766f0000  OLEAUT32.dll
          4.0.1381.72 shp  0x77bf0000  rpcltc1.dll
      

      使用 Microsoft Windows 95 或 Microsoft Windows 98 工作站上运行的 SQL Server 版本7.0 桌面版,在执行过程中,可以在执行过程中使用 "Microsoft 系统信息应用程序" 工具中加载的 "32 位模块",在此测试期间查看 Dllhost.exe 文件和 COM 对象 DLL 的 loading\unloading。 若要访问该工具,请单击 "开始",指向 "程序",指向 "附件",然后单击 "系统工具"。

注意 由于安全限制,Windows 95 或 Windows 98 不支持启动 DLLSurrogate 进程并通过远程客户端加载 COM DLL。 因此,COM 对象必须存在于运行的对象表(ROT)内,并且如果它可供远程客户端计算机使用,则该对象必须存在于运行/加载中。 当怀疑 COM 对象可能是 SQL Server 中的不稳定时,可以使用本文中的步骤来帮助隔离这些对象。 请确保每个组件都已被完全耗尽进程,以确保行为保持一致。 在 SQL Server 进程中和进程空间之外实例化 COM 对象的性能差异有所不同。 此外,某些 COM 对象尚未构建为可远程的,并且可能会泄漏资源。 在针对疑难解答步骤以外的其他内容执行本文中的步骤之前,进行全面测试。 以下 Microsoft 知识库文章举例说明了 COM 对象如何导致资源泄漏:

197426 修复:在进程之间传递 ADO 对象时句柄泄漏   注意 Microsoft SQL Server 6.5 默认情况下使用单线程单元(STA)模型进行操作,并在单独的内部线程上处理 COM 对象的初始化。 在此模型中,选择了一个线程来控制 SQL Server 进程内所有 OLE 对象的创建,并返回到需要访问该 COM 对象的所有客户端连接的代理。 由于这是由 SQL Server 内部处理的,因此在 COM 对象的实例化之间无法保证对象的持久性。  

参考

有关 SQL Server 6.5 COM 对象模型的详细信息,请单击下面的文章编号,以查看 Microsoft 知识库中相应的文章:

194661 SQL Server COM 对象持久性模型有关实现 Sp_OA 存储过程的方式的详细信息,请单击下面的文章编号,以查看 Microsoft 知识库中相应的文章:

180780 如何实现对 SQL Server 的 Sp_OA 过程扩展有关在 DLL 代理项中运行基于 DLL 的 COM 对象的详细信息;请参阅以下内容: Eddon、专家;Eddon Henry,分布式 Com 内部(Mps)。Microsoft 新闻,1998,(ISBN 1-57231-849-X),第八章: "DLL 代理项和可执行文件 Components'Box,不必要的 COM。Addison-Wesley Pub。Co (ISBN 0-201-63446-5)第六章: "应用程序" Grimes、Richard、专业 DCOM 编程。Wrox 按 Inc. (ISBN 1-861000-60-X),第四章: "分布式组件对象模型" 由 SQL Server 7.0 媒体附带,并且文件命名为 "Dcom95 95"。你可以从以下网站下载 Dcom95:

http://www.microsoft.com/com

需要更多帮助?

扩展你的技能
了解培训
抢先获得新功能
加入 Microsoft 内部人员

此信息是否有帮助?

谢谢您的反馈意见!

谢谢你的反馈! 可能需要转接到 Office 支持专员。

×