C#呼叫C++dll方法和注意事項
在實際C#開發專案中,存在如下兩種情況
- C#呼叫第三方庫,而第三方庫是使用C++編寫的;
- 牽涉到專案原始碼保密,C#程式碼容易被反編譯,因此抽取核心演算法部分使用C++編寫
這時候就涉及C#託管程式碼與C++非託管程式碼互相呼叫。
本文介紹C#呼叫C++的方法以及在C#呼叫C++產生問題的排查過程和經驗總結。
下面介紹C#如何靜態和動態呼叫C++庫;
一、C#中靜態呼叫C++動態連結
1. 建立 CppDemo,建立的時候選擇DLL動態庫。
2. 在DllDemo.cpp檔案中新增一個Add函式
extern "C" __declspec(dllexport) int Add(
{
return a+b;
}
3. 編譯生成DllDem.dll提供C#使用.
4. 新建C#工程,選擇控制檯測試程式InteropDemo
5. 在Program.cs中新增引用:using System.Runtime.InteropServices;
6. 在pulic class Program新增如下程式碼:
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace
{
class Program
{
[DllImport("CppDemo.dll", EntryPoint = "Add", ExactSpelling = false, CallingConvention = CallingConvention.Cdecl)]
public static extern int Add(int a, int b); //
static void Main(string[] args)
{
Console.WriteLine(
Console.Read();
}
}
}
C#中匯入C++庫並匯出需要使用的函式,這樣就可以實現C#靜態呼叫C++動態連結庫了。。
二、C# 中動態呼叫C++動態連結
C#除了可以靜態呼叫C++dll以外,通過簡單的封裝也可以實現C++一樣動態載入呼叫dll的功能,只要封裝C++中LoadLibrary, GetProcess, FreeLibrary這幾個函式就可以實現動態呼叫動態連結庫。實現過程如下:
1. 將kernel32中的幾個方法封裝成本地呼叫類LoadLibraryMethod Code
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace InteropDemo
{
public static class LoadLibraryMethod
{
[DllImport("kernel32.dll", EntryPoint = "LoadLibrary")]
public static extern int LoadLibrary(
[MarshalAs(UnmanagedType.LPStr)] string lpLibFileName);
[DllImport("kernel32.dll", EntryPoint = "GetProcAddress")]
public static extern IntPtr GetProcAddress(int hModule,
[MarshalAs(UnmanagedType.LPStr)] string lpProcName);
[DllImport("kernel32.dll", EntryPoint = "FreeLibrary")]
public static extern bool FreeLibrary(int hModule);
}
}
2. 使用LoadLibraryMethod類動態載入C++動態連結庫,獲得函式指標,並且將指標封裝成C#中的委託。原因很簡單,C#中已經不能使用指標了,如下:
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace InteropDemo
{
class Program
{
static void Main(string[] args)
{
//1. 動態載入C++ Dll
int hModule = LoadLibraryMethod.LoadLibrary(@"c:\CppDemo.dll");
if (hModule == 0) return;
//2. 讀取函式指標
IntPtr intPtr = LoadLibraryMethod.GetProcAddress(hModule, "Add");
//3. 將函式指標封裝成委託
Add addFunction = (Add)Marshal.GetDelegateForFunctionPointer(intPtr, typeof(Add));
//4. 測試
Console.WriteLine(addFunction(1, 2));
Console.Read();
}
/// <summary>
/// 函式指標
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
/// <returns></returns>
delegate int Add(int a, int b);
}
}
三、 C#呼叫C++問題排查案例
在實際應用出現一個問題,我們提供一個C++DLL給第三方使用,第三方使用C#呼叫,C#在呼叫C++的時候總是崩潰,解決該問題經歷瞭如下排查過程:
- 使用Windbug進行除錯,由於C#託管呼叫C++導致C++dll庫崩潰堆疊找不到,無法確認崩潰位置。
- 在提供的DLL中的各個匯出函式入口和出口增加日誌,該方案可行,最終執行發現在DLL中回撥函式ResultCallback4C 呼叫前後的日誌有開始沒結束,確定是回撥函式返回時崩潰,由於自己demo呼叫沒有問題,懷疑ResultCallback4C回撥函式內部處理有問題。
- 確定可能是回撥函式有問題後,將回調註釋掉,發現正常,初步斷定是呼叫方回撥內部處理有問題。
- 第三方呼叫為確認呼叫沒問題,將C#中回撥函式處理邏輯全部註釋,發現仍然有問題,排除了第三方回撥內部問題。
- 經過上述排查後仍然未能解決問題,之後整理了下思路和思考了C++ C#的一些性質,懷疑到可能是函式呼叫約定的問題,果斷將呼叫約定由cdeclcall改為stdcall,編譯重新提供給第三方,更新之後發現沒有問題,最終確定第三方在定義回撥函式時候CallingConvention = CallingConvention.stdcall)使用的stdcall,而和我們我們定義的不一致,導致崩潰。
四、 注意事項
1. C#呼叫C++呼叫約定必須一致,當然C++本身也是一樣。
2. C++和c#中對應的資料結構大小一致.
3. c#引用函式的引數型別和c++函式中的引數型別一致。
相關推薦
C#呼叫C++dll方法和注意事項
在實際C#開發專案中,存在如下兩種情況 C#呼叫第三方庫,而第三方庫是使用C++編寫的; 牽涉到專案原始碼保密,C#程式碼容易被反編譯,因此抽取核心演算法部分使用C++編寫 這時候就涉及C#託管程式碼與C++非託管程式碼互相呼叫。 本文介紹C#呼叫C++的方法以及在C#
C++中typename關鍵字的使用方法和注意事項
目錄起因近日,看到這樣一行程式碼:typedef typename __type_traits<T>::has_trivial_destructor trivial_destructor; 雖說已經有多年C++經驗,但上面這短短一行程式碼卻看得我頭皮發麻。看起來它
python2,python3子類呼叫父類初始化函式的方法和注意事項
python2、python3: python子類呼叫父類初始化函式有兩種方式,以下程式碼在python2和python3都能執行: class A(object): def __init__(self, x): self.x = x # 方法
androidStudio JNI開發之c調java的流程和注意事項
接著上一次的java調c,這次我們來看看c調java的具體步驟 接著上篇文章一直到在java檔案中新增native程式碼步驟 加入如下native方法 public native void call
java中介面(interface)及使用方法和注意事項
1、介面:一種把類抽象的更徹底,接口裡只能包含抽象方法的“特殊類”。介面不關心類的內部狀態資料,定義的是一批類所遵守的規範。(它只規定這批類裡必須提供某些方法,提供這些方法就可以滿足實際要求)。 在JAVA程式語言中是一個抽象型別,是抽象方法的集合,介面通常以interface來宣告。一個類通過
Extjs整合struts2的jsonplugin的方法和注意事項
最近在做一個第三方表報監控的系統,要用的很多資料展示的應用,發現用extjs和struts2的jsonplugin的結合解決問題很棒,專案已經上線,現在寫下步驟以便查閱。 步驟1、在專案中新增struts2的庫。如下 步驟2、新增Google的jsonplug
NSBundle(獲取資源路徑方法)的相關使用方法和注意事項
1、[NSBundle mainBundle],資料夾其實是Group,如左側的樹形檔案管理器 Build之後,檔案直接就複製到了根目錄下,於是讀取的方法,應該是這樣: NSString *earth = [[NSBundle mainBundle] pat
金錢草銅錢草怎麼養殖 金錢草的養殖方法和注意事項
金錢草是一種常見的綠色觀葉植物,它也是一種中藥材,而且金錢草還能開出美麗的黃色小花,它既能美化環境,也能止血消腫功能解毒止痛,平時很多人都有養殖金錢草的打算,只是不知道它怎樣才能養好,今天小編就把它養殖方法寫出來告訴大家,並讓大家瞭解養殖錢草時要注意什麼。 金錢草怎麼養殖 金錢草的養殖
PDM匯出sql的方法和注意事項(本人…
PDM生成sql的方法(應用oracle): 工具欄裡的Database--》Database Generation(Ctrl + G) Directory:匯出路徑 File name:匯出名(我寫的是myself.sql) 點選“確定”。 如果報錯:Generation aborted due to
python字串替換方法和注意事項
方法有兩種: last_date = “1/2/3” 目標為"123" 之一:repalce date =last_date.replace('/','') 之二:re p = re.compile("/") date = p.sub('', last_date)
使用neo4j圖資料庫的import工具匯入資料 -方法和注意事項
背景 最近我在嘗試儲存知識圖譜的過程中,接觸到了Neo4j圖資料庫,這裡我摘取了一段Neo4j的簡介: Neo4j是一個高效能的,NOSQL圖形資料庫,它將結構化資料儲存在網路上而不是表中。它是一個嵌入式的、基於磁碟的、具備完全的事務特性的Java持
使用 MPMoviePlayerController 出現的問題、解決方法和注意事項
在SDK3.2及SDK4.x中MPMoviePlayerController有下面這些改動,像實現豎屏播放不再需要使用私有API了。 - In 3.1 and earlier versions, MPMoviePlayerController was full-scre
mysql資料庫從window遷移的linux的方法和注意事項
一般情況下Mysql從window遷移到linux的時候,網上都會有標準的教程如下: 1) 在windows平臺上進入/mysql/bin目錄(假設你的資料庫名字是mydata) 執行mysqldump 命令將你的資料庫匯出,具體命令如下:
elasticsearch中client.transport.sniff的使用方法和注意事項
(1)通過TransportClient這個介面,我們可以不啟動節點就可以和es叢集進行通訊,它需要指定es叢集中其中一臺或多臺機的ip地址和埠,例子如下:Client client = new TransportClient() .addTr
關於C#與Delphi DLL呼叫及回撥問題注意事項
1.Delphi封裝的函式API及定義的函式型別(用於回撥)中引數的修飾關鍵詞盡不使用const 2.Delphi封裝的函式API及定義的函式型別(用於回撥)中引數的修飾關鍵詞使用const,對應C#中申明需帶ref 3.Delphi封裝的函式API及定義的函式型別(用於回
【C++】向量(vector) 基本使用方法及注意事項
介紹: 向量(Vector)是一個封裝了動態大小陣列的順序容器(Sequence Container)。跟任意其它型別容器一樣,它能夠存放各種型別的物件。可以簡單的認為,向量是一個能夠存放任意型別的動態陣列。 特點: 1.順序序列 順序容器中的元素按照嚴格的線性順序排序。可以通過元素
關於 C#呼叫c庫,將C#的byte[]傳入C庫的方法和將C庫的char*向上傳入C#的回撥函式byte[] 的方法
需求 使用C#開發,因某種原因,寫了C庫Dll,使用C#抓圖資料傳入C,將C庫收到的圖片資料向上傳入C#回撥函式。 當前現狀 C#中將byte[]轉換成I
關於 C#呼叫C庫Dll,有回撥函式時,只執行一次回撥函式就直接掛掉 的解決方法
錯誤 直接當機,如下圖: 錯誤原因 回撥函式宣告原因,跟堆疊有關係
C#呼叫C++DLL方法
最近使用海康的某平臺SDK,但是提供的demo沒有C#版本,只有C++的,在轉換過程中遇到很多問題,簡單記錄一下. 目錄 1.引數為基本型別,例如 int,float,char等。 [C++] void fun(int value); v
C#呼叫MySQL資料庫方法1(使用MySql.Data.dll連線)
方法1、 1、檢查nuget包管理器是否為最新程式 vs2015使用nuget包管理器安裝失敗,在使用vs2015安裝一些nuget包的時候,出現了an error occurred while retrieving package for "Newtonsoft.Jso