2009-10-15 10 views
10

Czy istnieje sposób, aby konkretna biblioteka DLL, do której odwołuje się podpis P/Invoke (DllImport), zależy od architektury procesora?Architektura CPU Niezależne P/Wywołanie: czy nazwa lub nazwa Dll może być "dynamiczna"?

Pracuję nad aplikacją, która ładuje dużą liczbę podpisów metod z rodzimej biblioteki dll od zewnętrznego dostawcy, w tym przypadku DLL interfejsu użytkownika do części sprzętu. Ten dostawca zaczął teraz dostarczać wersje bibliotek DLL w wersji x86 i x64 teraz i myślę, że moja aplikacja mogłaby odnieść korzyści z uruchamiania jako proces 64-bitowy. Z wyjątkiem tej jednej DLL, wszystko jest .NET kod, więc budowanie jako "Any CPU" będzie działać.

Wszystkie sygnatury metod w macierzystej bibliotece DLL są takie same na 64-bitach, jednak nazwa biblioteki DLL jest inna (Foo.dll vs. Foo_x64.dll). Czy istnieje jakiś sposób przez podpisy P/Invoke lub wpisy app.config mogę go pobrać, aby wybrać bibliotekę DLL do załadowania w oparciu o działającą architekturę procesora?

Jeśli zamiast różnych nazw plików DLL było to to samo nazwisko w różnych folderach, czy to spowoduje otwarcie innych opcji?

NB: Ponieważ jest istotne, że wersja tej przestrzeni użytkownika DLL jest zgodna z zainstalowanym sterownikiem jądra dla sprzętu, biblioteka DLL nie jest dołączona do naszej aplikacji, ale zamiast tego zależymy od instalatora dostawcy, aby umieścić go w katalog w% PATH%.

+0

Możliwe duplikaty http: // stackoverflow.com/questions/23215518/target-32-bit-or-64-bit-native-dll-depend-on-environment –

+3

Myślę, że duplikacja jest odwrotna, ponieważ to pytanie jest cztery lata starsze niż to :) – Cheetah

Odpowiedz

4

Nie można uzyskać pojedynczego podpisu PInvoke i uzyskać pożądanego zachowania. Atrybut jest wypalany na metadane i musi mieć stałe wartości. Jeden hack, który możesz zrobić, to mieć wiele metod.

public static class NativeMethods32 { 
    [DllImport("Foo.dll")] 
    public static extern int SomeMethod(); 
} 

public static class NativeMethods64 { 
    [DllImport("Foo_x864.dll")] 
    public static extern int SomeMethod(); 
} 

public static class NativeMethods { 
    public static bool Is32Bit { return 4 == IntPtr.Size; } 
    public static SomeMethod() { 
    return Is32Bit ? 
     NativeMethods32.SomeMethod(); 
     NativeMethods64.SomeMethod(); 
    } 
} 

Jednak nie jest to preferowane podejście. Łatwiejszym podejściem byłoby uczynienie biblioteki DLL taką samą nazwą na wielu platformach i stworzenie agnostycznego podprogowego podpisu PInvoke. Jest to podejście, które podejmuje większość/wszystkie biblioteki okien.

+0

Ta sama nazwa nie działa dla mojego przypadku, ponieważ 1) Jest to trzecia strona dostawcy DLL 2) DLL (s) są zainstalowane do folderu w PATH systemu, dzięki czemu aplikacje mogą je znaleźć automatycznie (na szczęście sprzedawca nie instaluje się ponownie do% SystemRoot% \ system32) 3) W 64-bitowym systemie operacyjnym zarówno 32-bitowe, jak i 64-bitowe biblioteki DLL muszą być dostępne. # 1 oznacza, że ​​nie mogę skrzypce i # 2 konflikty z # 3 . Skończyło się na użyciu rozwiązania podobnego do tego, co zasugerowałeś. Zdefiniowałem interfejs ze wszystkimi metodami i użyłem LinFu do stworzenia obiektu proxy w czasie wykonywania, który przekazuje poprawne statyczne metody. – Cheetah

11

"Jeśli zamiast różnych nazw plików DLL było to to samo nazwisko w różnych folderach, czy to spowoduje otwarcie innych opcji?"

Może to będzie działać dla Ciebie:

public static class NativeMethods 
{ 
    // here we just use "Foo" and at runtime we load "Foo.dll" dynamically 
    // from any path on disk depending on the logic you want to implement 
    [DllImport("Foo", EntryPoint = "bar")] 
    private void bar(); 

    [DllImport("kernel32")] 
    private unsafe static extern void* LoadLibrary(string dllname); 

    [DllImport("kernel32")] 
    private unsafe static extern void FreeLibrary(void* handle); 

    private sealed unsafe class LibraryUnloader 
    { 
    internal LibraryUnloader(void* handle) 
    { 
     this.handle = handle; 
    } 

    ~LibraryUnloader() 
    { 
     if (handle != null) 
     FreeLibrary(handle); 
    } 

    private void* handle; 

    } // LibraryUnloader 

    private static readonly LibraryUnloader unloader; 

    static NativeMethods() 
    { 
    string path; 

    if (IntPtr.Size == 4) 
     path = "path/to/the/32/bit/Foo.dll"; 
    else 
     path = "path/to/the/64/bit/Foo.dll"; 

    unsafe 
    { 
     void* handle = LoadLibrary(path); 

     if (handle == null) 
     throw new DllNotFoundException("unable to find the native Foo library: " + path); 

     unloader = new LibraryUnloader(handle); 
    } 
    } 
} 

Polega ona wyraźnie ładowania natywną bibliotekę z jego pełną ścieżkę przed P/Invoke sama próbuje go załadować.

Co myślisz?

+0

Będzie to działać z Window/MS.NET, ale co z Mono? – AndreyAkinshin

+0

Nie mam pojęcia o Mono, proszę powiedz nam, czego się dowiesz –

+0

nic na teraz = ( – AndreyAkinshin

1

Opracowałem specjalną bibliotekę dla celu: InteropDotNet. Wprowadza nowy atrybut RuntimeDllImport z dynamicznym rozdzielaniem ścieżek biblioteki (w locie). Domyślnie można napisać:

I biblioteka zostanie rozwiązana zależy od środowiska. Na przykład ścieżki dla Win/Linux, x86/x64:

x86/NativeLib.dll 
x86/libNativeLib.so 
x64/NativeLib.dll 
x64/libNativeLib.so 
Powiązane problemy