在C#中调用C语言函数

对于不太了解.Net的人,如果想要了解.Net,我必须给他介绍P/Invoke。P/Invoke是什么呢?简单地说,就是在.Net中调用本地代码(Native code)的一种解决方案。所谓“本地代码”是相对于托管代码(Managed code)来说的。

P/Invoke实在是一个非常棒(awesome)的特性。本来,.Net 这项技术充分印证了托管程序(Managed program)的种种好处,但是它不够“底层”。可是,这又有什么关系呢?我们有P/Invoke!这样,托管代码的优势和调用本地API的需求就无缝地融合在一起了。

我经常在论坛里看到一些新手提的这种问题:“我刚刚学会了C#,觉得它非常棒,很方便。我的问题是:我能用它调用短信猫(SMS Modem)厂商提供的接口API吗?这些接口API可是C++的耶~~”……OK,现在一旦你了解到了P/Invoke,你就可以完全打消这方面的顾虑了。


闲言少叙,来看我们的例子。

我们的例子是:把一个C语言写的函数封装到一个动态链接库里面,然后在一个C#程序中很方便地调用它。

实现这样的一个例子对很多人来说真是意义重大,从此可以不再担心.Net不够“底层”了。


先看我们的C语言函数:

 

[cpp]   view plain copy print ?
  1. int sum(int a, int b)  
  2.  
  3.     return b;  
  4.  

够简单吧。

 


一、为动态链接库暴露出函数接口


现在我们决定把它封装到一个动态链接库里面。为了让它能封装到动态链接库里面,我们给这个函数申明的前面加上这个:

 

[plain]   view plain copy print ?
  1. __declspec(dllexport)  

源代码就变成了这样的:

 

 

[cpp]   view plain copy print ?
  1. __declspec(dllexportint sum(int a, int b)  
  2.  
  3.     return b;  
  4.  

 

二、编译,得到动态链接库


然后,我们利用Visual C++自带的命令行工具cl、link将它封装成动态链接库。假设文件名为Test.c,我们希望得到Test.dll,命令如下:

 

[cpp]   view plain copy print ?
  1. cl /c Test.c    
  2. link /dll Test.obj  

我们也可以用gcc来编译得到Test.dll。命令如下:

 

 

[plain]   view plain copy print ?
  1. gcc -shared -o Test.dll Test.c  

现在我们就得到了Test.dll。

 


注:从Test.c得到Test.dll的办法很多,想详细了解的话请阅读一下两篇小文:

  1. 将C语言源代码编译成动态链接库 http://blog.csdn.net/xinyaping/article/details/7284899
  2. Visual C++ 2010 Express Tips: 用 C 和 C++ 创建动态链接库 http://blog.csdn.net/xinyaping/article/details/7288164


三、在C#中通过P/Invoke调用Test.dll中的sum()方法


P/Invoke很简单。请看下面这段简单的C#代码:

 

[csharp]   view plain copy print ?
  1. // -----------------------------------------------------------------------  
  2. // <copyright file="Program.cs" company="Yaping Xin">  
  3. // P/Invoke example.  
  4. // </copyright>  
  5. // -----------------------------------------------------------------------  
  6.   
  7. namespace Invoke  
  8.  
  9.     using System;  
  10.     using System.Runtime.InteropServices;  
  11.   
  12.     /// <summary>  
  13.     /// .Net P/Invoke example.  
  14.     /// </summary>  
  15.     internal class Program  
  16.      
  17.         /// <summary>  
  18.         /// Entry point of the application.  
  19.         /// </summary>  
  20.         /// <param name="args">Console arguments.</param>  
  21.         internal static void Main(string[] args)  
  22.          
  23.             int result Sum(2, 3);  
  24.             Console.WriteLine("DLL func execute result: {0}"result);  
  25.          
  26.   
  27.         /// <summary>  
  28.         /// Call method int sum(int, int) defined in Test.dll  
  29.         /// </summary>  
  30.         /// <param name="a">parameter a</param>  
  31.         /// <param name="b">parameter b</param>  
  32.         /// <returns>sum of and b</returns>  
  33.         [DllImport("Test.dll"EntryPoint "sum")]  
  34.         private static extern int Sum(int a, int b);  
  35.      
  36.  

上面这段代码够简单吧。除去注释,除去控制台输出,除去七零八碎的部分,剩下的东西就是这个了:

 

 

[csharp]   view plain copy print ?
  1. [DllImport("Test.dll"EntryPoint "sum")]  
  2. private static extern int Sum(int a, int b);  

这个就是大名鼎鼎的P/Invoke。注意在这里我故意用了一个和C语言源代码中不一样的函数名Sum。C语言源代码中的函数名是sum,如果C#也用sum这个函数名,那句DLLImport就可以这样写了:

 

 

[csharp]   view plain copy print ?
  1. [DllImport("Test.dll")]  

 

在这里不过是向您展示一下当C#中的函数名和DLL中的函数名不一致时,可以通过EntryPoint来进行映射(Mapping)。


编译并执行这段C#程序,执行时别忘了把Test.dll拷贝到执行目录中。结果当然是我们所预期的:


例子很简单,意义不简单。微笑


参考文献:

  1. 将C语言源代码编译成动态链接库 http://blog.csdn.net/xinyaping/article/details/7284899
  2. Visual C++ 2010 Express Tips: 用 C 和 C++ 创建动态链接库 http://blog.csdn.net/xinyaping/article/details/7288164
  3. An Introduction to P/Invoke and Marshaling on the Microsoft .NET Compact Frameworkhttp://msdn.microsoft.com/en-us/library/aa446536.aspx
  4. Essential P/Invoke http://www.codeproject.com/Articles/12121/Essential-P-Invoke
  5. .Net可以做什么 http://blog.csdn.net/xinyaping/article/details/6722015

来源:http://blog.csdn.net/xinyaping/article/details/7288325

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值