书接上回《C# 引用C/C++ DLL的几种方式(windows篇)》 ,本文将继续介绍在linux下通过C#调用c/c++ dll的方法。通过这篇文章,我们将获得一个可以同时在visual studio和linux下编译的c语言文件和一个可以同时在windows和linux下调用c dll的.net工程
源码下载
一、准备 修改CDLL工程文件 1.修改test.h文件,使其能够在linux下被编译成.so文件
test.h 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 #pragma once #ifdef ENV_WINDOWS _declspec(dllexport) int Add (int a, int b) ; #else #ifdef __cplusplus extern "C" {#endif int Add (int a, int b) ; #ifdef __cplusplus } #endif #endif
2.修改VisualStudio中CDLL工程属性,添加ENV_WINDOWS宏定义使之可以继续生成windows下可以被调用的c dll
3.将test.c和test.h复制到linux上,并进行编译,生成cdll.so
1 $ gcc -fPIC -shared test.c -o cdll.so
二、通过libdl.so动态加载dll 介绍 和windows下的kernel32类似,libdl.so是linux提供的一个动态加载/卸载/调用dll方法的工具。 libdl.so提供了以下接口:
方法
介绍
dlopen
打开动态共享目标文件并将其映射到内存中,返回其首地址
dlclose
关闭动态共享文件
dlsym
返回请求的入口点的指针
dlerror
返回NULL或者指向描述最近错误的字符串
使用 向CSharpTest工程中添加DL3.cs文件,并编辑
DL3.cs 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 public class DL3 { [DllImport("libdl.so.2" , EntryPoint = "dlopen" ) ] private static extern IntPtr UnixLoadLibrary (String fileName, int flags ) ; [DllImport("libdl.so.2" , EntryPoint = "dlclose" , CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi) ] private static extern int UnixFreeLibrary (IntPtr handle ) ; [DllImport("libdl.so.2" , EntryPoint = "dlsym" , CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi) ] private static extern IntPtr UnixGetProcAddress (IntPtr handle, String symbol ) ; [DllImport("libdl.so.2" , EntryPoint = "dlerror" , CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi) ] private static extern IntPtr UnixGetLastError () ; [UnmanagedFunctionPointer(CallingConvention.StdCall) ] public delegate int tAdd (int a, int b ) ; public static void TestDllImport () { var ptr = UnixLoadLibrary("./cdll.so" , 2 ); var ptr_Add = UnixGetProcAddress(ptr, "Add" ); tAdd add = (tAdd)Marshal.GetDelegateForFunctionPointer(ptr_Add, typeof (tAdd)); int res2 = add .Invoke(3 , 4 ); Console.WriteLine(res2); UnixFreeLibrary(ptr); } }
修改Program.cs,使之可以兼容linux和windows两种环境,并根据环境调用不同的dll
Program.cs 1 2 3 4 5 6 7 8 9 10 11 static void Main (string [] args ){ if (Environment.OSVersion.Platform == PlatformID.Win32NT) { DL2.TestDllImport(); DL1.TestDllImport(); } if (Environment.OSVersion.Platform == PlatformID.Unix) DL3.TestDllImport(); Console.WriteLine("Hello, World!" ); }
编译Linux下的CSharpTest程序,并将其放到linux环境下运行,查看输出(记得把cdll.so放到可执行文件目录下 )
至此,我们已经实现了这个C#程序同时兼容windows和linux下调用C/C++ DLL方法。
注: 这里我开始写的是’[DllImport(“libdl.so”, EntryPoint = “dlopen”)]’,结果报错”Unhandled exception. System.DllNotFoundException: Unable to load shared library ‘libdl.so’ or one of its dependencies…” 。后来经过尝试,将”libdl.so”改为”libdl.so.2”后成功调用。也许你看到这篇文章的时候需要改成”libdl.so.3”或者”libdl.so.fucklinux”什么的,总之,祝你好运!