第一種是直接添加c++項目引用
第二種是使用DllImport的方式
前兩種可以參考:
https://blog.csdn.net/zxy13826134783/article/details/84190800
第三種是本文需要介紹的,而且使用C#封裝ffmpeg視頻庫的開源庫FFmpeg.AutoGen也是使用下面的方法
本文測試環境:
win7
vistual studio 2012
步驟如下:
一 C++項目端操作
1.1 新建C++類庫項目,名爲Operation,選擇Win32項目,如下圖:
點擊確定,彈出對話框,如下圖:
點擊下一步,接着彈出對話框,選擇DLL,勾選空項目,如下圖:
1.2 新建測試類FunctionOutPut,鼠標右鍵項目,選擇 添加 /類,如下圖:
在FunctionOutPut.cpp中輸入如下代碼,代碼過於簡單,就兩個減法操作的函數,一個帶指針而已,不做解釋:
#include "FunctionOutPut.h"
FunctionOutPut::FunctionOutPut(void)
{
}
FunctionOutPut::~FunctionOutPut(void)
{
}
int sub(int a,int b){
return a-b;
}
int pointer(int &a,int &b){
return a-b;
}
1.3 添加一個名爲FunctionOutput.def模塊定義文件,添加方式如下,鼠標右鍵項目,選擇 添加 / 新建項 後,彈出對話框,如下圖:
並編輯如下:
1.4 生成項目,然後找到Debug(要找仔細咯,與C#的不同,它居然與項目文件同一個目錄)目錄下生成的Operation.dll,需要拷貝到C#的bin/Debug目錄下
二 在同一個解決方案下新建C#的控制檯項目,名爲callDLL
2.1 由於在C#項目中使用指針,需要勾選項目中的 ‘運許不安全代碼’ 選項,鼠標右鍵C#項目,選擇屬性,然後再彈出的對話框中勾選如下:
2.2 在主程序中編輯代碼如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace callDLL
{
class Program
{
//加載dll庫,參數爲dll庫的名稱,返回句柄
[DllImport("kernel32")]
public static extern IntPtr LoadLibrary(string lpFileName);
//通過句柄釋放dll庫
[DllImport("Kernel32")]
public static extern bool FreeLibrary(IntPtr handle);
//根據函數名輸出庫函數,返回函數的指針
[DllImport("Kernel32")]
public static extern IntPtr GetProcAddress(IntPtr handle, String funcname);
//定義c++中sub方法對應的委託
[UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)]
public delegate int CppSub(int a, int b);
//定義c++中pointer方法對應的委託,注意如果帶指針,需要在委託前面加上unsafe關機字
[UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)]
unsafe public delegate int pointer(int *a,int *b);
//因爲Main方法中使用到指針,所以需要在Main方法前加上unsafe關鍵字
unsafe static void Main(string[] args)
{
//加載c++對應的dll庫
IntPtr dll = LoadLibrary("Operation.dll");
//獲取c++對應的庫函數sub
IntPtr func = GetProcAddress(dll, "sub");
//根據庫函數sub獲取委託實例
CppSub sub = (CppSub)Marshal.GetDelegateForFunctionPointer(func, typeof(CppSub));
//委託間接調用sub函數
int res=sub(6, 3);
Console.WriteLine(res);
//獲取c++對應的庫函數pointer
IntPtr func1 = GetProcAddress(dll, "pointer");
//根據庫函數pointer獲取委託pointer實例
pointer p = (pointer)Marshal.GetDelegateForFunctionPointer(func1, typeof(pointer));
int a = 8;
int b=3;
int res1 = p(&a, &b);
Console.WriteLine(res1);
//釋放dll庫
FreeLibrary(dll);
Console.Read();
}
}
}
核心是通過委託來調用c++中對應的函數,同時需要注意的是,凡是涉及到使用指針相關的方法名或者定義委託的前面都要加上unsafe關鍵字,對應這方面的基礎知識參考:https://www.cnblogs.com/lgx5/p/7353346.html
2.3 生成項目,把剛纔生成的Operation.dll拷貝的bin/Debug目錄下,並把項目設置爲啓動項目,然後運行效果圖如下圖:
如果發生錯誤如下:
1 託管調試助手 "PInvokeStackImbalance":的調用導致堆棧不對稱。原因可能是託管的 PInvoke 簽名與非託管的目標籤名不匹配。請檢查 PInvoke 簽名的調用約定和參數與非託管
原因可能是:
你的委託定義的上方沒有加:
[UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)]
2 不能使用非固定表達式中包含的固定大小緩衝區。請嘗試使用 fixed 語句
原因是使用了指針進行賦值,卻沒有使用fixed語句,如下圖分析:
3 嘗試讀取或寫入受保護的內存。這通常指示其他內存已損壞。
這樣的錯誤我折騰了好久也沒解決
Demo源碼下載:http://zxy15914507674.gitee.io/shared_resource_name/Charp和C++間指針操作.rar