[科普小短文]在C#中调用C语言函数(静态调用Native DLL,Windows & Microsoft.Net平台)
2012-02-23 20:04
651 查看
本文属于“科普”性质,面向对.Net不了解的读者。
对于不太了解.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语言函数:
够简单吧。
一、为动态链接库暴露出函数接口
现在我们决定把它封装到一个动态链接库里面。为了让它能封装到动态链接库里面,我们给这个函数申明的前面加上这个:
源代码就变成了这样的:
二、编译,得到动态链接库
然后,我们利用Visual C++自带的命令行工具cl、link将它封装成动态链接库。假设文件名为Test.c,我们希望得到Test.dll,命令如下:
我们也可以用gcc来编译得到Test.dll。命令如下:
现在我们就得到了Test.dll。
注:从Test.c得到Test.dll的办法很多,想详细了解的话请阅读一下两篇小文:
将C语言源代码编译成动态链接库 http://blog.csdn.net/xinyaping/article/details/7284899 Visual C++ 2010 Express Tips: 用 C 和 C++ 创建动态链接库 http://blog.csdn.net/xinyaping/article/details/7288164
三、在C#中通过P/Invoke调用Test.dll中的sum()方法
P/Invoke很简单。请看下面这段简单的C#代码:
上面这段代码够简单吧。除去注释,除去控制台输出,除去七零八碎的部分,剩下的东西就是这个了:
这个就是大名鼎鼎的P/Invoke。注意在这里我故意用了一个和C语言源代码中不一样的函数名Sum。C语言源代码中的函数名是sum,如果C#也用sum这个函数名,那句DLLImport就可以这样写了:
在这里不过是向您展示一下当C#中的函数名和DLL中的函数名不一致时,可以通过EntryPoint来进行映射(Mapping)。
编译并执行这段C#程序,执行时别忘了把Test.dll拷贝到执行目录中。结果当然是我们所预期的:
例子很简单,意义不简单。
参考文献:
将C语言源代码编译成动态链接库 http://blog.csdn.net/xinyaping/article/details/7284899 Visual C++ 2010 Express Tips: 用 C 和 C++ 创建动态链接库 http://blog.csdn.net/xinyaping/article/details/7288164 An Introduction to P/Invoke and Marshaling on the Microsoft .NET Compact Frameworkhttp://msdn.microsoft.com/en-us/library/aa446536.aspx
Essential P/Invoke http://www.codeproject.com/Articles/12121/Essential-P-Invoke .Net可以做什么 http://blog.csdn.net/xinyaping/article/details/6722015
对于不太了解.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语言函数:
int sum(int a, int b) { return a + b; }
够简单吧。
一、为动态链接库暴露出函数接口
现在我们决定把它封装到一个动态链接库里面。为了让它能封装到动态链接库里面,我们给这个函数申明的前面加上这个:
__declspec(dllexport)
源代码就变成了这样的:
__declspec(dllexport) int sum(int a, int b) { return a + b; }
二、编译,得到动态链接库
然后,我们利用Visual C++自带的命令行工具cl、link将它封装成动态链接库。假设文件名为Test.c,我们希望得到Test.dll,命令如下:
cl /c Test.c link /dll Test.obj
我们也可以用gcc来编译得到Test.dll。命令如下:
gcc -shared -o Test.dll Test.c
现在我们就得到了Test.dll。
注:从Test.c得到Test.dll的办法很多,想详细了解的话请阅读一下两篇小文:
将C语言源代码编译成动态链接库 http://blog.csdn.net/xinyaping/article/details/7284899 Visual C++ 2010 Express Tips: 用 C 和 C++ 创建动态链接库 http://blog.csdn.net/xinyaping/article/details/7288164
三、在C#中通过P/Invoke调用Test.dll中的sum()方法
P/Invoke很简单。请看下面这段简单的C#代码:
// ----------------------------------------------------------------------- // <copyright file="Program.cs" company="Yaping Xin"> // P/Invoke example. // </copyright> // ----------------------------------------------------------------------- namespace Invoke { using System; using System.Runtime.InteropServices; /// <summary> /// .Net P/Invoke example. /// </summary> internal class Program { /// <summary> /// Entry point of the application. /// </summary> /// <param name="args">Console arguments.</param> internal static void Main(string[] args) { int result = Sum(2, 3); Console.WriteLine("DLL func execute result: {0}", result); } /// <summary> /// Call method int sum(int, int) defined in Test.dll /// </summary> /// <param name="a">parameter a</param> /// <param name="b">parameter b</param> /// <returns>sum of a and b</returns> [DllImport("Test.dll", EntryPoint = "sum")] private static extern int Sum(int a, int b); } }
上面这段代码够简单吧。除去注释,除去控制台输出,除去七零八碎的部分,剩下的东西就是这个了:
[DllImport("Test.dll", EntryPoint = "sum")] private static extern int Sum(int a, int b);
这个就是大名鼎鼎的P/Invoke。注意在这里我故意用了一个和C语言源代码中不一样的函数名Sum。C语言源代码中的函数名是sum,如果C#也用sum这个函数名,那句DLLImport就可以这样写了:
[DllImport("Test.dll")]
在这里不过是向您展示一下当C#中的函数名和DLL中的函数名不一致时,可以通过EntryPoint来进行映射(Mapping)。
编译并执行这段C#程序,执行时别忘了把Test.dll拷贝到执行目录中。结果当然是我们所预期的:
例子很简单,意义不简单。
参考文献:
将C语言源代码编译成动态链接库 http://blog.csdn.net/xinyaping/article/details/7284899 Visual C++ 2010 Express Tips: 用 C 和 C++ 创建动态链接库 http://blog.csdn.net/xinyaping/article/details/7288164 An Introduction to P/Invoke and Marshaling on the Microsoft .NET Compact Frameworkhttp://msdn.microsoft.com/en-us/library/aa446536.aspx
Essential P/Invoke http://www.codeproject.com/Articles/12121/Essential-P-Invoke .Net可以做什么 http://blog.csdn.net/xinyaping/article/details/6722015
相关文章推荐
- [科普小短文]在C#中调用C语言函数(静态调用Native DLL,Linux & Mono平台)
- 在C语言中静态调用Native DLL(Windows平台)
- windows服务的托管资源(C#) 静态调用 非托管资源(Delphi-dll) 开机造成无法进入桌面(一)
- cs0016:未能写入输出文件 "c:"WINDOWS"Microsoft.NET"Framework"v2.0.50727"Temporary ASP.NET Files"root"...."*.dll--“拒绝访问”
- 在ASP 调用 VB.net 编写的dll 出错 提示:Microsoft VBScript 运行时错误 错误 '800a01ad' ActiveX 部件不能创建对象
- cs0016:未能写入输出文件 "c:"WINDOWS"Microsoft.NET"Framework"v2.0.50727"Temporary ASP.NET Files"root"...."*.dll--“拒绝访问”
- 在C语言中动态调用Native DLL(Windows平台)
- Windows平台下使用CodeBlocks+GCC编译器生成动态dll,C#调用报错
- [科普小短文]在C#中调用C语言函数
- 主题:CS0016: 未能写入输出文件“c:\WINDOWS\Microsoft.NET\***.dll”错误处理
- C#托管代码与C++非托管代码互相调用一(C#调用C++代码&.net 代码安全)
- C#锐利体验-第三讲 Microsoft.NET平台基础构造(转)
- Windows平台使用Java调用Windows API或dll
- C#.Net调用非托管的DLL
- MS.NET 平台调用、托管DLL、非托管DLL简介
- C#/C++/CLI运行效率测试之二: Native C++调用Native C++ DLL
- C#静态调用C++Dll导出函数,并在C++Dll中回调C#函数
- 从.NET平台调用Win32 API(C#调用的dll动态链接库)
- ASP.net/C#中如何调用动态链接库DLL
- Delphi程序调用C#.Net编译的DLL并打开窗体(详解)