2008-12-18 36 views
6

Tôi có một DLL không được quản lý (scilexer.dll của trình soạn thảo mã Scintilla, được sử dụng bởi Scintilla.Net từ CodePlex) được tải từ một ứng dụng được quản lý máng thành phần Scintilla.Net . Các cửa sổ quản lý ứng dụng chạy mà không có vấn đề trên cả hai môi trường 32 và 64 bit, nhưng tôi cần phải tạo cài đặt khác nhau có sử dụng 64 hoặc 32 scilexer.dll.32 hoặc 64 bit DLL tải từ .Net mã được quản lý

Có cách nào để phân phối cả hai tệp DLL ở định dạng 32 và 64 bit sao cho trình tải DLL của khung .Net tải DLL không được quản lý ở định dạng 32 hoặc 64 bit tùy thuộc vào một số tùy chọn .config hoặc một số tên đường dẫn ma thuật "công cụ?

+0

Tôi muốn nói rằng hầu hết thời gian không bận tâm - trừ khi bạn mong đợi ứng dụng của bạn sử dụng gần 2GB RAM chỉ làm cho mục tiêu dự án của bạn chỉ x86, và nó sẽ chạy ở mọi nơi chỉ với phiên bản 32-bit của scilexer.dll. –

Trả lời

5

P/Invoke sử dụng LoadLibrary để tải DLL, và nếu đã có một thư viện được nạp với một tên đã cho, LoadLibrary sẽ trả về nó. Vì vậy, nếu bạn có thể cung cấp cho cả hai phiên bản của DLL cùng tên, nhưng đặt chúng trong các thư mục khác nhau, bạn có thể làm một cái gì đó như thế này chỉ một lần trước khi cuộc gọi đầu tiên của bạn đến một chức năng từ scilexer.dll, mà không cần phải sao chép các khai báo extern của bạn:

string platform = IntPtr.Size == 4 ? "x86" : "x64"; 
    string dll = installDir + @"\lib-" + platform + @"\scilexer.dll"; 
    if (LoadLibrary(dll) == IntPtr.Zero) 
     throw new IOException("Unable to load " + dll + "."); 
+0

Sử dụng phương pháp này, làm việc như một sự quyến rũ. Phản hồi được chấp thuận. – massimogentilini

+0

Bí quyết nhỏ này thật tuyệt vời, rất vui vì bạn đã đăng nó! Trong trường hợp của tôi, tôi đã sử dụng nó để "tải trước" một dll không được quản lý đang nằm trong thư mục bin của dịch vụ web của tôi. –

1

Bạn có thể đặt dll trong system32. 32 bit trong syswow64 và 64 bit trong hệ thống thực32. Đối với ứng dụng 32 bit, khi thay system32 truy cập chúng được chuyển hướng đến Syswow64.

Bạn có thể tạo mục nhập trong sổ đăng ký. Khóa phần mềm có một khóa con có tên Wow6432Node mà ứng dụng 32 bit xem là khóa phần mềm.

Dưới đây là những gì powershell installer does.

2

Điều tốt nhất tôi đã đi lên với như sau:

  • Distribute ứng dụng của tôi với hai DLL tên 64 hoặc 32
  • Trong đoạn mã khởi động chính bao gồm:
  
    File.Delete(Application.StartupPath + @"\scilexer.dll"); 
    { 
     // Check for 64 bit and copy the proper scilexer dll 
     if (IntPtr.Size == 4) 
     { 
      File.Copy(Application.StartupPath + @"\scilexer32.dll", 
      Application.StartupPath + @"\scilexer.dll"); 
     } 
     else 
     { 
      File.Copy(Application.StartupPath + @"\scilexer64.dll", 
      Application.StartupPath + @"\scilexer.dll"); 
     } 
    } 
0

Các tệp không được quản lý có thể được cài đặt vào GAC song song với các đối tác được quản lý của chúng. This article nên giải thích cách hoạt động của nó.

4

Thật không may, tôi không biết gì về DLL cụ thể này. Tuy nhiên, khi bạn thực hiện P/Gọi chính mình và bạn có thể đối phó với một chút trùng lặp, bạn có thể tạo một proxy cho mỗi nền tảng.

Ví dụ, giả sử rằng bạn đã giao diện sau đây, mà cần được thực hiện bởi một trong hai một 32 hoặc 64 bit DLL:

public interface ICodec { 
    int Decode(IntPtr input, IntPtr output, long inputLength); 
} 

Bạn tạo các proxy:

public class CodecX86 : ICodec { 
    private const string dllFileName = @"Codec.x86.dll"; 

    [DllImport(dllFileName)] 
    static extern int decode(IntPtr input, IntPtr output, long inputLength); 

    public int Decode(IntPtr input, IntPtr output, long inputLength) { 
     return decode(input, output, inputLength); 
    } 
} 

public class CodecX64 : ICodec { 
    private const string dllFileName = @"Codec.x64.dll"; 

    [DllImport(dllFileName)] 
    static extern int decode(IntPtr input, IntPtr output, long inputLength); 

    public int Decode(IntPtr input, IntPtr output, long inputLength) { 
     return decode(input, output, inputLength); 
    } 
} 

Và cuối cùng là tạo một nhà máy chọn đúng nhà máy cho bạn:

public class CodecFactory { 
    ICodec instance = null; 

    public ICodec GetCodec() { 
     if (instance == null) { 
      if (IntPtr.Size == 4) { 
       instance = new CodecX86(); 
      } else if (IntPtr.Size == 8) { 
       instance = new CodecX64(); 
      } else { 
       throw new NotSupportedException("Unknown platform"); 
      } 
     } 
     return instance; 
    } 
} 

Khi các tệp DLL được tải lazily lần đầu tiên chúng được gọi, điều này thực sự hoạt động, mặc dù mỗi nền tảng chỉ có thể tải phiên bản gốc. Xem this article để có giải thích chi tiết hơn.

+1

Xem ra! Tôi đã thực hiện chính xác điều tương tự với ứng dụng của mình và tôi vẫn gặp sự cố trên các hệ thống 32 bit theo thời gian. Bởi vì bạn không thể kiểm soát cách JIT hoạt động, bạn không thể chắc chắn ứng dụng của bạn sẽ không thử tải DLL 64 bit trên các hệ thống 32 bit và ngược lại. –

+0

Tôi đã sử dụng điều này trong sản xuất trong một năm rưỡi, và nó đã làm việc tốt cho tôi cho đến nay. – SteinNorheim

Các vấn đề liên quan