中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

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

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

C# 調用Dll

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

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

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

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

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

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

一. C# 中靜態調用C++動態鏈接


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

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

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

return a+b;
}

   3. 編譯工程。

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

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


C# 調用DllC# 調用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();
       }
   }
}

  好了,現在您可以測試Add程序了,是不是可以在C# 中調用C++動態鏈接了,當然這是靜態調用,需要將CppDemo編譯生成的Dll放在DllDemo程序的Bin目錄下

二. C# 中動態調用C++動態鏈接

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

   1.   將kernel32中的幾個方法封裝成本地調用類NativeMethod

C# 調用DllC# 調用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類動態讀取C++Dll,獲得函數指針,并且將指針封裝成C#中的委托。原因很簡單,C#中已經不能使用指針了,如下          
           int hModule = NativeMethod.LoadLibrary(@"c:"CppDemo.dll");

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

詳細請參見代碼

C# 調用DllC# 調用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. 動態加載C++ Dll
int hModule = NativeMethod.LoadLibrary(@"c:\CppDemo.dll");
if (hModule == 0) return;

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

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

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

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

   }
}

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

分別介紹 DllImportAttribute屬性、extern關鍵字 、IntPtr類型 這三個方面,向大家介紹如何應用C#調用非托管DLL函數。


C# 如何使用 DllImport Attribute(屬性) 標識 DLL 和函數

System.Runtime.InteropServices.DllImportAttribute

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

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

DllImport 屬性提供非托管 DLL 函數的調用信息。


示例1  簡單DllImportAttribute 應用

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

示例2  如何將 DllImportAttribute 應用于方法。

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);

參數說明:

EntryPoint         指定要調用的 DLL 入口點。

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

CharSet            控制名稱及函數中字符串參數的編碼方式。默認值為 CharSet.Ansi。

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

CallingConvention  指定用于傳遞方法參數的調用約定。默認值為 WinAPI。
                  該值對應于基于32位Intel平臺的 __stdcall。

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

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

ThrowOnUnmappableChar     控制對轉換為 ANSI '?' 字符的不可映射的 Unicode 字符引發異常。


C# 關鍵字 extern 的使用

public static extern int MyMethod(int x);

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

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

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

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

程序從 User32.dll 庫導入的 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);
  }
}

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

示例4  調用DLL進行計算

該示例使用兩個文件 CM.cs 和 Cmdll.c 來說明 extern。
C 文件是從 C# 程序中調用的外部 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
這將創建可執行文件 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));
  }
}

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


IntPtr 類型的說明

對于平臺調用,應讓參數為 IntPtr 類型,而不是 String 類型。使用 System.Runtime.InteropServices.Marshal 類所提供的方法,可將類型手動轉換為字符串并手動將其釋放。

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

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

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

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


向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

衢州市| 衡阳县| 广丰县| 永济市| 邮箱| 山丹县| 广饶县| 鄂托克前旗| 高邑县| 习水县| 寻乌县| 湖州市| 开阳县| 贵州省| 武城县| 华亭县| 临沭县| 年辖:市辖区| 嘉善县| 乐安县| 广河县| 仁化县| 尤溪县| 阿合奇县| 宁国市| 光山县| 金门县| 伊金霍洛旗| 虞城县| 绥中县| 河津市| 恩平市| 遂昌县| 西昌市| 衡东县| 牙克石市| 固原市| 大田县| 横山县| 莆田市| 甘谷县|