2009-10-15 5 views
10

Есть ли способ, чтобы конкретная DLL, на которую ссылалась подпись P/Invoke (DllImport), зависела от архитектуры ЦП?Архитектура процессора Независимый P/Invoke: Может ли DllName или путь быть «динамическим»?

Я работаю над приложением, которое загружает большое количество сигнатур методов из родной dll от стороннего поставщика, в этом случае DLL-интерфейс пользовательского пространства к части оборудования. Этот поставщик теперь начал поставлять как x86, так и x64 версии DLL сейчас, и я думаю, что мое приложение выиграет от работы как 64-битный процесс. За исключением этой DLL, все это код .NET, поэтому создание «Any CPU» будет работать.

Все сигнатуры метода в родной DLL одинаковы на 64-битной основе, однако имя библиотеки DLL отличается (Foo.dll и Foo_x64.dll). Есть ли какой-либо способ через подписи P/Invoke или записи app.config, я могу заставить его выбрать, какую DLL загружать на основе текущей архитектуры процессора?

Если вместо разных DLL-имен это одно и то же имя в разных папках, открывает ли он какие-либо другие параметры?

NB: Поскольку версия DLL этого пользовательского пространства соответствует установленному драйверу ядра для аппаратного обеспечения, DLL не поставляется вместе с нашим приложением, но вместо этого мы зависим от установщика поставщика, чтобы поместить его в в папке% PATH%.

+0

Возможный дубликат http: // stackoverflow.com/questions/23215518/target-32-bit-or-64-bit-native-dll-depends-on-environment –

+3

Я думаю, что дублирование - это наоборот, учитывая, что этот вопрос на четыре года старше этого :) – Cheetah

ответ

4

Невозможно создать ни одну подпись PInvoke и получить нужное поведение. Атрибут сжигается в метаданные и должен иметь постоянные значения. Один взлом, который вы могли бы сделать, это иметь несколько методов.

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(); 
    } 
} 

Однако это не предпочтительный подход. Более простой подход заключается в том, чтобы сделать DLL одинаковым именем на нескольких платформах и создать сигнатурную сигнатуру PInvoke для платформы. Это подход, используемый большинством/всеми библиотеками Windows.

+0

То же имя не работает для моего случая, потому что 1) Это сторонний поставщик DLL 2) DLL (-ы) установлены в папку в системе PATH, чтобы приложения могли находить их автоматически (к счастью поставщик больше не устанавливает на% SystemRoot% \ system32) 3) На 64-битной ОС должны быть доступны как 32-битные, так и 64-битные DLL. # 1 означает, что я не могу играть, а # 2 конфликтует с # 3 , Я закончил с помощью решения, аналогичного тому, что вы предложили. Я определил интерфейс со всеми этими методами и использовал LinFu для создания прокси-объекта во время выполнения, который переходит к правильным статическим методам. – Cheetah

11

«Если вместо разных DLL-имен это одно и то же имя в разных папках, открывает ли он какие-либо другие параметры?»

Может быть, это будет работать для вас:

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); 
    } 
    } 
} 

Он состоит в явной загрузки родной библиотеки с ее полный путь, прежде чем P/Invoke сам пытается загрузить его.

Как вы думаете?

+0

Это будет работа с Window/MS.NET, но как насчет Mono? – AndreyAkinshin

+0

Не знаю, Моно, пожалуйста, сообщите нам, что вы узнали –

+0

ничего на данный момент = ( – AndreyAkinshin

1

Я разработал специальную библиотеку для цели: InteropDotNet. Он вводит новый атрибут RuntimeDllImport с разрешением динамического пути библиотеки («на лету»). По умолчанию вы можете написать

[RuntimeDllImport("NativeLib", 
    CallingConvention = CallingConvention.Cdecl, EntryPoint = "sum")] 
int Sum(int a, int b); 

И библиотека будет решена в зависимости от окружающей среды. Например, пути для Win/Linux, x86/x64:

x86/NativeLib.dll 
x86/libNativeLib.so 
x64/NativeLib.dll 
x64/libNativeLib.so 

 Смежные вопросы

  • Нет связанных вопросов^_^