1. 程式人生 > >[轉]在C#中呼叫C語言函式(靜態呼叫Native DLL,Windows & Microsoft.Net平臺)

[轉]在C#中呼叫C語言函式(靜態呼叫Native DLL,Windows & Microsoft.Net平臺)

原文: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
版權宣告:本文為博主原創文章,轉載請附上博文連結!