2008-12-18 80 views
6

我有一個非託管DLL(Scintilla代碼編輯器的scilexer.dll,由CodePlex使用,由Scintilla.Net使用)通過Scintilla.Net組件從託管應用程序加載。在32位和64位環境下,Windows託管應用程序運行沒有問題,但我需要創建使用64或32 scilexer.dll的不同安裝。32位或64位DLL從.net託管代碼加載

有沒有辦法將32位和64位格式的這兩個DLL分發,以便.Net框架的DLL加載程序根據某些.config選項或某些「路徑名稱加載32或64位格式的非託管DLL魔術「的東西?

+0

我會說,大部分時間不打擾 - 除非你希望你的應用程序使用接近2GB的RAM只是讓你的項目目標僅適用於x86,它只會在32位版本的scilexer.dll中運行。 – 2009-11-15 11:07:09

回答

5

P/Invoke使用LoadLibrary加載DLL,如果已經有一個加載了給定名稱的庫,LoadLibrary將返回它。所以,如果你可以給這兩個版本的DLL使用相同的名字,但是把它們放在不同的目錄中,你可以在第一次從scilexer調用函數之前做一次這樣的事情。DLL,而無需複製你的外部聲明:

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 + "."); 
1

你可以把dll放在system32中。 syswow64中的32位和真正的system32中的64位。對於32位應用程序,當訪問system32時,它們被重定向到Syswow64。

您可以在註冊表中創建一個條目。軟件密鑰有一個名爲Wow6432Node的子項,32位應用程序將其視爲軟件密鑰。

這是什麼powershell installer does

2

我想出的最好的是以下幾點:

  • 分發我的應用程序名爲64或32
  • 在主啓動代碼的兩個DLL包括以下內容:
  
    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

非託管dll可以與其管理的對應方一起安裝到GAC中。 This article應該解釋它是如何工作的。

4

不幸的是,我不知道任何關於這個特定的DLL。但是,當您自己進行P/Invoke時,您可以應付一點重複,可以爲每個平臺創建一個代理。

例如,假設您有以下界面,應該由這兩個一個32位或64位DLL中實現:

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

您創建代理:

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

最後讓一個工廠爲你挑選合適的工廠:

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

由於第一次調用DLL時懶惰地加載了DLL,儘管每個平臺都只能加載原生版本,但實際上它仍然有效。有關更詳細的解釋,請參閱this article

+1

小心!我已經對我的應用程序做了完全相同的事情,而且我仍然不時地在32位系統上遇到問題。由於無法控制JIT的工作方式,因此無法確定應用程序不會嘗試在32位系統上加載64位DLL,反之亦然。 – 2009-03-17 03:31:12

+0

我一直在生產中使用這個爲期一年半,迄今爲止它對我來說效果很好。 – SteinNorheim 2010-10-08 19:10:27