Carregamento de biblioteca nativa
Este artigo explica quais caminhos o runtime pesquisa ao carregar bibliotecas nativas por meio de P/Invoke. Este exemplo também mostra como usar SetDllImportResolver.
Variações do nome de biblioteca
Para simplificar o código P/Invoke entre plataformas, o runtime adiciona a extensão de biblioteca compartilhada canônica (.dll
, .so
ou .dylib
) a nomes de biblioteca nativa. Em plataformas baseadas em Unix, o runtime também tentará anexar lib
. Essas variações de nomes de biblioteca são pesquisadas automaticamente quando você usa APIs que carregam bibliotecas nativas, como DllImportAttribute.
Observação
Caminhos absolutos em nomes de biblioteca (por exemplo, /usr/lib/libc.so
) são tratados como estão e nenhuma variação será pesquisada.
Considere o seguinte exemplo de uso de P/Invoke:
[DllImport("nativedep")]
static extern int ExportedFunction();
Ao executar no Windows, a DLL é pesquisada na seguinte ordem:
nativedep
nativedep.dll
(se o nome da biblioteca já não terminar com.dll
ou .exe
)
Ao ser executado no Linux ou no macOS, o runtime tentará preceder lib
e acrescentar a extensão de biblioteca compartilhada canônica. Nesses sistemas operacionais, as variações do nome de biblioteca são tentadas na seguinte ordem:
nativedep.so
/nativedep.dylib
libnativedep.so
/libnativedep.dylib
1nativedep
libnativedep
1
No Linux, a ordem de pesquisa será diferente se o nome da biblioteca terminar com .so
ou contiver .so.
(observe o .
à direita). Considere o seguinte exemplo:
[DllImport("nativedep.so.6")]
static extern int ExportedFunction();
Nesse caso, as variações do nome de biblioteca são tentadas na seguinte ordem:
nativedep.so.6
libnativedep.so.6
1nativedep.so.6.so
libnativedep.so.6.so
1
1 O caminho será verificado somente se o nome da biblioteca não contiver um caractere separador de diretório (/
).
Resolvedor de importação personalizado
Em cenários mais complexos, você pode usar SetDllImportResolver para resolver as importações de DLL em tempo de execução. No exemplo a seguir, nativedep
será resolvido como nativedep_avx2
se a CPU der suporte.
Dica
Essa funcionalidade só está disponível no .NET Core 3.1 e no .NET 5+.
using System;
using System.Reflection;
using System.Runtime.InteropServices;
namespace PInvokeSamples
{
public static partial class Program
{
[LibraryImport("nativedep")]
private static partial int ExportedFunction();
public static void Main(string[] args)
{
// Register the import resolver before calling the imported function.
// Only one import resolver can be set for a given assembly.
NativeLibrary.SetDllImportResolver(Assembly.GetExecutingAssembly(), DllImportResolver);
int value = ExportedFunction();
Console.WriteLine(value);
}
private static IntPtr DllImportResolver(string libraryName, Assembly assembly, DllImportSearchPath? searchPath)
{
if (libraryName == "nativedep")
{
// On systems with AVX2 support, load a different library.
if (System.Runtime.Intrinsics.X86.Avx2.IsSupported)
{
return NativeLibrary.Load("nativedep_avx2", assembly, searchPath);
}
}
// Otherwise, fallback to default import resolver.
return IntPtr.Zero;
}
}
}