溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

C# 調(diào)用Dll

發(fā)布時間:2020-07-31 11:39:07 來源:網(wǎng)絡(luò) 閱讀:1754 作者:lijiang514419 欄目:編程語言
net平臺上,調(diào)用dll文件有2種含義
1、調(diào)用托管dll,即你使用。net平臺開發(fā)的dll,屬于托管代碼
2、調(diào)用非托管dll,即傳統(tǒng)的dll,一般是C++,VB,DELPHI等等開發(fā)出來的,屬于非托管代碼。
從你的意思中看出來你現(xiàn)在是調(diào)用托管的dll,方法是 “在解決方案管理器” - “解決方案”(或項目) 中的任意地方, 右鍵“添加引用”,“瀏覽”,選擇你需要調(diào)用的dll文件,確定即可,該dll會自動復(fù)制到bin目錄,打包時也會自動復(fù)制到你發(fā)布的地方。
添加完了引用,現(xiàn)在如何調(diào)用呢?

如果有命名空間則引入命名空間,比如你的y。dll里面,是a命名空間,有一個b類,然后有一個無參數(shù)靜態(tài)方法c
那么調(diào)用方法就是a.b.c(),跟你普通的使用類是一樣的

然后是非托管dll
需要添加dll的名稱,以及方法,也就是你所用到的dll的每個方法都需要添加一次,
[DllImport("msvcrt.dll")]
public static extern int puts(string c);

*******************************************************************************************

C#托管代碼與C++非托管代碼互相調(diào)用一(C#調(diào)用C++代碼&.net 代碼安全)

在最近的項目中,牽涉到項目源代碼保密問題,由于代碼是C#寫的,容易被反編譯,因此決定抽取核心算法部分使用C++編寫,C++到目前為止好像還不能被很好的反編譯,當(dāng)然如果你是反匯編高手的話,也許還是有可能反編譯。這樣一來,就涉及C#托管代碼與C++非托管代碼互相調(diào)用,于是調(diào)查了一些資料,順便與大家分享一下:源代碼下載

一. C# 中靜態(tài)調(diào)用C++動態(tài)鏈接


   1. 建立VC工程CppDemo,建立的時候選擇Win32 Console(dll),選擇Dll。

   2. 在DllDemo.cpp文件中添加這些代碼。

C# 調(diào)用DllC# 調(diào)用DllCode
extern"C" __declspec(dllexport) int Add(int a,int b)
{

return a+b;
}

   3. 編譯工程。

   4. 建立新的C#工程,選擇Console應(yīng)用程序,建立測試程序InteropDemo
   5. 在Program.cs中添加引用:using System.Runtime.InteropServices;

   6. 在pulic class Program添加如下代碼:


C# 調(diào)用DllC# 調(diào)用DllCode
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace InteropDemo
{
class Program
   {
       [DllImport("CppDemo.dll", EntryPoint = "Add", ExactSpelling = false, CallingConvention = CallingConvention.Cdecl)]
publicstaticexternint Add(int a, int b); //DllImport請參照MSDN

staticvoid Main(string[] args)
       {
           Console.WriteLine(Add(1, 2));
           Console.Read();
       }
   }
}

  好了,現(xiàn)在您可以測試Add程序了,是不是可以在C# 中調(diào)用C++動態(tài)鏈接了,當(dāng)然這是靜態(tài)調(diào)用,需要將CppDemo編譯生成的Dll放在DllDemo程序的Bin目錄下

二. C# 中動態(tài)調(diào)用C++動態(tài)鏈接

在第一節(jié)中,講了靜態(tài)調(diào)用C++動態(tài)鏈接,由于Dll路徑的限制,使用的不是很方便,C#中我們經(jīng)常通過配置動態(tài)的調(diào)用托管Dll,例如常用的一些設(shè)計模式:Abstract Factory, Provider, Strategy模式等等,那么是不是也可以這樣動態(tài)調(diào)用C++動態(tài)鏈接呢?只要您還記得在C++中,通過LoadLibrary, GetProcess, FreeLibrary這幾個函數(shù)是可以動態(tài)調(diào)用動態(tài)鏈接的(它們包含在kernel32.dll中),那么問題迎刃而解了,下面我們一步一步實驗

   1.   將kernel32中的幾個方法封裝成本地調(diào)用類NativeMethod

C# 調(diào)用DllC# 調(diào)用DllCode
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace InteropDemo
{
publicstaticclass NativeMethod
   {
       [DllImport("kernel32.dll", EntryPoint = "LoadLibrary")]
publicstaticexternint LoadLibrary(
           [MarshalAs(UnmanagedType.LPStr)] string lpLibFileName);

       [DllImport("kernel32.dll", EntryPoint = "GetProcAddress")]
publicstaticextern IntPtr GetProcAddress(int hModule,
           [MarshalAs(UnmanagedType.LPStr)] string lpProcName);

       [DllImport("kernel32.dll", EntryPoint = "FreeLibrary")]
publicstaticexternbool FreeLibrary(int hModule);
   }
}


   2. 使用NativeMethod類動態(tài)讀取C++Dll,獲得函數(shù)指針,并且將指針封裝成C#中的委托。原因很簡單,C#中已經(jīng)不能使用指針了,如下          
           int hModule = NativeMethod.LoadLibrary(@"c:"CppDemo.dll");

           IntPtr intPtr = NativeMethod.GetProcAddress(hModule, "Add");

詳細(xì)請參見代碼

C# 調(diào)用DllC# 調(diào)用DllCode
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace InteropDemo
{
class Program
   {
//[DllImport("CppDemo.dll", EntryPoint = "Add", ExactSpelling = false, CallingConvention = CallingConvention.Cdecl)]
//public static extern int Add(int a, int b); //DllImport請參照MSDN


staticvoid Main(string[] args)
       {
//1. 動態(tài)加載C++ Dll
int hModule = NativeMethod.LoadLibrary(@"c:\CppDemo.dll");
if (hModule == 0) return;

//2. 讀取函數(shù)指針
           IntPtr intPtr = NativeMethod.GetProcAddress(hModule, "Add");

//3. 將函數(shù)指針封裝成委托
           Add addFunction = (Add)Marshal.GetDelegateForFunctionPointer(intPtr, typeof(Add));

//4. 測試
           Console.WriteLine(addFunction(1, 2));
           Console.Read();
       }

///<summary>
/// 函數(shù)指針
///</summary>
///<param name="a"></param>
///<param name="b"></param>
///<returns></returns>
delegateint Add(int a, int b);

   }
}

*****************************************************************************************

分別介紹 DllImportAttribute屬性、extern關(guān)鍵字 、IntPtr類型 這三個方面,向大家介紹如何應(yīng)用C#調(diào)用非托管DLL函數(shù)。


C# 如何使用 DllImport Attribute(屬性) 標(biāo)識 DLL 和函數(shù)

System.Runtime.InteropServices.DllImportAttribute

從托管代碼中訪問非托管 DLL 函數(shù)之前,需要知道該函數(shù)的名稱以及該 DLL 的名稱,然后為 DLL 的非托管函數(shù) 編寫 托管定義。

它將用到 static 和 extern 修飾符,此類型的公共靜態(tài)成員對于多線程操作是安全的。

DllImport 屬性提供非托管 DLL 函數(shù)的調(diào)用信息。


示例1  簡單DllImportAttribute 應(yīng)用

using System.Runtime.InteropServices;
[DllImport("user32.dll")]    
publicstaticexternint MessageBox(int hWnd, String text, String caption, uint type);

示例2  如何將 DllImportAttribute 應(yīng)用于方法。

using System.Runtime.InteropServices;
[DllImport(  "KERNEL32.DLL",
            EntryPoint="MoveFileW",
            SetLastError=true,
            CharSet=CharSet.Unicode,
            ExactSpelling=true,
            CallingConvention=CallingConvention.StdCall
         )
]
publicstaticexternbool MoveFile(String src, String dst);

參數(shù)說明:

EntryPoint         指定要調(diào)用的 DLL 入口點。

SetLastError       判斷在執(zhí)行該方法時是否出錯(使用 Marshal.GetLastWin32Error API 函數(shù)來確定)。
                  C#中默認(rèn)值為 false。

CharSet            控制名稱及函數(shù)中字符串參數(shù)的編碼方式。默認(rèn)值為 CharSet.Ansi。

ExactSpelling      是否修改入口點以對應(yīng)不同的字符編碼方式。

CallingConvention  指定用于傳遞方法參數(shù)的調(diào)用約定。默認(rèn)值為 WinAPI。
                  該值對應(yīng)于基于32位Intel平臺的 __stdcall。

BestFitMapping     是否啟用最佳映射功能,默認(rèn)為 true。
                  最佳映射功能提供在沒有匹配項時,自動提供匹配的字符。
                  無法映射的字符通常轉(zhuǎn)換為默認(rèn)的“?”。

PreserveSig        托管方法簽名是否轉(zhuǎn)換成返回 HRESULT,默認(rèn)值為 true(不應(yīng)轉(zhuǎn)換簽名)。
                  并且返回值有一個附加的 [out, retval] 參數(shù)的非托管簽名。

ThrowOnUnmappableChar     控制對轉(zhuǎn)換為 ANSI '?' 字符的不可映射的 Unicode 字符引發(fā)異常。


C# 關(guān)鍵字 extern 的使用

public static extern int MyMethod(int x);

外部修飾符 extern 用于指示外部實現(xiàn)方法,常與 DllImport 屬性一起使用(DllImport 屬性提供非托管 DLL 函數(shù)的調(diào)用信息)。

若將 abstract 和 extern 修飾符一起使用來修改同一成員是錯誤的。extern 將方法在 C# 代碼的外部實現(xiàn),而 abstract 意味著在此類中未提供此方法的實現(xiàn)。

因為外部方法聲明不提供具體實現(xiàn),所以沒有方法體;
此方法聲明只是以一個分號結(jié)束,并且在簽名后沒有大括號{ }。

示例3  接收用戶輸入的字符串并顯示在消息框中

程序從 User32.dll 庫導(dǎo)入的 MessageBox 方法。

using System;
using System.Runtime.InteropServices;
class MyClass
{
  [DllImport("User32.dll")]
publicstaticexternint MessageBox(int h, string m, string c, int type);

publicstaticint Main()
  {
string myString;
     Console.Write("Enter your message: ");
     myString = Console.ReadLine();
return MessageBox(0, myString, "My Message Box", 0);
  }
}

運(yùn)行結(jié)果: 輸入"Hello"文本后,屏幕上將彈出一個包含該文本的消息框。
Enter your message: Hello

示例4  調(diào)用DLL進(jìn)行計算

該示例使用兩個文件 CM.cs 和 Cmdll.c 來說明 extern。
C 文件是從 C# 程序中調(diào)用的外部 DLL。

使用 Visual C++ 命令行將 Cmdll.c 編譯為 DLL:
cl /LD /MD Cmdll.c

文件:Cmdll.c

// cmdll.c
// compile with: /LD /MD
int __declspec(dllexport) MyMethod(int i)
{
return i*10;
}


使用命令行編譯 CM.cs:
csc CM.cs
這將創(chuàng)建可執(zhí)行文件 CM.exe。


文件:CM.cs

// cm.cs
using System;
using System.Runtime.InteropServices;
publicclass MyClass
{
  [DllImport("Cmdll.dll")]
publicstaticexternint MyMethod(int x);

publicstaticvoid Main()
  {
     Console.WriteLine("MyMethod() returns {0}.", MyMethod(5));
  }
}

運(yùn)行此程序,MyMethod 將值 5 傳遞到 DLL 文件,該文件將此值乘以 10 返回。
運(yùn)行結(jié)果:MyMethod() returns 50.


IntPtr 類型的說明

對于平臺調(diào)用,應(yīng)讓參數(shù)為 IntPtr 類型,而不是 String 類型。使用 System.Runtime.InteropServices.Marshal 類所提供的方法,可將類型手動轉(zhuǎn)換為字符串并手動將其釋放。

IntPtr 類型被設(shè)計成整數(shù),其大小適用于特定平臺。
                 在 32 位硬件和操作系統(tǒng)中將是 32 位;
                 在 64 位硬件和操作系統(tǒng)中將是 64 位。

IntPtr 類型由支持指針的語言使用,并作為在支持與不支持指針的語言間引用數(shù)據(jù)的一種通用方式。它也可用于保持句柄。例如,IntPtr 的實例廣泛地用在 System.IO.FileStream 類中來保持文件句柄。

IntPtr 類型符合 CLS,而 UIntPtr 類型卻不符合。只有 IntPtr 類型可用在公共語言運(yùn)行庫中。此類型實現(xiàn) ISerializable 接口。

*****************************************************************************************


向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI