[轉]在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
版權聲明:本文為博主原創文章,轉載請附上博文鏈接!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM