【问题标题】:Accessing COM in SQL CLR在 SQL CLR 中访问 COM
【发布时间】:2012-11-12 01:43:40
【问题描述】:

希望大家有个美好的一天!

对于过去三天我一直在思考的事情,我需要您的建议。我有一个用非托管平台编写的 COM 组件。该组件有一个返回某种敏感数据的方法,我需要在获得该值后立即存储它。

我需要的是调用 UDF 来访问 COM 对象并获取值。到目前为止,我已经尝试过了,但遇到了这个异常:

消息 6522,第 16 级,状态 2,第 1 行
在执行用户定义的例程或聚合“GetRate”期间发生 .NET Framework 错误: System.Runtime.InteropServices.COMException:检索 COM 类 具有 CLSID 的组件的工厂 {D039A99F-5D45-42C7-A53C-507913D8C6D6} 由于以下原因而失败 错误:80040154。
System.Runtime.InteropServices.COMException:
在 System.RuntimeTypeHandle.CreateInstance(RuntimeType 类型,布尔 publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandle& ctor, Boolean& bNeedSecurityCheck)
在 System.RuntimeType.CreateInstanceSlow(布尔 publicOnly,布尔 填充缓存)
在 System.RuntimeType.CreateInstanceImpl(布尔 publicOnly,布尔 skipVisibilityChecks,布尔 fillCache)
在 System.Activator.CreateInstance(类型类型,布尔非公共)
在 UserDefinedFunctions.GetRate(SqlString Source_Currency_Name, SqlString Destination_Currency_Name、SqlMoney 金额、SqlBoolean 模式)

该函数似乎看不到已注册的 COM 组件 (80040154)。 clr 程序集注册为不受限制。我尝试使用“sa”或 Windows 集成模式调用 UDF。没有区别。

这是初始化 COM 组件的代码,代码在 SQL 之外工作正常

Activator.CreateInstance(Type.GetTypeFromCLSID(new Guid("D039A99F-5D45-42C7-A53C-507913D8C6D6"), true))

有没有办法让这个工作人员?一种或另一种方式,我需要一个 UDF 调用这个 COM 对象,或者至少通过这个 UDF 使用 .NET 远程访问一些 Windows 服务。我们将不胜感激每一个指导我完成这种方式的建议。

谢谢大家。

【问题讨论】:

  • @DJKRAZE 我已经提到代码在 SQL 之外运行良好。 :)
  • @BehnamEsmaili 看来该链接已经解决了在 SQL 之外启动 COM 对象的问题,正如我已经提到的,我对此没有任何问题。
  • 你检查异常有没有内部异常?
  • 没错,但“SQL 外部”可能是不同于“SQL 内部”的进程位数。

标签: c# sql-server-2008 com user-defined-functions sqlclr


【解决方案1】:

我猜您是在将 CLR 程序集导入 SQL Server 吗?如果是这样,这可能是平台/架构问题。当您构建 DLL 时,您的目标平台是什么?

确保您针对正确的平台(即 x86、x64)构建 DLL。

我建议您在 Visual Studio 中的“项目属性”、“构建/平台的目标”中将项目的平台从 "Any CPU" 修改为 "X86"

然后使用"DROP ASSEMBLY",然后使用"CREATE ASSEMBLY",重新导入正确构建的dll。

您可能还需要确保已进行以下更改:

  1. 在下面找到您的 COM 对象 GUID HKey_Classes_Root/Wow6432Node/CLSID。
  2. 找到后,添加一个新的 REG_SZ(字符串)值。名字应该是 AppID 和数据应该是您刚刚获得的相同 COM 对象 GUID 搜索。
  3. 在 HKey_Classes_Root/Wow6432Node/AppID 下添加一个新密钥。新钥匙 应该与 COM 对象 GUID 一样调用。
  4. 在刚刚添加的新键下,添加新的 REG_SZ(字符串)值, 并将其称为 DllSurrogate。将该值留空。
  5. 在 HKey_Local_Machine/Software/Classes/AppID 下创建一个新密钥,如果 它还不存在。
  6. 同样,新键的调用方式应与 COM 对象的相同 图形用户界面。无需在此键下添加任何值。

另一种解决方案是使用 SQL clr 调用 WCF 服务。有关如何执行此操作,请参阅以下指南:

http://www.codeproject.com/Articles/21149/Invoking-a-WCF-Service-from-a-CLR-Trigger

【讨论】:

  • 先生,在发布问题之前我也检查过这个。那不是我的问题。我确切地知道 drop 和 create assembly 的工作原理也看看 cmets。 @Simon Mourier 说平台问题,我刚刚回答了这个问题。 :)
  • 我也认为你没有回答。第一部分是所有问题。
  • 每当有人提出关于赏金的问题时,这意味着他们需要的不仅仅是猜测和一些简单的细节。对不起,先生,但您的回答并没有给我更多。不管我在 cmets 上向大家提供的有关平台的信息如何,您的回答都只是关于 CREATE 和 DROP 语句。先生,我说的对吗?
  • 先生,我明白你的意思了。我说对不起,但您的回答根本不是我的问题,因为检查目标平台并确保正确的程序集注册是我第一次遇到此异常时检查的一些简单错误。正如我已经说过的,我只将这个赏金提供给在 SQL-CLR 中访问 COM 的解决方案,仅此而已。我想你明白我的意思。我不想让某人失望,但这根本不是我的答案。也许它在其他地方有效,但我已经检查过了。 ;) 干杯
  • 也很抱歉,您想解决我的问题还是获得投票? :)
【解决方案2】:

一般来说,我不建议使用 SQL CLR 对象作为 COM 和 SQL 之间的桥梁。从安全性开始,到非常繁琐的发布过程结束,有很多潜在的警告,需要物理访问生产 sql 框,这可能很容易获得,也可能不容易获得。

我还注意到您正在使用 Activator.CreateInstance 然后向它​​提供 clsid。在您的原始帖子中,您暗示它是一个 COM clsid。我不确定在 SQL CLR 中创建的 AppDomain 中工作的 Activator 是否真的可以找到 com clsid 的对象。

我会尝试的方式:

  • 为您的 com 创建托管代理
  • 确保已签名并放入 gac
  • 尝试从 SQL CLR 访问该托管代理

但我严重怀疑它会起作用。任何远程解决方案 WCF/WebServices/Remoting 甚至 SQL Broker 似乎都是更好的选择。

简而言之,如果没有看到实际的 .net 和 sql codez,就很难说出更多信息。

【讨论】:

  • +1 不错的尝试身体。我曾尝试在 SQL CLR 中使用 .NET Remoting,但它似乎使事情变得更加复杂。还有其他建议吗?我需要一个从 SQL CLR 访问 COM 的解决方案。这些都是我已经尝试过的大部分技术问题。顺便谢谢你。
  • 您也可以尝试一些深奥的解决方案,如此链接codeproject.com/Articles/37140/…
【解决方案3】:

如果您的 COM 应用程序的网络版本非常好,则在 sql select * from sys.dm_clr_properties 上运行此 cmd 仅当网络版本小于或等于时才有效!!!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-07-27
    • 2017-02-04
    • 1970-01-01
    • 2015-03-05
    • 1970-01-01
    • 1970-01-01
    • 2013-01-14
    相关资源
    最近更新 更多