2012-08-13 175 views
14

可能重複:
preprocessor directive…C#更改C#的DllImport目標代碼取決於的x64/86

我有一個外部c + + DLL使用的DllImport導入。如果我的應用程序在x64中編譯,我需要導入此dll的x64版本,如果它是x86版本,則需要x86 dll。

達到此目的的最佳方法是什麼?理想情況下,我想要一些預處理指令,但我知道這在c#中不起作用嗎?

更多信息:該DLL正在被設置爲AnyCPU的項目導入。父項目是確定應用程序是編譯爲x64還是x86的項目。我們爲不同的客戶編譯兩個版本 - 我想在兩個版本中共享子項目。

+0

如何導入兩種版本(私有方法),但要根據環境暴露給客戶端代碼是正確的?使用.NET 4,只需檢查[Environment.Is64BitOperatingSystem](http://msdn.microsoft.com/zh-cn/。COM/EN-US /庫/ system.environment.is64bitoperatingsystem.aspx)。注意我不會保留兩個不同版本的C#應用​​程序,因爲依賴本地DLL(所以我不會使用預處理器)。 – 2012-08-13 12:54:57

+0

邁克爾 - 這幾乎是我的問題,但我有一個額外的複雜,這意味着他們的解決方案將無法正常工作。我的dll是由anycpu項目導入的,父項目決定應用程序是x64還是x86 – Sugrue 2012-08-13 12:57:11

+0

@Sugrue然後,您將需要使用運行時解決方案,即導入並使用'Environment.Is64BitProcess'或'sizeof (void *)'或者'IntPtr.Size'。 – 2012-08-13 12:58:32

回答

22

這主要是一個部署問題,只需讓您的安裝程序根據目標計算機上的Windows版本複製正確的DLL即可。

但沒有人喜歡這樣做。動態禁止正確的DLL函數非常痛苦,你必須爲每個導出的函數編寫委託類型,並使用LoadLibrary + GetProcAddress + Marshal.GetDelegateForFunctionPointer來創建委託對象。

但沒有人喜歡這樣做。較不痛苦的做法是聲明兩次函數,給它不同的名稱並使用[DllImport]屬性中的EntryPoint屬性指定真實名稱。然後在運行時測試您想要調用的。

但沒有人喜歡這樣做。最有效的技巧是引導Windows爲您加載正確的DLL。你必須做的第一件事是將DLL複製到Windows不會查找它的目錄中。最好的方法是在build目錄中創建一個「x86」和「x64」子目錄,並將相應的DLL複製到每個目錄中。通過編寫一個後期構建事件來創建目錄並複製這些DLL。

然後通過pinvoking SetDllDirectory()告訴Windows它。您指定的路徑將被添加到Windows搜索DLL的目錄中。像這樣:

using System; 
using System.Runtime.InteropServices; 
using System.Reflection; 
using System.IO; 

class Program { 
    static void Main(string[] args) { 
     var path = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); 
     path = Path.Combine(path, IntPtr.Size == 8 ? "x64" : "x86"); 
     bool ok = SetDllDirectory(path); 
     if (!ok) throw new System.ComponentModel.Win32Exception(); 
     //etc.. 
    } 
    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
    private static extern bool SetDllDirectory(string path); 
} 

不要考慮讓代碼在64位模式下運行實際上對您有用。這是非常罕見的,需要從中獲得巨大的虛擬內存地址空間,這是唯一的真正好處。您仍然需要支持需要在2 GB的情況下正常運行的32位版本。

+0

很好的解決方案。 PhonicUK和Michael Graczyk也有很好的解決方案,但是這個不需要重複代碼,我喜歡。 – Sugrue 2012-08-13 14:36:55

+1

個人而言,我更喜歡直接調用'LoadLibrary'來傳遞完整路徑,而不是修改DLL搜索路徑,這對我來說總是讓人感覺笨拙。當然,這個基本想法是一樣的。 – 2014-09-12 10:46:25

+0

第二段涵蓋LoadLibrary。餿主意。 – 2014-09-12 10:48:59

5

使用不同的名稱添加x86和x86_64 DLL導入,然後可以通過檢查Environment.Is64BitProcess(或IntPtr.size,如果您使用的值爲< .Net)的值在運行時根據體系結構有條件地調用它們4)。無論項目是構建爲x86,x86_64還是任何CPU,都可以工作。

或者,設置2個不同的構建配置 - 一個只配置x86,另一個配置只配置x86_64,爲每個構建一個條件編譯符號並使用您自定義符號上的#ifdef。

+0

我認爲OP不知道如何使用'#ifdef'你能爲他提供一個快速的代碼示例,也可能是加載庫的代碼示例嗎?儘管如此,仍然給了+1沒有例子。 – 2012-08-13 13:34:50

+0

'Environment.Is64BitProcess'真的幫我感謝 – LuckyLikey 2015-08-10 08:32:04