C#程序調(diào)用C++動態(tài)庫(dll文件)遇到的坑及解決
C#程序調(diào)用C++程序DLL遇到的坑
這兩天有一個(gè)需求就是C++寫的程序,給外包公司寫界面,他們用的是C#寫的,所以我得生成C++動態(tài)庫(dll文件)給他們調(diào)用,過程中遇到了很多坑
這里記錄下來給大家參考。
C#調(diào)用c++動態(tài)庫(dll)方法
可以參考:C#調(diào)用C++的dll兩種實(shí)現(xiàn)(托管與非托管)
總結(jié)一下就是先建一個(gè)C++程序,建立的時(shí)候選擇dll類型。(或者右擊項(xiàng)目-屬性-常規(guī)-配置類型里將exe類型修改為dll類型)
然后建立一個(gè)頭文件(test.h),一個(gè)c++文件(test.cpp)
test.h文件聲明一個(gè)函數(shù)
extern "C" __declspec(dllexport) int add(int a, int b);
test.cpp文件寫函數(shù)體,并導(dǎo)入test.h頭文件
#include"test.h" extern "C" __declspec(dllexport) int add(int a, int b){ return a+b; };
然后右擊項(xiàng)目,點(diǎn)擊重新生成
并記錄下生成dll的路徑
然后創(chuàng)建一個(gè)c#程序用DllImport語句導(dǎo)入,路徑是前面dll的路徑
using System; using System.Runtime.InteropServices; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleApplication2 { class Program { //這里注意,一個(gè)函數(shù)導(dǎo)入一次,如果是兩個(gè)函數(shù)就導(dǎo)入兩次,路徑是前面生成的dll路徑 [DllImport(@"D:\CC\Project7_源碼版本_dll\Project7\Project7.dll", EntryPoint = "add")] extern static int add(int a,int b); static void Main(string[] args) { Console.WriteLine(add(2,3)); Console.ReadKey(); } } }
然后在main函數(shù)里進(jìn)行測試,運(yùn)行即可
當(dāng)然,如果真有這么簡單也沒必要發(fā)這篇博客了,你可能會遇到各種各樣的坑,讓你絕望,下面列舉我遇到過的坑。
問題1:報(bào)錯(cuò)System.DllNotFoundException
這個(gè)問題首先要檢查生成的dll和C#運(yùn)行的環(huán)境位數(shù)是不是一致的,要么都是32位,要么都是64位。
如果位數(shù)沒問題,那就一定是你把dll移動到其他地方去了,dll在哪生成的就在哪放在,不要亂移動?。。?!
在Debug目錄下生成就Debug目錄,在Release目錄下生成就Release。DllImport寫對應(yīng)的路徑就行了。
如果還是不行,建議看看其他的博客……反正博主這個(gè)問題沒困擾多久就解決了
問題2:報(bào)錯(cuò)System.BadImageFormatException
這個(gè),是我苦惱了兩天的報(bào)錯(cuò),一直沒辦法解決。最后沒辦法找了我室友c++大神幫忙解決了,就是下面這個(gè)一流軟件架構(gòu)師。
主要問題還是位數(shù)的問題,程序調(diào)用了位數(shù)不一致的庫。
解決方案1:
生成和調(diào)試都用32位的。
解決方案2:
如果你就是想用64位的,那就右擊C#程序-屬性-生成-目標(biāo)平臺改為x64(或者Any CPU,取消勾選首選32位)
就是這個(gè)問題,你覺得自己明明選擇了x64運(yùn)行,可它其實(shí)還是默認(rèn)32位運(yùn)行的。
如果只要調(diào)用加法的測試函數(shù),基本上就只會碰到上面兩個(gè)問題。如果你想調(diào)用自己的程序,你可能會遇到下面這些問題
問題3:參數(shù)有字符串,報(bào)錯(cuò)System.AccessViolationException
廢話不多說,直接上解決方案:
cpp文件參數(shù)類型寫char*,在函數(shù)體里面可以直接把char* 類型賦值給string類型,但是參數(shù)必須是char*類型
extern "C" __declspec(dllexport) int add(char* str);
c#程序參數(shù)寫string
[DllImport(@"D:\\test.dll", EntryPoint = "add")] extern static int add(string str);
還有一種可能會報(bào)錯(cuò)System.AccessViolationException,就是函數(shù)不對應(yīng),我有次是 EntryPoint = "add"這個(gè)忘記改成對應(yīng)的函數(shù)名了,也是報(bào)的這個(gè)錯(cuò),所以仔細(xì)檢查,把函數(shù)名對應(yīng)起來。
問題4:如何返回多個(gè)值
好像有種方法是返回結(jié)構(gòu)體,但我嘗試了一下沒成功就用了另一種辦法,一下就成功了。
那就是,傳地址:
cpp文件參數(shù)類型寫地址int*
extern "C" __declspec(dllexport) int add(int* a,int* b){ a++; b++; return a; };
c#程序參數(shù)寫ref int
[DllImport(@"D:\\test.dll", EntryPoint = "add")] extern static int add(ref int a,ref int b); static void Main(string[] args) { //這里必須先初始化 int a=0; int b=0; Console.WriteLine(add(ref a,ref b)); Console.WriteLine(a); Console.WriteLine(b); Console.ReadKey(); }
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- C#調(diào)用C++dll方法步驟
- C#通過PInvoke調(diào)用c++函數(shù)的備忘錄的實(shí)例詳解
- vs2019 實(shí)現(xiàn)C#調(diào)用c++的dll兩種方法
- 關(guān)于C#調(diào)用C++dll傳指針釋放內(nèi)存問題
- C#調(diào)用C++動態(tài)庫接口函數(shù)和回調(diào)函數(shù)方法
- c#調(diào)用c++的DLL的實(shí)現(xiàn)方法
- C#調(diào)用C++的dll兩種實(shí)現(xiàn)方式(托管與非托管)
- 在C#項(xiàng)目中調(diào)用C++編寫的動態(tài)庫的三種方式
- C#調(diào)用C++使用C++/CLI的實(shí)現(xiàn)
相關(guān)文章
C# 使用動態(tài)庫DllImport("kernel32")讀寫ini文件的步驟
kernel32.dll是Windows中非常重要的32位動態(tài)鏈接庫文件,屬于內(nèi)核級文件,這篇文章主要介紹了C# 利用動態(tài)庫DllImport("kernel32")讀寫ini文件,需要的朋友可以參考下2023-05-05Unity通過UGUI的Slider調(diào)整物體顏色
這篇文章主要為大家詳細(xì)介紹了Unity通過UGUI的Slider調(diào)整物體顏色,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-02-02C#獲取Windows進(jìn)程監(jiān)聽的TCP/UDP端口實(shí)例
本文介紹了C#獲取Windows下某進(jìn)程監(jiān)聽的TCP/UDP端口的方法,希望對您有所幫助。2013-11-11c#動態(tài)類型,及動態(tài)對象的創(chuàng)建,合并2個(gè)對象,map實(shí)例
下面小編就為大家?guī)硪黄猚#動態(tài)類型,及動態(tài)對象的創(chuàng)建,合并2個(gè)對象,map實(shí)例。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-02-02C#開發(fā)Windows服務(wù)實(shí)例之實(shí)現(xiàn)禁止QQ運(yùn)行
這篇文章主要介紹了通過C#開發(fā)Windows服務(wù),查殺qq進(jìn)程的服務(wù)功能,需要的朋友可以參考下2013-10-10C#實(shí)現(xiàn)的SN快速輸入工具實(shí)例
這篇文章主要介紹了C#實(shí)現(xiàn)的SN快速輸入工具,以實(shí)例的形式詳細(xì)講述了C#實(shí)現(xiàn)序列號快速輸入的方法,是非常實(shí)用的技巧,需要的朋友可以參考下2014-11-11C#使用Tesseract進(jìn)行Ocr識別的方法實(shí)現(xiàn)
本文主要介紹了C#使用Tesseract進(jìn)行Ocr識別的方法實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-06-06