【问题标题】:How to find exact cause that makes System.Reflection.Assembly.LoadFile fail?如何找到导致 System.Reflection.Assembly.LoadFile 失败的确切原因?
【发布时间】:2021-03-10 15:29:42
【问题描述】:

LoadFile() 功能真的让我很难受。 我有两个程序集,Asm1.dllAsm2.dll,它们正在 GAC 中安装。 稍后,使用LoadFile() 加载这些程序集以创建匹配的类型库。

这一切都适用于Asm1.dll(在 PowerShell 中测试):

[System.Reflection.Assembly]::LoadFile("D:\MyTools\Asm1.dll")

GAC    Version        Location
True   v4.0.30319     C:\Windows\Microsoft.Net\assembly\GAC_64\Asm1\v4.0_4.0.30000.0__abcdef123456\Asm1.dll

但它不适用于Asm2.dll

[System.Reflection.Assembly]::LoadFile("D:\MyTools\Asm2.dll")

Exception calling "LoadFile" with "1" argument(s): "Could not load file or assembly 'Asm2.dll'
or one of its dependencies. The specified module could not be found."

但是,这两个程序集确实存在于我的工作文件夹以及 GAC 中:

gci C:\Windows\Microsoft.Net\assembly\GAC_64\Asm2\v4.0_2.3.30000.0__abcdef123456\Asm2.dll
gci C:\Windows\Microsoft.Net\assembly\GAC_64\Asm1\v4.0_4.0.30000.0__abcdef123456\Asm1.dll

Mode                LastWriteTime         Length Name
-a----      10 Mar 2021     15:37        1494528 Asm2.dll
-a----      10 Mar 2021     12:47        6749184 Asm1.dll

gci D:\MyTools\Asm1.dll
gci D:\MyTools\Asm2.dll

Mode                LastWriteTime         Length Name
-a----      10 Mar 2021     12:47        6749184 Asm1.dll
-a----      10 Mar 2021     14:00        1494528 Asm2.dll

我还尝试使用完整的 GAC 路径 LoadFile() - 两个程序集的结果相同。

从过去我知道,在重建我的工具之前,从我的组件的所有痕迹中清除 HKCU 注册表和 GAC 后,问题就消失了。但在我更新了 Visual Studio 并在没有先清理所有东西的情况下重建了我的工具之后,它确实在今天早上重新出现。

LoadFile() 函数就像一个黑匣子,准确地告诉我出了什么问题。打个比方,我不想再通过“在我只是在寻找熔断的保险丝时拆除我的整个建筑物”来解决这个问题。

那么我该如何追踪这个失败的根本原因呢?

编辑

@Efie 谢谢。 $error[0] 仅指向 LoadFile() 函数作为错误源。那里没有其他见解。

@Ian Kemp、@Jeroen Mostert 感谢您推荐融合日志查看器。

它确实提供了一些信息,但仍未指出实际原因。相反 - 日志表明程序集绑定成功,而错误消息仍然出现在 PowerShell 控制台中。

The operation was successful.

=== Pre-bind state information ===
LOG: DisplayName = Asm2, Version=2.3.30000.0, Culture=neutral, 
PublicKeyToken=abcdef123456
 (Fully-specified)
LOG: Appbase = file:///C:/Windows/system32/WindowsPowerShell/v1.0/
LOG: Initial PrivatePath = NULL
LOG: Dynamic Base = NULL
LOG: Cache Base = NULL
LOG: AppName = PowerShell_ISE.exe
Calling assembly : (Unknown).
===
LOG: This bind starts in default load context.
LOG: Using application configuration file: 
C:\Windows\system32\WindowsPowerShell\v1.0\PowerShell_ISE.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: Binding succeeds. Returns assembly from C:\Windows\Microsoft.Net\assembly\GAC_64\Asm2\v4.0_2.3.30000.0__abcdef123456\Asm2.dll.
LOG: Assembly is loaded in default load context.

两个程序集 Asm1Asm2 的日志文件是相同的,除了名称、版本以及融合日志明确报告它在 GAC 中找到 Asm1 而它没有不要为Asm2 这样做:

LOG: Post-policy reference: Asm1, Version=4.0.30000.0, Culture=neutral, PublicKeyToken=abcdef123456
LOG: Found assembly by looking in the GAC.

如果我在对LoadFile() 的两个调用中指定完整的 GAC 路径,则两个程序集 Asm1Asm2 的日志文件除了名称和版本之外是相同的;包括Post-policy-line。

【问题讨论】:

  • 错误对象内可能有其他信息。只有消息被打印到屏幕上。您可以通过检查$error 变量来检查最近的错误,例如$error[0]。有时那里隐藏着其他信息。 $error[0] | Get-Member 将为您提供可以进一步挖掘的属性列表。
  • 那个黑匣子确实有记录功能。 See also.
  • 我呼吁那些反对这个问题的人提出解决方案!与此同时,我运行了dependency walker。它检测到 Asm1.dll 对OLE32.DLL 的依赖(不出所料)。但它也检测到 c:\windows\system32\OLE32.DLLc:\program files\powershell\7\API-MS-WIN-CORE-COM-L1-1-0.DLL 之间的循环依赖关系,我认为这是 PowerShell 中的一个错误。但是,临时重命名 PowerShell 文件夹删除了循环依赖,但并没有解决原始问题。还有什么想法吗?

标签: c# powershell fusion-log-viewer


【解决方案1】:

我过去使用的模式是这样的(我是凭记忆做的,所以可能需要调整才能真正起作用!):

try
{
    Add-Type -LiteralPath "c:\temp\myassembly.dll";
}
catch [System.Reflection.ReflectionTypeLoadException]
{
    $ex = $_.psbase.Exception;
    foreach( $item in $ex.LoaderExceptions )
    {
        write-host $ex.ToString();
    }
    throw;
}

【讨论】:

  • 返回的信息与 PowerShell 在调用 [System.Reflection.Assembly]::LoadFile("c:\temp\myassembly.dll") 时打印的异常完全相同。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-09-11
  • 1970-01-01
  • 1970-01-01
  • 2012-09-13
  • 1970-01-01
  • 2014-01-17
  • 2018-08-04
相关资源
最近更新 更多