在 SQL Server 进程外部运行基于 DLL 的 COM 对象

本文介绍如何在 SQL Server 进程外部运行基于 DLL 的 COM 对象。

原始产品版本:SQL Server
原始 KB 数: 198891

总结

Microsoft SQL Server 提供通过一组 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 对象的过程称为远程处理。 远程处理要求另一个可执行文件是代理进程,以取代 SQL Server 可执行文件。 DCOM 服务控制管理器(rpcss.exe)使用的默认可执行文件名为 dllhost.exe。 DCOM 支持结构使用 dllhost.exe 文件将 DLL 加载到其进程空间中,然后使用代理/存根对以透明方式将请求的接口封送回客户端,在本例中为 SQL Server。 此可执行文件可以同时接受多个接口/方法请求。 接口使用完成后,DCOM 服务控制管理器(SCM)管理dllhost.exe文件的清理和卸载。 不应期望 COM 对象在实例化之间保留状态信息。

以下步骤适用于在 SQL Server 进程空间中创建的任何基于 DLL 的 COM 对象,无论是通过实例化 sp_OACreate 还是扩展存储过程。

详细信息

下面介绍了可用于实例化 COM 对象的两种基本方法的信息。

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

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

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

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

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

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

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

  • 使用 Visual C++ 附带的 OLE/COM 对象查看器(oleview.exe),并在“所有对象”下找到 ProgIDOLEComponent.Object。 选择 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
      
    2. 可以使用编程标识符查找 COM 对象的类标识符。

      打开注册表编辑器(regedit.exe),在密钥下HKEY_CLASSES_ROOT使用Find该方法查找具有 OLEComponent.Object> 名称的<键。 你可以在其他级别找到它,但它应位于该级别直接位于该 HKEY_CLASSES_ROOT级别。 找到密钥后,展开密钥名称的文件夹,应会看到名为 CLSID 的子项。 选择该文件夹以查看该键中的值。 屏幕右侧是一个名为 Default 的标题。 该键的数据应采用以下形式:

      {59F929A0-74D8-11D2-8CBC-08005A390B09}

      记下此值或将其复制到记事本。 包括方括号。

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

    4. 在 GUID 的 InprocServer32 子项下,请确保存在一个 ThreadingModel 值,并且它设置为“两者”或“免费”,以确保封送处理了解 COM 对象的线程模型,以便从 SQL Server 进程空间中执行 COM。 ThreadingModel如果没有值或设置为“单元”,则 COM 对象实例化可能不一致。

      注意

      如果添加 ThreadingModel 该值,请确保在实现之前测试 COM 对象。

    5. 突出显示密钥下的 HKEY_CLASSES_ROOT\CLSID GUID 编号/子项。 从“编辑”菜单中选择“新建,然后选择“字符串值”。 在 “名称” 列下,键入 AppID

    6. Enter ,然后插入从步骤 1 中记录的类标识符或 GUID 编号作为值。 GUID 应位于大括号内,如以下示例所示:

      {59F929A0-74D8-11D2-8CBC-08005A390B09}
      

      DCOM 使用应用程序标识符 AppID 将 DLL 与可执行文件相关联。

    7. 在下方 HKEY_CLASSES_ROOT\AppID 添加新的子项,并将其名称设置为同一类标识符或 GUID 编号,并在上一步中插入括号。

    8. 突出显示 GUID 名称。 从“编辑”菜单中选择“新建,然后选择“字符串值”。 在“名称”列下,键入 dllSurrogate

      将“数据”列留空表示此值。 由于数据列为空,因此通知 DCOM 运行默认可执行文件, dllhost.exe,并在其进程空间中加载 COM 对象。

    9. 关闭“注册表编辑器”。 单击“开始,然后选择“运行”。 在 “运行 ”对话框中,键入 DCOMCNFG

      按 Enter 键打开“分布式 COM 配置属性”对话框。 单击“默认属性”选项卡,并确保已选中此计算机上的“启用分布式 COM”。 如果不是,请选择它,然后选择“ 应用”。

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

      OLE 自动化错误信息
      HRESULT:0x80040154
      源:ODSOLE 扩展过程
      说明:类未注册

      OLE 自动化错误信息
      HRESULT:0x80070005
      源:ODSOLE 扩展过程
      说明:访问被拒绝。

      OLE 自动化错误信息
      HRESULT:0x80080005
      源:ODSOLE 扩展过程
      说明:服务器执行失败

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

      WAITFOR DELAY '000:00:20'
      

      运行脚本并立即导航到命令提示符并运行 tlist.exe 文件。 记下 dllhost.exe PID。 重新运行 tlist.exe 并将 PID 作为参数传递。 这显示了在dllhost.exe进程空间中加载的 DLL。 基于 DLL 的 COM 对象应列为在此进程中运行。 脚本返回后,再次运行 tlist.exe 会显示 dllhost.exe 进程不再运行。

      在以下示例输出中,ADODB。 连接对象是在 SQL Server 进程空间之外创建的。 在 com 对象存在于dllhost.exe进程空间中时,执行了使用 tlist.exe此快照。 请注意,加载模块 msado15.dll,即包含 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
      

参考

OLE 自动存储过程 (Transact-SQL)