سؤال

I'm confused by the behavior of Assembly.LoadFrom. In my application I call Assembly.LoadFrom to a .NET .exe and start it using EntryPoint.Invoke (this odd approach is useful for building a launcher app on non-Windows platforms).

I had assumed that since the assemblyFile was in a different folder, that it would fail to find some managed .dll dependencies that are located in the same folder as it. But it worked; it didn't fail...

It would appear that when I called Assembly.LoadFrom(assemblyFile), it checked the folder containing assemblyFile for managed dependencies of assemblyFile. I didn't expect this. What would happen if that assembly had unmanaged dependencies (such as a DllImport), would it still search that same directory? And is this behavior framework specific?

هل كانت مفيدة؟

المحلول

The Assembly has nothing to do with loading unmanagged libraries. What does the loading for unmanaged libraries is the DllImport call which is lazy (does not load till the first call).

DllImport in turn (in .NET, I don't know what Mono does on other platforms) calls LoadLibary on windows. LoadLibary has a known set of rules for how it resolves it's dependencies:

  • If a DLL with the same module name is already loaded in memory, the system uses the loaded DLL, no matter which directory it is in. The system does not search for the DLL.
  • If the DLL is on the list of known DLLs for the version of Windows on which the application is running, the system uses its copy of the known DLL (and the known DLL's dependent DLLs, if any). The system does not search for the DLL. For a list of known DLLs on the current system, see the following registry key: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs.

If those two points are not met and SafeDllSearchMode is enabled (it is by default for for XP SP2 and newer) it uses the following order

  1. The directory from which the application loaded.
  2. The system directory. Use the GetSystemDirectory function to get the path of this directory.
  3. The 16-bit system directory. There is no function that obtains the path of this directory, but it is searched.
  4. The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.
  5. The current directory.
  6. The directories that are listed in the PATH environment variable. Note that this does not include the per-application path specified by the App Paths registry key. The App Paths key is not used when computing the DLL search path.

So to answer your question, no the directory your managed assembly is located in is not searched when looking for unmanaged assemblies, only the directory of the application that loaded your managed assembly.

However all hope is not lost, you can call SetDLLDirectory and add the folder of your managed assembly and it will include it in the search when looking for the unmanaged DLL, it will change the search order to

  1. The directory from which the application loaded.
  2. The directory specified by the lpPathName parameter (in the SetDLLDirectory call).
  3. The system directory. Use the GetSystemDirectory function to get the path of this directory. The name of this directory is System32.
  4. The 16-bit system directory. There is no function that obtains the path of this directory, but it is searched. The name of this directory is System.
  5. The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.
  6. The directories that are listed in the PATH environment variable.

If you need to add more than one folder for searching see the MSDN for documenation on AddDllDirectory for the steps required to allow for multiple search directories.

نصائح أخرى

None of the .NET specific configuration affects the way unmanaged DLLs are located. Normal operating system search rules are in effect, regardless of how the CLR finds managed assemblies. The underlying OS call on Windows is LoadLibrary(), a winapi function that has no support for altering search rules itself. You can specify a full path name to avoid searching but that's almost never practical in pinvoke.

If this is a problem then you'll have to write explicit code to help the OS locate the file. Common techniques are pinvoking SetDllDirectory(), altering the PATH environment variable with Environment.SetEnvironmentVariable() and changing the default directory by assigning Environment.CurrentDirectory

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top