C#調用C(C++)dll樣本教程,包含dll找不到函數入口的解決辦法,包含C#dll調用方式不對出錯的解決辦法__Jquery

來源:互聯網
上載者:User

本篇文章為了熟悉在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檔案查看裡面的函數入口名稱,發現如下圖:


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

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

輸入mydef,點擊添加,在mydef檔案下添加如下代碼:

LIBRARY "CreateCDll"EXPORTSfnAddfnMax
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,到此結束,希望對新手有協助。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.