C#調(diào)用C動(dòng)態(tài)鏈接庫的實(shí)現(xiàn)
前言
已經(jīng)沒寫過博客好久了,上一篇還是1年半前寫的LTE Gold序列學(xué)習(xí)筆記,因?yàn)楣ぷ魇亲鐾ㄐ艆f(xié)議的,然后因?yàn)榇髮W(xué)時(shí)沒好好學(xué)習(xí)專業(yè)課,現(xiàn)在理論還不扎實(shí),不敢瞎寫;
因?yàn)楣ぷ髟颍?jīng)常需要分析一些字節(jié)流數(shù)據(jù),所以基本都是用C寫的,結(jié)果輸出在命令行,或者txt/csv文件;但個(gè)人還是喜歡輸出到GUI界面,可選的手段就MFC、WinForm、PyQt:
MFC的話感覺多少有點(diǎn)過時(shí)了,所以用WinForm,PyQt的多點(diǎn),尤其是WinForm很方便;前段時(shí)間用WinForm寫了個(gè)日志分析工具,因?yàn)楸救耸菢I(yè)余的C#使用者,所以寫的很痛苦,至于數(shù)據(jù)處理的核心思想就CSDN上的結(jié)構(gòu)體字節(jié)流的相互處理,數(shù)據(jù)處理部分大概1000來行;但工作中用的結(jié)構(gòu)體通常很大,涉及大小端轉(zhuǎn)換,同時(shí)還有位域,處理起來很麻煩,用C的話就很方便,所以用C處理數(shù)據(jù)用WinForm、PyQt顯示的方法比較方便;所以就想著用C處理玩數(shù)據(jù)保存到txt/csv文件,然后用C#/Python去調(diào)用C應(yīng)用并讀取文件,但感覺有點(diǎn)low;所以就打算把C部分的處理輸出成dll文件,然后用C#/Python去調(diào)用DLL;當(dāng)然對(duì)我的需求來說,把所有數(shù)據(jù)封裝到1個(gè)結(jié)構(gòu)體里面,每個(gè)結(jié)構(gòu)體字段是Uint或者Uint數(shù)組即可;以下部分實(shí)現(xiàn)就僅僅是能用即可,沒具體設(shè)置;
C語言部分-編譯生成動(dòng)態(tài)鏈接庫
我辦公電腦上是VS2015,自己電腦是VS2017,創(chuàng)建工程有點(diǎn)差異;
VS2015工程設(shè)置使用CSDN上面的截圖,注意源文件后綴用默認(rèn)的cpp,不要用c,我還沒去學(xué)習(xí)這塊的細(xì)節(jié),反正能用就行
VS2017生成控制臺(tái)應(yīng)用程序后,需要將如下紅框中的配置類型修改為動(dòng)態(tài)庫;
然后代碼和C應(yīng)用程序的差異的話就在函數(shù)聲明或定義前加上
extern "C" _declspec(dllexport) int add_test(int x, int y);
不設(shè)置配置和平臺(tái)的話,默認(rèn)輸出就在Debug路徑下生成和項(xiàng)目名一樣的DLL文件,如下圖:
C#部分-使用動(dòng)態(tài)鏈接庫
把編譯生成的DLL文件放到C#編譯輸出的路徑下,不配置的話就在如下路徑:
在C#中調(diào)用C的話,核心代碼就如下2行,
[DllImport("DLLTEST.dll",CallingConvention=CallingConvention.Cdecl)] extern static int add_test(int x, int y);
還有需要注意的點(diǎn),需要包含如下引用,當(dāng)然寫了如上第一行就會(huì)提示讓包含了:
using System.Runtime.InteropServices;
感覺像是函數(shù)外部聲明,能用就行,暫時(shí)沒有去深究原理啥的,輸出如下:
因?yàn)樾枰幚淼臄?shù)據(jù)通常比較多,所以就定義一個(gè)結(jié)構(gòu)體,把需要傳輸?shù)臄?shù)據(jù)全放里面,然后用1個(gè)接口就讀過去了;
簡單做個(gè)測試
- C程序定義一個(gè)結(jié)構(gòu)體,結(jié)構(gòu)體里面僅包含一個(gè)字段,字段是一個(gè)Uint類型的數(shù)組:
typedef struct { unsigned int data[32]; }RetData;
- C程序輸出結(jié)構(gòu)體數(shù)據(jù)測試:
void get_array(RetData* ret) { for (int idx = 0; idx < 32; idx++) { ret->data[idx] = idx * 10; } }
- C#程序也定義一個(gè)結(jié)構(gòu)體,結(jié)構(gòu)體包含一個(gè)字段,字段是Uint32類型的數(shù)組:
struct GetData { [MarshalAs(UnmanagedType.ByValArray,SizeConst =32)] public UInt32[] data; }
C#程序讀入結(jié)構(gòu)體數(shù)據(jù)測試,可能用法很不專業(yè),能讀出來就行
/* 函數(shù)外部聲明 */ [DllImport("DLLTEST.dll", CallingConvention = CallingConvention.Cdecl)] extern static void get_array(ref GetData ret); /* 在Main函數(shù)中調(diào)用 */ GetData getData = new GetData(); get_array(ref getData);
- 輸出
今天下午在公司寫了個(gè)維測工具,整個(gè)流程和上面測試步驟一致,能正常使用
Python部分-使用動(dòng)態(tài)鏈接庫
把編譯生成的DLL文件放到Python文件同級(jí)路徑下,這樣在Python代碼中就直接使用DLL文件名即可,Python測試代碼如下,調(diào)用數(shù)組那塊先前在公司測試正常能用來自,忘了,懶得寫了
import ctypes dll = ctypes.windll.LoadLibrary('DLLTEST.dll') print(dll.add_test(4, 5))
輸出5:如下圖:
本來打算把整個(gè)工程打包放到CSDN來著,但免費(fèi)的話審核不通過,所以就把C/C#部分代碼都貼下面了:
C程序頭文件
#pragma once #ifndef DLL_TEST_H #define DLL_TEST_H typedef struct { unsigned int data[32]; }RetData; extern "C" _declspec(dllexport) int add_test(int x, int y); extern "C" _declspec(dllexport) void get_array(RetData* ret); #endif // !DLL_TEST_H
C程序源文件
#include <stdio.h> #include <stdlib.h> #include "dll_test.h" int add_test(int x, int y) { return x + y; } void get_array(RetData* ret) { for (int idx = 0; idx < 32; idx++) { ret->data[idx] = idx * 10; } }
C#程序
using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; namespace ConsoleApp1 { struct GetData { [MarshalAs(UnmanagedType.ByValArray,SizeConst =32)] public UInt32[] data; } class Program { [DllImport("DLLTEST.dll",CallingConvention=CallingConvention.Cdecl)] extern static int add_test(int x, int y); [DllImport("DLLTEST.dll", CallingConvention = CallingConvention.Cdecl)] extern static void get_array(ref GetData ret); static void Main(string[] args) { Console.WriteLine("{0} + {1} = {2}", 4, 5, add_test(4, 5)); GetData getData = new GetData(); get_array(ref getData); Console.ReadLine(); } } }
到此這篇關(guān)于C#調(diào)用C動(dòng)態(tài)鏈接庫的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)C#調(diào)用C動(dòng)態(tài)鏈接庫內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C#中的Linq Intersect與Except方法使用實(shí)例
這篇文章主要介紹了C#中的Linq Intersect與Except方法使用實(shí)例,本文直接給出示例代碼,需要的朋友可以參考下2015-06-06Unity實(shí)現(xiàn)局域網(wǎng)聊天室功能
這篇文章主要為大家詳細(xì)介紹了Unity實(shí)現(xiàn)局域網(wǎng)聊天室功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-10-10