2010-09-24 61 views
12

我有兩個版本的System.Data.SQLite.DLL - 適用於x86和x64平臺。 x86版本保留在應用程序文件夾中,x64版本保存在appFolder \ x64文件夾中。 編譯爲AnyCPU的應用程序。 如何根據Windows平臺加載所需的SQLite版本?加載x86或x64程序集

回答

17

如果您正在使用SQLite從http://system.data.sqlite.org,該System.Data.SQLite.DLL完全管理。有一個底層原生DLL,SQLite.Interop.DLL,需要根據進程(32位或64位)進行更改。

我部署在「\本地\ X64" 本地庫爲64位和」 \本地\ X86" 32位。在運行時P/Invoke SetDllDirectory設置DLL加載目錄指向進程的正確路徑。 http://msdn.microsoft.com/en-us/library/ms686203(v=vs.85).aspx

(請注意,我不熟悉的傳統System.Data.SQLite.DLL版本從http://sqlite.phxsoftware.com架構)

private static class NativeMethods 
{ 
    [DllImport("kernel32.dll", CallingConvention = CallingConvention.Cdecl)] 
    internal static extern bool SetDllDirectory(string pathName); 
} 

... 

    // Underlying SQLite libraries are native. 
    // Manually set the DLL load path depending on the process. 
    var path = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Native"); 
    if(IntPtr.Size == 8) // or: if(Environment.Is64BitProcess) // .NET 4.0 
    { 
     path = Path.Combine(path, "X64"); 
    } 
    else 
    { 
     // X32 
     path = Path.Combine(path, "X86"); 
    } 
    NativeMethods.SetDllDirectory(path); 
+3

我已經解決了這個問題。謝謝。我用「IntPtr.Size == 8」。我使用AppDomain.CurrentDomain.AssemblyResolve代替SetDllDirectory。 – Rover 2011-05-20 10:18:27

1

您可以使用Environment.Is64BitProcess來將進程標識爲64位。 (我會盡量避免捕捉異常的流量控制儘可能。)

+0

這是個好主意,但它不能解決我的問題。 – Rover 2010-09-24 13:28:09

+0

@Rover:怎麼樣?你一定有64位.NET安裝? – 2010-09-24 13:42:30

+0

我使用沒有這個變量的.NET 3.5。我想我可以檢查平臺的版本,但它只是避免捕捉一些例外,但需要彙編不加載。 – Rover 2010-09-24 13:55:41

0

你不能只使用SQLite的源作爲一個單獨的項目在您的解決方案,而不是一個預編譯組件?使用AnyCPU系統本身會照顧一切,你不必做的代碼...

+0

這是我在x86和x64上使用的dll之一。我沒有所有使用dll的源代碼。 – Rover 2010-09-24 13:31:25

+0

這並不能解決任何問題,因爲開發機器的架構並不總是與部署機器相同。任何CPU只適用於.NET程序集,而不適用於本機DLL(在引擎蓋下使用SQLITE) – BigBoss 2013-10-05 10:00:21

3

我很驚訝,這在所有工作。它應該首先找到x86版本並且失敗。一個失敗的程序集綁定不會通過AssemblyResolve產生另一個嘗試。

顯然,CLR實際上找不到x86版本,或者在x64模式下也會失敗。換句話說,當你解決這個問題時,你會破壞64位代碼。首先追蹤x86問題,使用Fuslogvw.exe查看該程序集正在探測哪些文件夾。

一個真正的修復應該包括將x86程序集移動到一個單獨的文件夾中,並相應地調整您的事件處理程序。您可以測試IntPtr.Size以確定您是否以64位模式運行(大小== 8)。此外,請確保生成完整的路徑名稱,使用現在使用的相對路徑可能會導致應用程序的工作目錄未設置在希望的位置。 Assembly.GetEntryAssembly()。位置爲您提供EXE的路徑。

+0

我刪除了代碼以避免混淆,只留下問題。 – Rover 2010-09-24 14:16:06

+0

嗯,我不認爲這改變了我的答案。最後一段告訴你如何做對。 – 2010-09-24 14:17:35

+0

好吧,我查了個平臺,找到了需要的程序集。我應該如何將程序集加載到AppDomain中? – Rover 2010-09-24 14:32:58

0
  1. 在GAC中安裝相應的DLL(例如,64位版本在一個64位平臺上)
  2. 在你的web/app配置中使用程序集綁定(可能在機器配置中)
  3. 完全限定你的web/app配置中的任何部分程序集引用。
5

還有就是內置支持這1.0.80.0及更高版本。

如果開發和客戶機器可能有不同的處理器體系結構,可能需要多個二進制包。對於這種情況,強烈建議使用本機庫預加載功能。它從版本1.0.80.0開始可用,並且默認啓用。(from download page)

但是,要獲得它在我自己的工作插件我也有參考SQLite的首次之前,補充一點:

// Make SQLite work... (loading dll from e.g. x64/SQLite.Interop.dll) 
System.Environment.SetEnvironmentVariable("PreLoadSQLite_BaseDirectory", System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location)); 

Sql.Data.SQLite... 

看到這個問題:New SQLite mixed assemblies

11

一些反病毒程序阻止SetDllDirectory() - 花了很長時間才意識到這一點。 我們使用

System.Reflection.Assembly myass = System.Reflection.Assembly.GetExecutingAssembly(); 
FileInfo fi = new FileInfo(myass.Location); 
System.IntPtr moduleHandle = LoadLibraryEx(fi.Directory.FullName + "\\x64\\SQLite.Interop.DLL", IntPtr.Zero, 0); 

加載使用顯式路徑64 DLL。它在那個時候加載,並且.NET運行時將使用內存中的DLL,而不是在其中搜索磁盤。

+5

Upvote for myass' :) – 2015-06-30 11:47:50

+0

在我的情況下沒有工作。即使我已經使用調試器進行了驗證,但是本機庫可以正確加載。 SQLite仍然拋出關於本地DLL丟失的異常。 – BartoszKP 2016-12-13 15:22:20