1. 程式人生 > >C#呼叫C(C++)dll示例教程,包含dll找不到函式入口的解決辦法,包含C#dll呼叫方式不對出錯的解決辦法

C#呼叫C(C++)dll示例教程,包含dll找不到函式入口的解決辦法,包含C#dll呼叫方式不對出錯的解決辦法

本篇文章為了熟悉在C#環境下如何呼叫C(C++)寫的dll。

【轉帖註明出處】

一、首選建立一個C的DLL工程,生產dll檔案用來備用,步驟如下:

1、VS2010建立C++專案內選擇Win32的應用程式,名稱為CreateCDll,在應用程式設定介面內選擇DLL,如下圖:

2、在上圖中在附件選項內選擇【匯出符號】點選完成,便生成了C++的dll工程,如下圖

可以看到選擇了匯出符號的好處是工程自動幫我們建立了CREATECDLL_API的巨集,這個巨集是什麼呢,就是我們要匯出到DLL用的關鍵字可以按F12看CREATECDLL_API的原定義:

// 下列 ifdef 塊是建立使從 DLL 匯出更簡單的
// 巨集的標準方法。此 DLL 中的所有檔案都是用命令列上定義的 CREATECDLL_EXPORTS
// 符號編譯的。在使用此 DLL 的
// 任何其他專案上不應定義此符號。這樣,原始檔中包含此檔案的任何其他專案都會將
// CREATECDLL_API 函式視為是從 DLL 匯入的,而此 DLL 則將用此巨集定義的
// 符號視為是被匯出的。
#ifdef CREATECDLL_EXPORTS
#define CREATECDLL_API __declspec(dllexport)
#else
#define CREATECDLL_API __declspec(dllimport)
#endif

上圖中原始檔內有三個檔案,第一個CreateCDll.cpp就是我們要寫的DLL介面函式原始檔(工程自動幫我們建立了三個範例一個變數一個函式一個類,為了簡單我們可以刪除這三段程式碼),dllmain.cpp類似於dll的main入口,stdafx.cpp就不做介紹了,好了我們開始在CreaeCDll.cpp內新增我們的介面函式,為了測試我們簡單的寫兩個函式,一個是求兩個數的和函式,第二個是比較兩個數的大小,並輸出最大值,好到此原始碼如下:

// CreateCDll.cpp : 定義 DLL 應用程式的匯出函式。
//

#include "stdafx.h"
#include "CreateCDll.h"

// 求和
CREATECDLL_API int fnAdd(int num1,int num2)
{
	return num1 + num2;
}
// 求最大值
CREATECDLL_API int fnMax(int num1,int num2)
{
	return (num1 > num2)?num1:num2;
}
3、OK到此我們兩個介面已經寫好,我們把工程編譯一下,可以看到在工程的Debug目錄下已經生產了DLL和LIB檔案,如下圖:

4、好了第三步我們已經生產了DLL,下面我們要建立C#的工程來呼叫剛生成的DLL,我們建立一個C#視窗應用程式名稱為ImportCDll,儲存,新增如下介面:

5、把剛生成的dll檔案拷貝到C#工程的DEBUG目錄下,然後在C#內完成如下程式碼:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace ImportCDll
{
    public partial class Form1 : Form
    {
        // 匯入求和dll內函式介面
        [DllImport("CreateCDll.dll",EntryPoint="fnAdd")]
        private static extern int fnAdd(int num1, int num2);
        // 匯入求最大值dll內函式介面
        [DllImport("CreateCDll.dll", EntryPoint = "fnMax")]
        private static extern int fnMax(int num1, int num2);

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }

        // 求和按鈕事件
        private void button1_Click(object sender, EventArgs e)
        {
            textBox3.Text = string.Format("{0}",fnAdd(Convert.ToInt32(textBox1.Text),Convert.ToInt32(textBox2.Text)));
        }
        // 求最大值按鈕事件
        private void button2_Click(object sender, EventArgs e)
        {
            textBox4.Text = string.Format("{0}", fnMax(Convert.ToInt32(textBox1.Text), Convert.ToInt32(textBox2.Text)));
        }
    }
}
6、如上程式碼已經完成相應操作參見程式碼內註釋,需要注意的是需要新增:using System.Runtime.InteropServices;引用才能使用dll,好了編譯執行,當我們點選求和或者最大值的時候發現報錯了如下圖:

提示找不到函式入口???怎麼回事很納悶!!!為了確認是否dll內真的沒有我們兩個函式的入口,我們使用PE Explorer來開啟我們的CreateCDll.dll檔案檢視裡面的函式入口名稱,發現如下圖:


可以發現我們函式名字被改變了分別變成了:[email protected]@[email protected](對應fnAdd)和[email protected]@[email protected](對應fnMax),怎麼回事,原來編譯器在編譯的時候會自動的在我們的函式上加上標誌字元,因此我們需要在做dll檔案的時候使用def檔案來告訴編譯器不要改變我們的介面名稱,怎麼做呢?如下。

7、如上的錯誤需要在剛才的C的dll工程內新增def檔案來告訴編譯器不要修改我們的函式介面名稱,在工程上右擊【新增】---->【新建專案】,選擇【模組定義檔案(.def)】,如下圖:

輸入mydef,點選新增,在mydef檔案下新增如下程式碼:

LIBRARY "CreateCDll"
EXPORTS
fnAdd
fnMax
LIBRARY 後面新增你的dll名稱,注意不需要加.dll;在 EXPORTS下面直接新增你的函式名稱,不需要引號見上面程式碼示例。

好了到此我們再把dll的工程編譯一下,然後用PE Explorer看一下編譯好的dll的函式名稱,發現如下:

名稱已經正確好,OK再次拷貝到我們C#工程的debug目錄下,再次編譯,執行。

8、執行重新編譯,再次點選求和或者最大值按鈕,又報錯了…………,報錯介面如下:


經過百度-google了一下,發現在dll呼叫的時候需要把【CallingConvention】的呼叫方式值修改為【CallingConvention.Cdecl】,預設好像是採用【StdCall】的方式;經修改程式碼如下:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace ImportCDll
{
    public partial class Form1 : Form
    {
        // 匯入求和dll內函式介面
        [DllImport("CreateCDll.dll", EntryPoint = "fnAdd", CallingConvention = CallingConvention.Cdecl)]
        private static extern int fnAdd(int num1, int num2);
        // 匯入求最大值dll內函式介面
        [DllImport("CreateCDll.dll", EntryPoint = "fnMax", CallingConvention = CallingConvention.Cdecl)]
        private static extern int fnMax(int num1, int num2);

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }

        // 求和按鈕事件
        private void button1_Click(object sender, EventArgs e)
        {
            textBox3.Text = string.Format("{0}", fnAdd(Convert.ToInt32(textBox1.Text), Convert.ToInt32(textBox2.Text)));
        }
        // 求最大值按鈕事件
        private void button2_Click(object sender, EventArgs e)
        {
            textBox4.Text = string.Format("{0}", fnMax(Convert.ToInt32(textBox1.Text), Convert.ToInt32(textBox2.Text)));
        }
    }
}

9、再次編譯執行,OK了效果如下:


OK,到此結束,希望對新手有幫助。

相關推薦

Java專案讀取配置檔案時FileNotFoundException 系統到指定的檔案System.getProperty("user.dir")的理解

唉,讀取個檔案,也就是在專案裡面去獲得配置檔案的目錄,然後,變成檔案,有事沒事,總是出個 FileNotFoundException  系統找不到指定的檔案,氣死人啦。 還有就是:System.getProperty("user.dir"),都說獲得的是“工作目錄”,有老鐵

C#呼叫C(C++)dll示例教程包含dll函式入口解決辦法包含C#dll呼叫方式不對出錯解決辦法

本篇文章為了熟悉在C#環境下如何呼叫C(C++)寫的dll。 【轉帖註明出處】 一、首選建立一個C的DLL工程,生產dll檔案用來備用,步驟如下: 1、VS2010建立C++專案內選擇Win32的應用程式,名稱為CreateCDll,在應用程式設定介面內選擇DLL,如下圖:

c#中引用Microsoft.SqlServer.Types後系統執行報"未能載入 SqlServerSpatial140.dll到指定的模組(異常來自......)的解決方法

1.在資源管理器中檢視C:\Windows\System32或者C:\Windows\SysWOW64下有沒有SqlServerSpatialXXX.dll的檔案,如果沒有,在網上下載後,把檔案重新命名為報錯的dll檔名,將其放入此目錄下 2.如果有,如下圖,我將原本的130改為140,程式便不

安裝xampp時提示到文件“-n”提示沒有安裝Microsoft Visual C++ 2008 Redistributable Package (x86)

pac sdn .exe tro setup net sof edi microsoft ①安裝xampp時提示找不到文件“-n”; ②提示沒有安裝Microsoft Visual C++ 2008 Redistributable Package (x86)。 解決方法如下

c# 無法載入DLL“xxxx”:到指定的模組(異常來自HRESULT:0X8007007E)的一個解決方法

以前的一個c#專案,今天執行的時候突然發現呼叫DLL時出現了下面的錯誤。 心中很詫異,明明以前能用的,今天怎麼報錯了。程式碼沒有修改,也不存在DLL路徑錯誤的問題。 後來看到有網友說用 depend

python setup.py install 報錯:error: [WinError 3] 系統到指定的路徑。: 'C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\PlatformSDK\\lib

Outline 在通過 setup.py 安裝python模組時,遇到了以下報錯: # 執行 python setup.py install # 報錯: error: [WinError 3] 系統找不到指定的路徑。: 'C:\\Program Files (x86)\\Microsof

vs程式執行時報錯"未能載入 SqlServerSpatialxxx.dll到指定的模組(異常來自......)"的解決方法

報錯原因: 因為程式中引用了Microsoft.SqlServer.Types程式集,正常情況下程式會去c:\windows\system32或者c:\windows\syswow64目錄中尋找,所以找不到。 其實你引用時已經在bin\debug\SqlServerTypes資料夾下生成了報

【小松教你手遊開發】【unity實用技能】u3d 當你發現一個函式呼叫但是完全到是誰呼叫的時候

一般有可能是通過函式名作為字串呼叫,但是這種在除錯時也是能跟蹤到 而如果連除錯都跟蹤不到的時候,看看是不是動畫效果。 如果是的話可能是在那個特效中呼叫。 這樣的話除錯也跟蹤不到。 這種時候要找的話要定位到對應的GameObject上,開啟Animation,檢視 長這

[記錄點滴]授人以漁從Tensorflowdll擴充套件到如何排查問題

# [記錄點滴]授人以漁,從Tensorflow找不到dll擴充套件到如何排查問題 [toc] ## 0x00 摘要 本文將通過一個經典的 “tensorflow找不到dll” 問題來入手,給大家一個如何找到缺失dll的辦法,進而再分享一個windows上排查問題的好工具(因為大多開發者在windows

【Python】selenium調用IE11瀏覽器報錯“到元素”NoSuchWindowException: Message:Unable to find element on closed window

conn ont csdn creates logs 註冊 target get 意思 當編寫自動化腳本,定位瀏覽器元素時,報如下錯誤: 代碼: >>> # coding=utf-8 >>> from selenium import w

12306火車票訂票失敗!您的身份信息未經核驗一般人是能訂票的我訂了可是沒成功。。。

ext con efault jsb fill ast edit 技術 post 12306火車票訂票失敗!您的身份信息未經核驗。一般人是不能訂票的,我訂了,可是沒成功。。。 上圖哈,未經核驗能能夠訂票,只是出票失敗了。看來12306不是吃幹飯的

web頁面到資源文件報404但是資源文件存在且路徑沒錯

環境搭建 思維 邏輯 資源 存在 lan 開始 details tails 如題 , 今天遇到這個問題,maven項目導入本地myeclipse,正常跑起來之後,在web端存在部分頁面資源加載不進來。 但是項目資源確實存在,一開始以為是myeclipse開發環境搭建錯誤導

各類無次數限制的免費API接口再也不怕到免費API了

p地址 歸屬地查詢 指數 騰訊 tps developer 馬化騰 soj yun 各類無次數限制的免費API接口整理,主要是聚合數據上和API Store上的一些,還有一些其他的。聚合數據提供30大類,160種以上基礎數據API服務,國內最大的基礎數據API服務,下面就羅

前端經驗之談(在項目中經常使用但是有時候想起來的一些東西待完善想起一個加一個)

經驗之談 letter 節點 ont 前端 val 隱藏元素 utl ade css:   align-items: center; 該樣式配合display: flex;可以使子元素垂直居中   justify-content: center; 該樣式配合display

Linux下Java運行.class文件報錯到或無法加載主類

code 運行 pro jar 更改 class ssp linux lib classpath配置的錯誤,所以找不到.class文件。 原先的etc/profile中的classpath配置 export CLASSPATH=$JAVA_HOME/lib/tools.j

知道這4個隱藏資源網站的人非常少難怪總是到資源

3-0 圖片 搜索 網易雲音樂 分享 qq音樂 需要 ade -c 現在的互聯網是開放的,我們可以通過網絡下載到很多自己需要的東西,但是有些網站因為不夠知名而被忽視,但是裏面的資源還是很不錯的。 今天小編就來跟大家分享幾個隱藏的資源網站: Aio search 國外的一個B

Django admin後臺管理無樣式報錯到靜態檔案

python+django+uwsgi 建立超級使用者進入admin後臺管理時,發現沒有樣式,報錯找不到靜態檔案(報錯如下) Not Found: /static/admin/css/dashboard.css Not Found: /static/admin/css/base.c

在IntelliJ IDEA中註解@Slf4j到log

轉載:https://blog.csdn.net/qq_26346457/article/details/78736373     @Test    public  void test2(){  &nbs

Linux下Java執行.class檔案報錯到或無法載入主類

classpath配置的錯誤,所以找不到.class檔案。 原先的etc/profile中的classpath配置 export CLASSPATH=$JAVA_HOME/lib/tools.jar   更改後的: export CLASSPATH=.:$JAVA_HOME

SQL語句中為什麼where子句能使用列別名而order by卻可以?

當select的表示式很長時,我們經常會用as子句為該表示式指定別名,然而卻發現無法在Where條件中直接使用該別名作為判斷條件.  例如下面的SQL語句:  select id, (c1 + c2) as s from t1 where s > 100  執行會