在工作上我常常會遇到軟硬體整合的專案,由於大部分的硬體設備都是使用C/C++撰寫控制程式,也因此每次跟設備廠商要SDK的時候都會得到包含一個.h及一個.lib的資料檔案,有時候會有.DLL,如果設備商在編譯.DLL時有開啟”Common Language Runtime 支援 (/clr)”,那你就可以輕鬆的在使用C#來呼叫他們的方法來使用,但若沒支援CLR,你有兩種選擇:
一、使用C/C++來完成你的專案。
二、自己撰寫一支輸出.DLL並支援RLC的C/C++程式,並在程式中呼叫設備商提供的方法。
本文將紀錄以Visual Studio 2017,如何使用C++編譯可以讓C#呼叫的.DLL檔案。
首先要創建一個可編譯出.DLL的專案,我選擇使用”Windows 傳統式精靈”。
專案類型的設定,如下圖。
接著在專案的屬性頁設定”支援CLR”。(”專案名稱”上點擊右鍵選”屬性”)
再來就開始撰寫C++的程式了。
首先是標頭檔的程式碼:
#pragma once class Method { public: Method();//預設的空建構子 int Add(int a, int b);//加法 int Sub(int a, int b);//減法 int Mul(int a, int b);//乘法 float Div(int a, int b);//除法 };
主要方法程式碼:
#include "methodForCSCall.h" Method::Method() { } int Method::Add(int a, int b) { return a + b; } int Method::Sub(int a, int b) { return a - b; } int Method::Mul(int a, int b) { return a * b; } float Method::Div(int a, int b) { return a / b; }
可供別人使用.dll呼叫的程式碼:
#include "methodForCSCall.h" //可以將class的物件宣告在外面變成全域 //Calculate cal; extern "C" __declspec(dllexport) int Addition(int a, int b) { Method met; return met.Add(a, b); } extern "C" __declspec(dllexport) int Subtraction(int a, int b) { Method met; return met.Sub(a, b); } extern "C" __declspec(dllexport) int Multiplication(int a, int b) { Method met; return met.Mul(a, b); } extern "C" __declspec(dllexport) float Division(int a, int b) { Method met; return met.Div(a, b); }
程式部分撰寫及編譯完成後,可以在Debug或Release資料夾下,找到編譯出來的.dll檔以及.lib檔;要呼叫.dll檔時,必須要這兩個檔案存在同一個資料夾下才可以呼叫使用。
※注意一:如果今天此.dll程式中有呼叫到其他.h及.lib的方法,也必須把它們都放置在同一個資料夾下,才可以正常使用此動態連結程式庫。
※注意二:這點不只適用於.dll的輸出,程式輸出如果在自己電腦執行,以Debug輸出即可,若是要輸出給其他電腦執行,務必以Release輸出,這點很重要,我就因為這個問題撞牆撞很久。
接下來是關於C#如何呼叫.dll檔,此處以Windows Form建置專案。
下圖為程式介面對應元件屬性名稱。
C#呼叫.dll方法的程式碼:
using System; using System.Runtime.InteropServices; using System.Windows.Forms; namespace CSCallCDllFunc { public partial class J : Form { public J() { InitializeComponent(); } //設置進入點 EntryPoint = "DLL中的函數名稱" [DllImport("methodDllForCSCall.dll", EntryPoint = "Addition")] private static extern int add(int a, int b); //也可以不設置進入點,但函數名稱必須與DLL相同 [DllImport("methodDllForCSCall.dll")] private static extern int Subtraction(int a, int b); //設置進入點 EntryPoint = "DLL中的函數名稱" [DllImport("methodDllForCSCall.dll", EntryPoint = "Multiplication")] private static extern int Mul(int a, int b); //也可以不設置進入點,但函數名稱必須與DLL相同 [DllImport("methodDllForCSCall.dll")] private static extern float Division(int a, int b); private void bt_Add_Click(object sender, EventArgs e) { tb_result.Text= add(Int32.Parse(tb_D1.Text), Int32.Parse(tb_D2.Text)).ToString(); } private void bt_sub_Click(object sender, EventArgs e) { tb_result.Text = Subtraction(Int32.Parse(tb_D1.Text), Int32.Parse(tb_D2.Text)).ToString(); } private void bt_mul_Click(object sender, EventArgs e) { tb_result.Text = Mul(Int32.Parse(tb_D1.Text), Int32.Parse(tb_D2.Text)).ToString(); } private void bt_div_Click(object sender, EventArgs e) { tb_result.Text = Division(Int32.Parse(tb_D1.Text), Int32.Parse(tb_D2.Text)).ToString(); } } }※注意三:宣告.dll方法時可選擇設定程式進入點,也就是對應的方法名稱;或是不設定直接取相同方法名稱,可依需求自行決定。
C++變數型態對應C#變數型態表可以參考以下網頁列出的資訊。
https://dotblogs.com.tw/merlin/archive/2012/07/17/73424.aspx
好了,以上是小弟個人的關於C++編譯.dll及C#呼叫.dll的程式紀錄,給大家參考,如有誤人子弟之處,還請各位先進給予指教。
如果覺得本篇文章對你有幫助的話,也請別忘記留言給予鼓勵喔。
留言列表