动态链接库(Dynamic Link Library 或者 Dynamic-link Library,缩写为 DLL),是window系统的基石。动态链接提供了一种方法,使进程可以调用不属于其可执行代码的函数。函数的可执行代码位于一个 DLL 文件中,该 DLL 包含一个或多个已被编译、链接并与使用它们的进程分开存储的函数。从语言方面来说就是可以在一定程度上使不同的语言之间实现相互调用。本文将实现一个将C语言编译成DLL,供C#调用的例子!
使用环境:vs2012专业版(11.0.50727.1 RTMREL)+ win8.1企业版
1、新建DLL工程
新建项目->win32->win32项目->应用程序设置->Dll
2、新建testDll.h和testDll.cpp文件,源文件后缀名必须为.cpp
testDll.h文件内容
#ifndef Test_Dll
#define Test_Dll
extern "C" _declspec(dllexport) char* testChar(char* str);//测试字符串当参数带入以及返回
extern "C" _declspec(dllexport) int testInt(int a,int b);//测试整形,其余浮点型,双精度类似
#endif
testDll.cpp文件内容
#include "stdafx.h"
#include "testDll.h"
//以上两个头文件不能调换位置,stdafx.h头文件必须放在第一个,否则将会出错
char* testChar(char* str)//测试字符串当参数带入以及返回
{
return str;
}
int testInt(int a,int b)//测试整形,其余浮点型,双精度类似
{
return a + b;
}
3、生成项目的解决方案,在项目的debug目录下可以找到生成的TestDllWin32.dll文件
4、新建C#控制台应用程序
在Program.cs中引入System.Runtime.InteropServices,使用DllImport函数引入Dll文件,再使用extern关键字引入所要使用的函数
注意:必须将生成的TestDllWin32.dll文件放到程序的bin目录下的debug目录中,否则必须使用绝对路径引用Dll文件
Program.cs文件内容
namespace Test
{
class Program
{
[DllImport("TestDllWin32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
extern static IntPtr testChar(byte[] str);
[DllImport("TestDllWin32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
extern static int testInt(int a, int b);
static void Main(string[] args)
{
//使用字符串作为参数传入和接收返回的字符串
string str = "hello world";
IntPtr ch = testChar(Encoding.ASCII.GetBytes(str));
string result = Marshal.PtrToStringAnsi(ch);
Console.WriteLine("testChar:\n" + result);//输出:testChar:hello world
//int,float,double类型的传递
int a = 3;
int b = 4;
int reint = testInt(a, b);
Console.WriteLine("testInt:\n" + reint);//输出:testInt:7
Console.ReadKey();
}
}
}
5、测试结果
------------------------2016.3.12更新-------关于从C#传输中文路径到C里面打开文件的问题-----------------------------
问题:如果从C#传递到C编译而成的DLL中的字符串是一个需要打开的文件的路径名,并且路径名包含中文字符串,那么以上的传递方法将会出现问题,文件无法打开,个人粗浅理解:由于编码格式出错,原因如下图:
注:C语言编译而成的DLL中的CparseXmlFileName方法,只输出传入进去的字符串
传入的字符串:C:\\Users\\TwinklingZ\\Desktop\\ProjectOfTeacher\\minixml解析应用\\Label1.prt
即使使用UTF8的编码(Encoding.UTF8.GetBytes(Filename))也会出错:
解决办法,使用IntPtr类型,代码如下:
class Program
{
const string miniXmlDll = "miniXmlDll.dll";
[DllImport(miniXmlDll, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
extern static IntPtr CparseXmlFileName(IntPtr str);
static void Main(string[] args)
{
string Filename = "C:\\Users\\TwinklingZ\\Desktop\\ProjectOfTeacher\\minixml解析应用\\Label1.prt";
var ptr = Marshal.StringToHGlobalAnsi(Filename);
/*
* 测试文件
*/
IntPtr re = CparseXmlFileName(ptr);
Marshal.FreeHGlobal(ptr);
string refile = Marshal.PtrToStringAnsi(re);
Console.WriteLine("FileName:" + refile);
Console.ReadKey();
}
}
测试结果: