C# : 调用C++动态库(dll)
在實(shí)際軟件開發(fā)過程中,由于公司使用了多種語言開發(fā),在C#中可能需要實(shí)現(xiàn)某個功能,而該功能可能用其他語言已經(jīng)實(shí)現(xiàn)了,那么我們可以調(diào)用其他語言寫好的模塊嗎?還有就是,由于C#開發(fā)好的項(xiàng)目,我們可以利用reflector等反編譯工具反編譯出其源代碼,所以對于一些核心算法,我們不希望被別人知道,因此為了增強(qiáng)代碼的安全性,我們需要將一些核心算法用C或C++來編寫,然后用C#來調(diào)用這些已經(jīng)寫好的接口。在面對以上情況時,我們該怎么做呢?
?方案一:重新實(shí)現(xiàn)
??????? 針對第一種情況,我們可以將C或者C++功能用C#來重新實(shí)現(xiàn),這樣的話代碼比較統(tǒng)一,維護(hù)比較方便,但是這樣的話增加了軟件開發(fā)的成本,把C++的代碼功能改成C#涉及到指針和內(nèi)存的操作比較繁瑣,況且有開發(fā)好的模塊為什么不重復(fù)利用呢?針對第二種情況就不能得到有效解決,雖然可以使用混淆器對代碼進(jìn)行混淆,但是任然不是很安全。
?方案二:封裝COM組件
??????? 我們可以將C或者C++的函數(shù)封裝成COM組件,在C#中調(diào)用時比較方便,但是COM組件需要注冊,而且多次注冊可能也會導(dǎo)致一些問題,同時在處理C或者C++的類型與COM組件的類型轉(zhuǎn)換的時候也可能有些麻煩。
?方案三:使用動態(tài)鏈接庫
??????? 我們可以直接調(diào)用C或者C++已經(jīng)寫好的動態(tài)鏈接庫,這樣比較方便,這樣很好的解決了上述問題。
?
??????? 在實(shí)際項(xiàng)目中,我們需要使用C#調(diào)用C++的一些接口,因此我使用的是方案三采用動態(tài)庫,下面我就在實(shí)際中怎么處理的進(jìn)行說明。
?????? ?在調(diào)用動態(tài)庫的過程中我也遇到了以下一些問題:
????????1、C++中有指針,C#中需要使用指針嗎?
????????由于C++中的動態(tài)庫中有指針參數(shù),因此我也是用.NET的不安全代碼,使用了C#的指針,但是最后也還是出現(xiàn)了一些問題,如在C#中傳入的參數(shù)是一個二維數(shù)組時就出現(xiàn)了問題,這個問題我在網(wǎng)上找了好多資料也沒有解決,最后和c++程序員商量了下改變了傳入?yún)?shù)的參數(shù)類型。最后也沒有使用指針。
????????2、C#和C++中的類型如何轉(zhuǎn)換呢?
??????? 雖然C#和C++比較類似,但是其給我們的參數(shù)類型我們要與C#的參數(shù)類型一一對應(yīng)起來,因此我找了一些資料把其類型一一對應(yīng)了,具體看后續(xù)說明。
????????3、C++寫好的動態(tài)庫放到那個位置呢?
????????關(guān)于C++動態(tài)庫的位置也是個問題,在應(yīng)用中我們使用了相對路徑和絕對路徑進(jìn)行測試,有的發(fā)現(xiàn)在VS中可以調(diào)用到,但是發(fā)布后發(fā)現(xiàn)無法調(diào)用到動態(tài)庫,最后只要把動態(tài)的dll放到系統(tǒng)的目錄system32下面才解決了改問題,目前還沒找到其他的方法,如有其他的更好方法還請大家指點(diǎn)。
????????4、如何反編譯C++的dll的名稱,端口?
??????? 可以通過Dependency Walker工具進(jìn)行反編譯查看別人寫的動態(tài)庫的信息
????????5、還有其他的一些細(xì)節(jié),如C#調(diào)用動態(tài)庫需要指定其編碼、代碼寫法等等
c#調(diào)用c++動態(tài)庫一般我們這樣寫
[DllImport("UCamer.dll", CallingConvention = CallingConvention.Winapi)] public extern static void Disp_Destroy(IntPtr hShow); DllImport的第一個參數(shù)UCamer.dll是動態(tài)庫dll的路徑,此dll放在程序運(yùn)行的根目錄或者c:windows/sytem32下??CallingConvention 參數(shù)是c#調(diào)用c++的方式 是個枚舉 msdn解釋如下
| Cdecl | 調(diào)用方清理堆棧。這使您能夠調(diào)用具有?varargs?的函數(shù)(如?Printf),使之可用于接受可變數(shù)目的參數(shù)的方法。? |
| FastCall | 不支持此調(diào)用約定。 |
| StdCall | 被調(diào)用方清理堆棧。這是使用平臺 invoke 調(diào)用非托管函數(shù)的默認(rèn)約定。? |
| ThisCall | 第一個參數(shù)是?this?指針,它存儲在寄存器 ECX 中。其他參數(shù)被推送到堆棧上。此調(diào)用約定用于對從非托管 DLL 導(dǎo)出的類調(diào)用方法。? |
| Winapi | 此成員實(shí)際上不是調(diào)用約定,而是使用了默認(rèn)平臺調(diào)用約定。例如,在 Windows 上默認(rèn)為?StdCall,在 Windows CE.NET 上默認(rèn)為?Cdecl。? |
?從上面來看Winapi方式是根據(jù)系統(tǒng)自動選擇調(diào)用規(guī)約的。 而thisCall是對c++類的調(diào)用方法。 所以 一般情況下我們選擇Winapi就可以了。
例子:
#region 無標(biāo)題窗體右鍵任務(wù)欄彈出菜單代碼[DllImport("user32.dll", EntryPoint = "GetWindowLong", CharSet = CharSet.Auto)]public static extern int GetWindowLong(HandleRef hWnd, int nIndex);[DllImport("user32.dll", EntryPoint = "SetWindowLong", CharSet = CharSet.Auto)]public static extern IntPtr SetWindowLong(HandleRef hWnd, int nIndex, int dwNewLong);protected override CreateParams CreateParams{get{const int WS_MINIMIZEBOX = 0x00020000; // Winuser.h中定義 CreateParams cp = base.CreateParams;cp.Style = cp.Style | WS_MINIMIZEBOX; // 允許最小化操作 return cp;}}#endregion#region 窗體拖動代碼[DllImport("user32.dll")]public static extern bool ReleaseCapture();[DllImport("user32.dll")]public static extern bool SendMessage(IntPtr hwnd, int wMsg, int wParam, int lParam);public const int WM_SYSCOMMAND = 0x0112;public const int SC_MOVE = 0xF010;public const int HTCAPTION = 0x0002;private void Login_MouseDown(object sender, MouseEventArgs e){ReleaseCapture();SendMessage(this.Handle, WM_SYSCOMMAND, SC_MOVE + HTCAPTION, 0);}#endregion[DllImport("wininet.dll")]private extern static bool InternetGetConnectedState(out int conn, int val);private void btnNetTest_Click(object sender, EventArgs e){int Out;if (InternetGetConnectedState(out Out, 0) == true){MessageDxUtil.ShowTips("Internet網(wǎng)絡(luò)連通!");}else{MessageDxUtil.ShowTips("Internet網(wǎng)絡(luò)不通!");}}?
總結(jié)
以上是生活随笔為你收集整理的C# : 调用C++动态库(dll)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 台式计算机拆机步骤ppt,三相异步电动机
- 下一篇: C#:向C++封送结构体数组