C# Assembly.LoadFrom如何解析非托管依赖项?

C# Assembly.LoadFrom如何解析非托管依赖项?,c#,.net,dllimport,C#,.net,Dllimport,我被他的行为弄糊涂了。在我的应用程序中,我调用Assembly.LoadFrom到.NET.exe,并使用EntryPoint.Invoke启动它(这种奇怪的方法对于在非Windows平台上构建启动器应用程序非常有用) 我假设由于assemblyFile位于不同的文件夹中,它将无法找到与其位于同一文件夹中的一些托管.dll依赖项。但它奏效了;它没有失败 似乎当我调用Assembly.LoadFrom(assemblyFile)时,它检查了包含assemblyFile的文件夹中是否存在assemb

我被他的行为弄糊涂了。在我的应用程序中,我调用
Assembly.LoadFrom
到.NET
.exe
,并使用
EntryPoint.Invoke
启动它(这种奇怪的方法对于在非Windows平台上构建启动器应用程序非常有用)

我假设由于
assemblyFile
位于不同的文件夹中,它将无法找到与其位于同一文件夹中的一些托管
.dll
依赖项。但它奏效了;它没有失败


似乎当我调用
Assembly.LoadFrom(assemblyFile)
时,它检查了包含
assemblyFile
的文件夹中是否存在
assemblyFile
的托管依赖项。我没想到会这样。如果该程序集具有非托管依赖项(例如
DllImport
),它还会搜索同一目录吗?这种行为是特定于框架的吗?

特定于.NET的配置都不会影响非托管DLL的定位方式。无论CLR如何查找托管程序集,正常的操作系统搜索规则都有效。Windows上的底层操作系统调用是LoadLibrary(),这是一个winapi函数,不支持更改搜索规则本身。您可以指定一个完整的路径名以避免搜索,但这在pinvoke中几乎不实用


如果这是一个问题,那么您必须编写显式代码来帮助操作系统定位该文件。常用的技术有pinvoking SetDllDirectory()、使用environment.SetEnvironmentVariable()更改PATH环境变量,以及通过分配environment.CurrentDirectory更改默认目录。
程序集与加载未管理的库无关。非托管库的加载是延迟的
DllImport
调用(直到第一次调用才加载)

DllImport反过来(在.NET中,我不知道Mono在其他平台上做什么)在windows上调用
LoadLibrary
对如何解析其依赖项有如下说明:

  • 如果内存中已经加载了具有相同模块名称的DLL,则系统将使用加载的DLL,无论它位于哪个目录中。系统不搜索DLL
  • 如果DLL位于运行应用程序的Windows版本的已知DLL列表中,系统将使用其已知DLL的副本(以及已知DLL的从属DLL,如果有)。系统不搜索DLL。有关当前系统上已知DLL的列表,请参阅以下注册表项:
    HKEY\U LOCAL\U MACHINE\system\CurrentControlSet\Control\Session Manager\KnowNDLL
如果不满足这两点,并且启用了
SafeDllSearchMode
(XP SP2和更新版本的默认设置),则使用以下顺序

  • 从中加载应用程序的目录
  • 系统目录。使用GetSystemDirectory函数获取此目录的路径
  • 16位系统目录。没有获取此目录路径的函数,但会对其进行搜索
  • Windows目录。使用GetWindowsDirectory函数获取此目录的路径
  • 当前目录
  • PATH环境变量中列出的目录。请注意,这不包括应用程序路径注册表项指定的每个应用程序路径。计算DLL搜索路径时不使用应用路径键

  • 因此,为了回答您的问题,在查找非托管程序集时,不会搜索托管程序集所在的目录,只搜索加载托管程序集的应用程序的目录

    但是,所有希望都没有丧失,您可以调用并添加托管程序集的文件夹,它将在搜索中包含该文件夹。当查找非托管DLL时,它将将搜索顺序更改为

  • 从中加载应用程序的目录
  • lpPathName参数指定的目录(在SetDLLDirectory调用中)
  • 系统目录。使用GetSystemDirectory函数获取此目录的路径。此目录的名称为System32
  • 16位系统目录。没有获取此目录路径的函数,但会对其进行搜索。此目录的名称为System
  • Windows目录。使用GetWindowsDirectory函数获取此目录的路径
  • PATH环境变量中列出的目录

  • 如果您需要添加多个文件夹进行搜索,请参阅上的MSDN for documenation,了解允许多个搜索目录所需的步骤。

    没有什么奇怪的,Mono中的行为也是一样的。对于未经管理的依赖项…应用平台的常规规则(请参阅Windows的LoadLibrary()。老实说,我不确定,但我认为这是特定于平台的,所以对于Mono,比方说,在Linux上,正常的Linux规则将应用于搜索。@Adriano,但JIT惰性地解析
    DllImport
    。当
    DllImport(“myweetlibrary.dylib”)
    最终被解析时,它会知道它来自遥远目录中的
    assemblyFile
    ,并搜索该目录吗?我猜不会的。