第一種方式:C++導出函數, c#dllimport 的方式
在很多地方都看到過,如[dllimport “user32.dll”]這種代碼,調用windows API,就是通過這種方式實現。
例子:新建C++項目,創建動態鏈接庫(DLL),然后添加頭文件textdll.h
#pragma once #ifdef A_EXPORTS #define DLL_API __declspec(dllexport) #else #define DLL_API __declspec(dllimport) #endif extern "C" DLL_API void MessageBoxShow(); //通過extern “C” 使MessageBoxShow方法為一個導出方法,外部可見
然后,dllmain.cpp中添加代碼:
#include "stdafx.h" #include "textdll.h" BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; } #ifdef _MANAGED #pragma managed(push, off) #endif void MessageBoxShow() { MessageBox(NULL, TEXT("Hello World"), TEXT("In a DLL"), MB_OK); } #ifdef _MANAGED #pragma managed(pop) #endif
編譯通過后,找到目錄下生成的DLL(TESTDLL.dll),拷貝出來,放到C#的debug目錄(程序目錄)下, 然后新建C#程序:
using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; //必須要添加該引用 using System.Text; using System.Threading.Tasks; namespace dlltest { class Program { [DllImport("TESTDLL.dll")] //最關鍵的,導入該dll public extern static void MessageBoxShow(); static void Main(string[] args) { MessageBoxShow(); } } }
然后運行可以看到結果:成功的調用了C++DLL中的方法。
第二種方式:
通過C++/CLI作為中間層,因為C++/CLI即可調用.NET的類庫,又可調用C++原生庫,
所以可以通過C# 調用 C++/CLI 再調用 C++ DLL這樣的三層調用方式完成。
1、創建一個c++空項目
項目創建完成,我們添加一個類,寫幾個方法,這兒就簡單寫一個計算器的加減乘除吧!
在CaculateData.h中添加如下代碼,定義幾個函數聲明;
#include <stdio.h> #include <stdlib.h> #include <iostream> #ifdef CaculateDLL_EXPORTS #define Calculate_EXPORTS __declspec(dllexport) #else #define Calculate_EXPORTS __declspec(dllimport) #endif extern "C" Calculate_EXPORTS int Add(int numberA, int numberB); extern "C" Calculate_EXPORTS int Subtract(int numberA, int numberB); extern "C" Calculate_EXPORTS int Multiplication(int numberA, int numberB); extern "C" Calculate_EXPORTS int Divided(int numberA, int numberB); class CaculateData { public: CaculateData(); ~CaculateData(); };
可以看到,#ifdef的宏沒有定義,所以我們需要添加一個宏:
項目右鍵---屬性---配置屬性---C/C++---預處理器---預處理器定義,將定義的宏添加進去;
可以看到,定義好了,顏色就變成紫色的,說明已經聲明了宏;
在CaculateData.cpp中實現這幾個方法;
#include "CaculateData.h" #include <iostream> CaculateData::CaculateData() { } CaculateData::~CaculateData() { } Calculate_EXPORTS int Add(int numberA, int numberB) { return numberA + numberB; } Calculate_EXPORTS int Subtract(int numberA, int numberB) { return numberA - numberB; } Calculate_EXPORTS int Multiplication(int numberA, int numberB) { return numberA * numberB; } Calculate_EXPORTS int Divided(int numberA, int numberB) { if (numberB == 0) { std::cout << "除數不能為空" << std::endl; } return numberA / numberB; }
修改C++工程項目輸出目錄,這兒主要是便於CLI引用,我們這兒同意定義到Testinvoking項目的輸出目錄..\bin\Debug\netcoreapp2.2
(修改步驟:項目右鍵—屬性—配置屬性—常規—輸出目錄)
配置類型修改為:動態庫.dll (修改步驟:項目右鍵—屬性—配置屬性—常規—配置類型)
然后生成;
2、新建一個CLR項目
這個項目就是來實現C#調用C++的
因為需要調用Caculate.dll,所以需要引用它;
配置屬性—VC++目錄—庫目錄(把剛剛生成Caculate.dll的路徑添加進去)
同時引用庫:
添加一個類InvokeCon.cpp,用它來調用Caculate.dll中的方法
InvokeCon.cpp代碼如下:
#include "InvokeCon.h" InvokeCon::InvokeCon() { } int InvokeCon::AddCli(int numberA, int numberB) { return Add(numberA, numberB); } int InvokeCon::SubtractCli(int numberA, int numberB) { return Subtract(numberA, numberB); } int InvokeCon::MultiplicationCli(int numberA, int numberB) { return Multiplication(numberA, numberB); } int InvokeCon::DividedCli(int numberA, int numberB) { return Divided(numberA, numberB); }
InvokeCon.h代碼:
#pragma once #include <iostream> #include "C:\Users\tjy\source\repos\TestInvoking\Caculate\CaculateData.h"//引用庫聲明對應文件路徑 public ref class InvokeCon { public: InvokeCon(); int AddCli(int numberA, int numberB); int SubtractCli(int numberA, int numberB); int MultiplicationCli(int numberA, int numberB); int DividedCli(int numberA, int numberB); };
然后編譯,修改編譯類型為動態庫dll
3、c#通過引用CliDll.dll來調用Caculate中的方法
然后生成:此時就產生了CliDll.dll庫
1、添加對Dll的引用;
2、在C#項目中添加測試代碼:
可以看到,此時就能夠調用多個方法,而且會有方法名提示!
using System; namespace TestInvoking { public class Program { public static void Main(string[] args) { try { Console.WriteLine("---------c#通過CLI調用C++類方法---------"); Console.Write("請輸入numberA:"); int numberA = Convert.ToInt32(Console.ReadLine()); Console.Write("請輸入numberB:"); int numberB = Convert.ToInt32(Console.ReadLine()); InvokeCon invoke = new InvokeCon(); int addResult = invoke.AddCli(numberA, numberB); int subResult = invoke.SubtractCli(numberA, numberB); int mutilResult = invoke.MultiplicationCli(numberA, numberB); int divResult = invoke.DividedCli(numberA, numberB); Console.WriteLine($"the {numberA} And {numberB} sum is:{addResult};sub is:{subResult};Mutil is:{mutilResult};div is:{divResult}"); } catch(Exception ex) { Console.WriteLine($"ex:{ex}"); } Console.WriteLine("執行成功"); Console.ReadLine(); } } }
OK,完成!
代碼已經放到了github,需要的朋友可以去看,就是這篇文章簡單的demo:
github地址:https://github.com/tomorrowGooddays/Invoke