close

在工作上我常常會遇到軟硬體整合的專案,由於大部分的硬體設備都是使用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 傳統式精靈”。

開專案.png

專案類型的設定,如下圖。

專案設定.png

接著在專案的屬性頁設定”支援CLR”。(”專案名稱”上點擊右鍵選”屬性”)

CLR設定.PNG

再來就開始撰寫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建置專案。

下圖為程式介面對應元件屬性名稱。

程式介面對應屬性廷稱.png

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的程式紀錄,給大家參考,如有誤人子弟之處,還請各位先進給予指教。

如果覺得本篇文章對你有幫助的話,也請別忘記留言給予鼓勵喔。

arrow
arrow
    創作者介紹
    創作者 zhong.jun.jimmy 的頭像
    zhong.jun.jimmy

    第一次寫程式就不上手

    zhong.jun.jimmy 發表在 痞客邦 留言(0) 人氣()