我知道关于32/64位冲突的问题有很多答案,但是在这种情况下,所有内容都可以在64位进程中运行。
我正在帮助客户从SQL Server 2008 R2 x64升级到SQL Server 2016 x64上的新实例。 客户有一些旧过程(数百个),这些过程使用sp_OACreate / Method / Destroy序列来使我们的产品的COM接口使用C#编码并暴露给COM和目标x64。使用x64版本的RegAsm注册,并具有强大的名称并将其加载到GAC中。
在我的环境中,我具有SQL 2008 R2 runnign,并且所有这些均按预期工作。我安装了SQL 2016并重现了该问题。
(我知道最好使用不同的方法,但是由于这种方法在很多地方都可以使用,因此不易更改。)
我还测试了在VB脚本中创建对象的过程,这可以按预期工作。能够在64位进程中运行VBScript并调用CreateObject
。
EXEC @hr = sp_OACreate 'Satori64.CASSTask', @TaskObject OUT, 4
EXEC sp_OAGetErrorInfo @TaskObject, @ErrorSource out , @ErrorDescription out
ErrorSource = "ODSOLE Extended Procedure"
ErrorDescription = "Class not registered"
hr = "-2147221164" (80040154)
EXEC @hr = sp_OACreate 'Satori64.CASSTask', @TaskObject OUT, 1
EXEC sp_OAGetErrorInfo @TaskObject, @ErrorSource out , @ErrorDescription out
ErrorSource = "ODSOLE Extended Procedure"
ErrorDescription = ""
hr = "-2146234287" (80131051)
在进行了更多研究并查看了procmon日志之后,我发现SQL Server查找COM对象的方式与vbscript查找并加载它的方式大不相同。
由于有一些评论,我更深入地介绍了procmon日志,以查看可能发生的情况。在SQL 2008 R2和2016之间,文件和注册表访问类似。 2008日志显示装配了装配体,并找到并创建了预期的对象。 2016日志显示它能够找到程序集,但随后立即意外失败。尽管这样做有帮助,但它没有回答出什么问题了。
因此,我更加深入地研究了是否可以找到为什么未加载程序集的原因。
我添加了:
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Fusion]
"LogFailures"=dword:00000001
"ForceLog"=dword:00000001
"LogPath"="C:\\Temp\\Fusion\\"
并查看了两个版本的日志:
SQL R2 2008成功
*** Assembly Binder Log Entry (11/18/2019 @ 10:06:54 PM) ***
The operation was successful.
Bind result: hr = 0x0. The operation completed successfully.
Assembly manager loaded from: C:\Windows\Microsoft.NET\Framework64\v4.0.30319\clr.dll
Running under executable C:\Program Files\Microsoft SQL Server 2008\MSSQL10_50.MSSQL2008\MSSQL\Binn\sqlservr.exe
--- A detailed error log follows.
=== Pre-bind state information ===
LOG: DisplayName = Satori64, Version=4.7.1.1, Culture=neutral, PublicKeyToken=ac6bbd3b7853cfdf
(Fully-specified)
LOG: Appbase = file:///C:/Program Files/Microsoft SQL Server 2008/MSSQL10_50.MSSQL2008/MSSQL/Binn/
LOG: Initial PrivatePath = NULL
LOG: Dynamic Base = NULL
LOG: Cache Base = NULL
LOG: AppName = sqlservr.exe
Calling assembly : (Unknown).
===
LOG: This bind starts in default load context.
LOG: Download of application configuration file was attempted from file:///C:/Program Files/Microsoft SQL Server 2008/MSSQL10_50.MSSQL2008/MSSQL/Binn/sqlservr.exe.config.
LOG: Configuration file C:\Program Files\Microsoft SQL Server 2008\MSSQL10_50.MSSQL2008\MSSQL\Binn\sqlservr.exe.config does not exist.
LOG: No application configuration file found.
LOG: Using host configuration file:
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework64\v4.0.30319\config\machine.config.
LOG: Post-policy reference: Satori64, Version=4.7.1.1, Culture=neutral, PublicKeyToken=ac6bbd3b7853cfdf
LOG: Found assembly by looking in the GAC.
LOG: Binding succeeds. Returns assembly from C:\windows\Microsoft.Net\assembly\GAC_64\Satori64\v4.0_4.7.1.1__ac6bbd3b7853cfdf\Satori64.dll.
LOG: Assembly is loaded in default load context.
SQL 2016失败
*** Assembly Binder Log Entry (11/18/2019 @ 10:08:37 PM) ***
The operation failed.
Bind result: hr = 0x80070002. The system cannot find the file specified.
Assembly manager loaded from: C:\Windows\Microsoft.NET\Framework64\v4.0.30319\clr.dll
Running under executable C:\Program Files\Microsoft SQL Server\MSSQL13.SQLSERVER\MSSQL\Binn\sqlservr.exe
--- A detailed error log follows.
=== Pre-bind state information ===
LOG: DisplayName = Satori64, Version=4.7.1.1, Culture=neutral, PublicKeyToken=ac6bbd3b7853cfdf
(Fully-specified)
LOG: Appbase = file:///C:/Program Files/Microsoft SQL Server/MSSQL13.SQLSERVER/MSSQL/Binn/
LOG: Initial PrivatePath = NULL
LOG: Dynamic Base = NULL
LOG: Cache Base = NULL
LOG: AppName = sqlservr.exe
Calling assembly : (Unknown).
===
LOG: This bind starts in default load context.
LOG: Using application configuration file: C:\Program Files\Microsoft SQL Server\MSSQL13.SQLSERVER\MSSQL\Binn\sqlservr.exe.Config
LOG: Using host configuration file:
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework64\v4.0.30319\config\machine.config.
LOG: Post-policy reference: Satori64, Version=4.7.1.1, Culture=neutral, PublicKeyToken=ac6bbd3b7853cfdf
LOG: Fusion is hosted. Check host about this assembly.
LOG: Assembly is not in CLR Loaded list. Asking host assembly store.
LOG: Try host assembly store with assembly satori64, version=4.7.1.1, culture=neutral, publickeytoken=ac6bbd3b7853cfdf, processorarchitecture=amd64.
LOG: Try host assembly store with assembly satori64, version=4.7.1.1, culture=neutral, publickeytoken=ac6bbd3b7853cfdf, processorarchitecture=msil.
LOG: Try host assembly store with assembly satori64, version=4.7.1.1, culture=neutral, publickeytoken=ac6bbd3b7853cfdf.
WRN: Host assembly store does not contain this assembly.
ERR: Unrecoverable error occurred during pre-download check (hr = 0x80070002).
在这里我有点茫然。 SQL可以加载程序集,但是由于某些原因,不能通过COM访问它。
我决定从头开始,创建一个具有绝对最小引用的新程序集,一个具有单个方法的类。 我强烈命名它,并在RegAsm(x64)中注册了它,并将其加载到GAC。
这显示了完全相同的结果。 sp_OACreate可以在2008 R2中正常运行。在2014年和2016年失败。
任何想法将不胜感激!