摘要:本文主要講述如何在c#中逐步實現載入自己用 c++ 語言編寫的動態鏈結庫,以及在匯入時如何進行 c# 和 c++ 語言的資料型別匹配。
一、發生的背景
在開發新專案中使用了新的語言開發 c# 和新的技術方案 web service,但是在新專案中,一些舊的模組需要繼續使用,一般是採用 c 或 c++ 或 delphi 編寫的,如何利用舊模組對於開發人員來說,有三種可用方法供選擇:第
一、將 c 或 c++ 函式用 c# 徹底改寫一遍,這樣整個專案**比較統一,維護也方便一些。但是儘管微軟以及某些書籍說,c# 和 c++ 如何接近,但是改寫起來還是很痛苦的事情,特別是 c++ 裡的指標和記憶體操作;第
二、將 c 或 c++ 函式封裝成 com,在 c# 中呼叫com 比較方便,只是在封裝時需要處理 c 或 c++ 型別和 com 型別之間的轉換,也有一些麻煩,另外com 還需要註冊,註冊次數多了又可能導致混亂;第
三、將 c 或 c++ 函式封裝成動態鏈結庫,封裝的過程簡單,工作量不大。因此我決定採用載入動態鏈結庫的方法實現,於是產生了在 c# 中如何呼叫自定義的動態鏈結庫問題,我在網上搜尋相關主題,發現一篇呼叫系統 api 的文章,但是沒有說明如何解決此問題,在 msdn 上也沒有相關詳細說明。基於此,我決定自己從簡單出發,逐步試驗,看看能否達到自己的目標。
(說明一點:我這裡改寫為什麼很怕麻煩,我改寫的**是變長加密演算法函式,**有600多行,對演算法本身不熟悉,演算法中指標和記憶體操作太多,要想保證演算法正確,最可行的方法就是少動**,否則只要有一點點差錯,就不能肯定演算法與以前相容)
#define libexport_api extern "c" __declspec(dllexport)
第一步,我先從簡單的呼叫出發,定義了乙個簡單的函式,該函式僅僅實現乙個整數加法求和:
libexport_api int mysum(int a,int b)
c# 匯入定義:
public class refcomm
在c#中呼叫測試:
int isum = refcomm.mysum(2,3);
執行檢視結果isum為5,呼叫正確。第一步試驗完成,說明在c#中能夠呼叫自定義的動態鏈結庫函式。
第二步,我定義了字串操作的函式(簡單起見,還是採用前面的函式名),返回結果為字串:
libexport_api char *mysum(char *a,char *b)
c# 匯入定義:
public class refcomm
在c#中呼叫測試:
string strdest="";
string strtmp= refcomm.mysum("12345", strdest);
執行檢視結果 strtmp 為"12345",但是strdest為空。我修改動態鏈結庫實現,返回結果為串b:
libexport_api char *mysum(char *a,char *b)
修改 c# 匯入定義,將串b修改為ref方式:
public class refcomm
在c#中再呼叫測試:
string strdest="";
string strtmp= refcomm.mysum("12345", ref strdest);
執行檢視結果 strtmp 和 strdest 均不對,含不可見字元。再修改 c# 匯入定義,將charset從auto修改為ansi:
public class refcomm
在c#中再呼叫測試:
string strdest="";
string strtmp= refcomm. mysum("12345", ref strdest);
執行檢視結果 strtmp 為"12345",但是串 strdest 沒有賦值。第二步實現函式返回串,但是在函式出口引數中沒能進行輸出。再次修改 c# 匯入定義,將串b修改為引用(ref):
public class refcomm
執行時呼叫失敗,不能繼續執行。
libexport_api char *mysum(char *a,char **b)
c#匯入定義:
public class refcomm
在c#中呼叫測試:
string strdest="";
string strtmp= refcomm. mysum("12345", ref strdest);
執行檢視結果 strtmp 和 strdest 均為"12345",呼叫正確。第三步實現了函式出口引數正確輸出結果。
libexport_api int mysum(int a,int b,int *c)
c#匯入的定義:
public class refcomm
在c#中呼叫測試:
int c=0;
int isum= refcomm. mysum(2,3, ref c);
執行檢視結果isum 和c均為5,呼叫正確。
經過以上幾個步驟的試驗,基本掌握了如何定義動態庫函式以及如何在 c# 定義匯入,有此基礎,很快我實現了變長加密函式在 c# 中的呼叫,至此目標實現。
三、結論
在 c# 中呼叫 c++ 編寫的動態鏈結庫函式,如果需要出口引數輸出,則需要使用指標,對於字串,則需要使用雙重指標,對於 c# 的匯入定義,則需要使用引用(ref)定義。
對於函式返回值,c# 匯入定義和 c++ 動態庫函式宣告定義需要保持一致,否則會出現函式呼叫失敗。定義匯入時,一定注意 charset 和 callingconvention 引數,否則導致呼叫失敗或結果異常。執行時,動態鏈結庫放在 c# 程式的目錄下即可,我這裡是乙個 c# 的動態鏈結庫,兩個動態鏈結庫就在同乙個目錄下執行。
易語言呼叫C 寫的DLL
直接呼叫會彈出堆疊錯誤的資訊,原因是vs預設是 cdcel方式,而易語言是 stdcall,所以呼叫約定不一致導致堆疊錯誤。解決方案很簡單,易語言宣告dll函式時 在庫中對應命令名 函式名前加乙個 符號即可。簡單測試一下 標頭檔案 1 pragma once 2 include 3 4 5 exte...
在C 中呼叫C 寫的DLL
這裡兩個問題,一是如何將c 編譯成dll,二是在c 和c 中呼叫這個dll 1,寫c 的dll,參照以下link,它說的是c 中的dll呼叫,所以肯定成功 2,寫乙個c 呼叫上面寫的dll 2.1將以上的dll拷貝到debug release目錄,然後寫c 程式如下 using system usi...
C 呼叫易語言寫的Dll檔案
分類 c 2011 07 19 22 52 218人閱讀收藏 舉報 本人是用易語言起步的,起初是為了興趣,後來由於易語言被殺軟誤殺嚴重,連空白程式都殺,後來轉到了學c 隨著學習的深入,接觸越來越複雜的東西之後,發現有些功能沒有用易語言來寫方便,所以就想到用c 來呼叫易語言寫的dll,就和一般的dll...