2009-10-15 24 views
10

Có cách nào để có DLL cụ thể được tham chiếu bằng chữ ký P/Invoke (DllImport) phụ thuộc vào kiến ​​trúc CPU không?Kiến trúc CPU Độc lập P/Gọi: DllName hoặc đường dẫn có thể là "động" không?

Tôi đang làm việc trên một ứng dụng tải một số lượng lớn các chữ ký phương thức từ một dll gốc từ một nhà cung cấp bên thứ ba, trong trường hợp này giao diện người dùng-không gian DLL tới một phần cứng. Nhà cung cấp đó hiện đã bắt đầu cung cấp cả hai phiên bản x86 và x64 của DLL bây giờ, và tôi nghĩ rằng ứng dụng của tôi sẽ được hưởng lợi từ việc chạy như một quá trình 64bit. Ngoại trừ một DLL này, mọi thứ đều là mã .NET, vì vậy việc xây dựng thành "CPU bất kỳ" sẽ hoạt động.

Tất cả các chữ ký của phương thức trong DLL gốc đều giống nhau trên 64bit, tuy nhiên tên của DLL khác nhau (Foo.dll so với Foo_x64.dll). Có cách nào thông qua hoặc P/Invoke chữ ký hoặc app.config mục tôi có thể nhận được nó để chọn DLL để tải dựa trên kiến ​​trúc CPU đang chạy?

Nếu thay vì các tên DLL khác nhau, tên này giống với tên trong các thư mục khác nhau, có mở bất kỳ tùy chọn nào khác không? NB: Bởi vì điều quan trọng là phiên bản DLL không gian người dùng này khớp với trình điều khiển hạt nhân đã cài đặt cho phần cứng, DLL không đi kèm với ứng dụng của chúng tôi, nhưng thay vào đó chúng tôi phụ thuộc vào trình cài đặt của nhà cung cấp thư mục trong% PATH%.

+0

Có thể trùng lặp http: // stackoverflow.com/questions/23215518/target-32-bit-hoặc-64-bit-native-dll-tùy-on-môi trường –

+3

Tôi nghĩ rằng sự trùng lặp là cách khác xung quanh, cho câu hỏi này là bốn năm cũ hơn một :) – Cheetah

Trả lời

4

Không có cách nào để có một chữ ký PInvoke duy nhất và nhận được hành vi mà bạn muốn. Thuộc tính được ghi vào siêu dữ liệu và phải có giá trị không đổi. Một hack bạn có thể làm mặc dù là có nhiều phương pháp.

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

Tuy nhiên đây không phải là cách tiếp cận ưa thích. Một cách tiếp cận dễ dàng hơn là làm cho DLL có cùng tên trên nhiều nền tảng và tạo ra một chữ ký PInvoke bất khả tri nền tảng. Đây là cách tiếp cận hầu hết/tất cả các thư viện của windows.

+0

Điều tương tự không hoạt động cho trường hợp của tôi vì 1) Đây là nhà cung cấp bên thứ ba DLL 2) DLL được cài đặt vào thư mục trong hệ thống PATH để ứng dụng có thể tự động tìm thấy chúng (may mắn thay) nhà cung cấp không cài đặt vào% SystemRoot% \ system32 nữa) 3) Trên hệ điều hành 64 bit, cả 32 bit và 64bit DLL cần phải có sẵn # 1 nghĩa là tôi không thể fiddle và # 2 xung đột với # 3 . Tôi đã kết thúc bằng cách sử dụng giải pháp tương tự như những gì bạn đã đề xuất. Tôi đã định nghĩa một giao diện với tất cả các phương thức và sử dụng LinFu để tạo một đối tượng proxy khi chạy mà chuyển tiếp đến các phương thức tĩnh chính xác. – Cheetah

11

"Nếu thay vì tên DLL khác nhau, tên đó giống với tên trong các thư mục khác nhau, có mở bất kỳ tùy chọn nào khác không?"

Có lẽ điều này sẽ làm việc cho bạn:

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

Nó bao gồm trong tải một cách rõ ràng thư viện bản địa với đường dẫn đầy đủ của nó trước khi P/Gọi tự cố gắng để tải nó.

Bạn nghĩ sao?

+0

Nó sẽ hoạt động với Window/MS.NET nhưng còn Mono thì sao? – AndreyAkinshin

+0

không có ý tưởng về Mono, xin vui lòng cho chúng tôi biết những gì bạn tìm ra –

+0

không có gì bây giờ = ( – AndreyAkinshin

1

Tôi đã phát triển một thư viện đặc biệt cho mục tiêu: InteropDotNet. Nó giới thiệu thuộc tính mới RuntimeDllImport với giải quyết đường dẫn thư viện động (trên bay). Theo cách mặc định, bạn có thể viết

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

Và thư viện sẽ được giải quyết tùy thuộc vào môi trường. Ví dụ: đường dẫn cho Win/Linux, x86/x64:

x86/NativeLib.dll 
x86/libNativeLib.so 
x64/NativeLib.dll 
x64/libNativeLib.so 
Các vấn đề liên quan