C#调用C++动态链接库中的函数指针与函数指针结构

这几天做项目时,遇到了C#调用C++函数指针的问题,C#调用C++ dll中的函数很简单,函数指针还真没调过,看了几篇文章研究了会儿后把问题搞定了,这里总结一下。

先看两篇文章:

http://jc.nfxxw.com/n/200607/14/n20060714_19510.shtml C#中的函数指针(实在是找不到出处了)

http://dev.csdn.net/article/69/69261.shtm 如何在C#中使用 Win32和其他库(这篇我在msdn上找了半天也没找到!)

函数指针搞C++的人应该都知道,效率高,易用性强,隐蔽代码等。在C++里面调用C++写的dll的函数指针那是在容易不过了。使用C#就稍微麻烦点了!那怎么掉呢?通过上面的第一篇文章我们知道应该使用委托 delegate。如果再高级点,定义一个函数指针结构(有点像linux的内核),也同样可以用C#调用。

猴子提示:委托就和C++中的函数指针一样。

下面我只写出了.h和.cs文件,都是伪代码,大家如果能明白意思,可以很简单的用到自己的项目了。

.h文件

// 获得梦之都网站的ip
//
// pDes  -  梦之都的网址 http://www.dreamdu.com/
// 返回值  -  false 获取失败 true 获取成功
typedef bool (*Dreamdu_PGetIP)(char const* pDes) ; 

// 获得可爱的猴子的名字
//
// pDes  -  可爱的猴子的名字 http://www.dreamdu.com/blog/
// 返回值  -  false 获取失败 true 获取成功
typedef void (*Monkey_PGetName)(char const* pDes) ; 

// 梦之都的函数指针结构
struct Dreamdu_Struct
{
	Dreamdu_PGetIP		Dreamdu_GetIP;
	Monkey_PGetName       	Monkey_GetName;
} ;

// 获取梦之都的函数指针结构的函数指针
// pDreamdu  -  梦之都的函数指针结构数组
typedef void (*Dreamdu_PGetDreamduStruct)(Dreamdu_Struct *pDreamdu) ;

// 获取梦之都函数指针结构的函数 这个就是输出函数啦 哈哈
// pDreamdu  -  函数指针结构数组
extern "C" Dreamdu_DLL_EXT_ void Dreamdu_GetDreamduStruct(Dreamdu_Struct *pDreamdu) ;

.csCS文件

public class Dreamdu
{
	//加载dll
	[DllImport("kernel32.dll")]
	private static extern IntPtr LoadLibrary(string lpFileName); 

	//获得函数指针的地址
	[DllImport("kernel32.dll")]
	private static extern GetDreamduFuns GetDreamduAddress(IntPtr hModule, string lpProcName);

	//释放dll
	[DllImport("kernel32", EntryPoint = "FreeLibrary", SetLastError = true)]
	private static extern bool FreeLibrary(IntPtr hModule);

	private delegate void GetDreamduFuns(IntPtr funs);
	private delegate bool Dreamdu_PGetIP(string name);
	private delegate void Monkey_PGetName(string name);

	//函数指针结构在cs中的声明
	[StructLayout(LayoutKind.Sequential, Pack = 1)]
	private class Dreamdu_Struct
	{
		public Dreamdu_PGetIP GetIP;
		public Monkey_PGetName GetName;
	}

	//装载 Dll
	public static void LoadDll(string lpFileName)
	{
		hModule = LoadLibrary(lpFileName);
		if (hModule == IntPtr.Zero)
		throw (new Exception());
	}

	//获得函数指针
	public static void LoadFun(string lpProcName)
	{
		if (hModule == IntPtr.Zero)
		throw (new Exception(""));
		dreamduStruct = GetProcAddress(hModule, lpProcName);
		if (farProc == null)
		throw (new Exception(""));

		try
		{
			pcon = Marshal.AllocHGlobal(Marshal.SizeOf(func));
			Marshal.StructureToPtr(func, pcon, true);
			dreamduStruct(pcon);
			Marshal.PtrToStructure(pcon, func);
		}
		finally
		{
			Marshal.FreeHGlobal(pcon);
		}
	}

	//卸载 Dll
	public static void UnLoadDll()
	{
		bool ret = FreeLibrary(hModule);
		hModule = IntPtr.Zero;
		dreamduStruct = null;
	}

	public static bool GetIP(string name)
	{
		return func.Dreamdu_PGetIP(name);
	}

	public static void GetName(string name)
	{
		return func.Monkey_PGetName(name);
	}

	private static IntPtr hModule = IntPtr.Zero;
	private static GetDreamduFuns dreamduStruct = null;
	private static FUNDreamduStruct func = new Dreamdu_Struct();
	private static IntPtr pcon = IntPtr.Zero;
}

上面的C#接口就已经封装好了,仔细观察GetDreamduAddress函数kernel32.dll中此函数是返回FARPROC指针的,但是在这里我重新定义了一个委托来获取函数指针。

上面的C#接口就已经封装好了,可以使用下面方式调用。

class DreamduDLL
{
	Dreamdu.LoadDll("Dreamdu.dll");
	Dreamdu.LoadFun("Dreamdu_GetDreamduStruct");
	//获取ip
	bool hasIP = Dreamdu.GetIP("www.dreamdu.com");
	if(hasIP)
	{
		//获取名称
		Dreamdu.GetName("www.dreamdu.com/blog/");
	}
	//使用完了别忘了卸载dll
	Dreamdu.UnLoadDll();
}

您可能感兴趣的内容

作者: 可爱的猴子
原载: 可爱的猴子 的blog
版权所有。转载时必须以链接形式注明作者和原始出处及本声明。

发表评论