原文:https://blog.csdn.net/yapingxin/article/details/7288325
對於不太了解.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
---------------------
作者:YapingXin
來源:CSDN
原文:https://blog.csdn.net/yapingxin/article/details/7288325
版權聲明:本文為博主原創文章,轉載請附上博文鏈接!