日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > C# >内容正文

C#

【转帖】.Net中C#的DllImport的用法

發(fā)布時間:2024/10/12 C# 124 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【转帖】.Net中C#的DllImport的用法 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
在 C# 中通過 P/Invoke 調(diào)用Win32 DLL?
http://msdn.microsoft.com/zh-cn/library/aa686045.aspx

?

?

大家在實際工作學習C#的時候,可能會問:為什么我們要為一些已經(jīng)存在的功能(比如 Windows中的一些功能,C++中已經(jīng)編寫好的一些方法)要重新編寫代碼,C#有沒有方法可以直接都用這些原本已經(jīng)存在的功能呢?答案是肯定的,大家 可以通過C#中的DllImport直接調(diào)用這些功能。
DllImport所在的名字空間 using System.Runtime.InteropServices;
MSDN中對DllImportAttribute的解釋是這樣的:可將該屬性應用于方法。DllImportAttribute 屬性提供對從非托管 DLL 導出的函數(shù)進行調(diào)用所必需的信息。作為最低要求,必須提供包含入口點的 DLL 的名稱。
DllImport 屬性定義如下:
namespace System.Runtime.InteropServices
{
  [AttributeUsage(AttributeTargets.Method)]
  public class DllImportAttribute: System.Attribute
  {
   public DllImportAttribute(string dllName) {...}
   public CallingConvention CallingConvention;
   public CharSet CharSet;
   public string EntryPoint;
   public bool ExactSpelling;
   public bool PreserveSig;
   public bool SetLastError;
   public string Value { get {...} }
  }
}?
  說明:?
  1、DllImport只能放置在方法聲明上。?
  2、DllImport具有單個定位參數(shù):指定包含被導入方法的 dll 名稱的 dllName 參數(shù)。?
  3、DllImport具有五個命名參數(shù):?
   a、CallingConvention 參數(shù)指示入口點的調(diào)用約定。如果未指定 CallingConvention,則使用默認值 CallingConvention.Winapi。?
   b、CharSet 參數(shù)指示用在入口點中的字符集。如果未指定 CharSet,則使用默認值 CharSet.Auto。?
   c、EntryPoint 參數(shù)給出 dll 中入口點的名稱。如果未指定 EntryPoint,則使用方法本身的名稱。?
   d、ExactSpelling 參數(shù)指示 EntryPoint 是否必須與指示的入口點的拼寫完全匹配。如果未指定 ExactSpelling,則使用默認值 false。?
   e、PreserveSig 參數(shù)指示方法的簽名應當被保留還是被轉(zhuǎn)換。當簽名被轉(zhuǎn)換時,它被轉(zhuǎn)換為一個具有 HRESULT 返回值和該返回值的一個名為 retval 的附加輸出參數(shù)的簽名。如果未指定 PreserveSig,則使用默認值 true。?
   f、SetLastError 參數(shù)指示方法是否保留 Win32"上一錯誤"。如果未指定 SetLastError,則使用默認值 false。?
  4、它是一次性屬性類。?
  5、此外,用 DllImport 屬性修飾的方法必須具有 extern 修飾符。

?

?========================================================

?

??? DllImport是System.Runtime.InteropServices命名空間下的一個屬性類,其功能是提供從非托管DLL導出的函數(shù)的必要調(diào)用信息。
??? DllImport屬性應用于方法,要求最少要提供包含入口點的dll的名稱。
????DllImport的定義如下: [AttributeUsage(AttributeTargets.Method)]
  public class DllImportAttribute: System.Attribute
  {
   public DllImportAttribute(string dllName) {…} //定位參數(shù)為dllName
public CallingConvention CallingConvention; //入口點調(diào)用約定
public CharSet CharSet; //入口點采用的字符接
public string EntryPoint; //入口點名稱
public bool ExactSpelling; //是否必須與指示的入口點拼寫完全一致,默認false
public bool PreserveSig; //方法的簽名是被保留還是被轉(zhuǎn)換
public bool SetLastError; //FindLastError方法的返回值保存在這里
public string Value { get {…} }
  } 用法示例: [DllImport("kernel32")]
private static extern long WritePrivateProfileString(string section,string key,string val,string filePath);

??? 以上是用來寫入ini文件的一個win32api。
????
??? 用此方式調(diào)用Win32API的數(shù)據(jù)類型對應:DWORD=int或uint,BOOL=bool,預定義常量=enum,結(jié)構(gòu)=struct。
?

DllImport會按照順序自動去尋找的地方: 1、exe所在目錄 2、System32目錄 3、環(huán)境變量目錄所以只需要你把引用的DLL 拷貝到這三個目錄下 就可以不用寫路徑了 或者可以這樣server.MapPath(.\bin\*.dll)web中的,同時也是應用程序中的 后來發(fā)現(xiàn)用[DllImport(@"C:\OJ\Bin\Judge.dll")]這樣指定DLL的絕對路徑就可以正常裝載?!∵@個問題最常出現(xiàn)在使用 第三方非托管DLL組件的時候,我的也同樣是這時出的問題,Asp.Net Team的官方解決方案如下: 首先需要確認你引用了哪些組件,那些是托管的,哪些是非托管的.托管的很好辦,直接被使用的需要引用,間接使用的需要拷貝 到bin目錄下.非托管的處理會比較麻煩.實際上,你拷貝到bin沒有任何幫助,因為CLR會把文件拷貝到一個臨時目錄下,然后在那運行web,而CLR 只會拷貝托管文件,這就是為什么我們明明把非托管的dll放在了bin下卻依然提示不能加載模塊了.  具體做法如下:  首先我們在服務器上隨便找個地 方新建一個目錄,假如為C:\DLL  然后,在環(huán)境變量中,給Path變量添加這個目錄  最后,把所有的非托管文件都拷貝到C:\DLL中.  或者 更干脆的把DLL放到system32目錄  對于可以自己部署的應用程序,這樣未償不是一個解決辦法,然而,如果我們用的是虛擬空間,我們是沒辦法把注 冊PATH變量或者把我們自己的DLL拷到system32目錄的。同時我們也不一定知道我們的Dll的物理路徑?! llImport里面只能用字符 串常量,而不能夠用Server.MapPath(@"~/Bin/Judge.dll")來確定物理路徑。ASP.NET中要使用DllImport 的,必須在先“using System.Runtime.InteropServices;”不過,我發(fā)現(xiàn),調(diào)用這種"非托管Dll”相當?shù)穆?#xff0c;可能是因為我的方法需要遠程驗證 吧,但是實在是太慢了。經(jīng)過一翻研究,終于想到了一個完美的解決辦法首先我們用

[DllImport("kernel32.dll")]
private extern static IntPtr LoadLibrary(String path);

[DllImport("kernel32.dll")]
private extern static IntPtr GetProcAddress(IntPtr lib, String funcName);

[DllImport("kernel32.dll")]
private extern static bool FreeLibrary(IntPtr lib);

分別取得了LoadLibrary和GetProcAddress函數(shù)的地址,再通過這兩個函數(shù)來取得我們的DLL里面的函數(shù)。
我們可以先用Server.MapPath(@"~/Bin/Judge.dll")來取得我們的DLL的物理路徑,然后再用LoadLibrary進行載入,最后用GetProcAddress取得要用的函數(shù)地址

以下自定義類的代碼完成LoadLibrary的裝載和函數(shù)調(diào)用:

public class DllInvoke
{
[DllImport("kernel32.dll")]
private extern static IntPtr LoadLibrary(String path);

[DllImport("kernel32.dll")]
private extern static IntPtr GetProcAddress(IntPtr lib, String funcName);

[DllImport("kernel32.dll")]
private extern static bool FreeLibrary(IntPtr lib);

private IntPtr hLib;

public DllInvoke(String DLLPath)
{
hLib = LoadLibrary(DLLPath);
}

~DllInvoke()
{
FreeLibrary(hLib);
}

//將要執(zhí)行的函數(shù)轉(zhuǎn)換為委托
public Delegate Invoke(String APIName,Type t)
{
IntPtr api = GetProcAddress(hLib, APIName);
return (Delegate)Marshal.GetDelegateForFunctionPointer(api,t);
}
}

下面代碼進行調(diào)用

public delegate int Compile(String command, StringBuilder inf);
//編譯
DllInvoke dll = new DllInvoke(Server.MapPath(@"~/Bin/Judge.dll"));
Compile compile = (Compile)dll.Invoke("Compile", typeof(Compile));
StringBuilder inf;
compile(@“gcc a.c -o a.exe“,inf);//這里就是調(diào)用我的DLL里定義的Compile函數(shù)

?

?

?========================================================

DllImport的用法:
DllImport("MyDllImport.dll")]
private static extern int mySum(int a,int b);

一 在C#程序設計中使用Win32類庫
常用對應類型:
1、DWORD 是 4 字節(jié)的整數(shù),因此我們可以使用 int 或 uint 作為 C# 對應類型。
2、bool 類型與 BOOL 對應。

示例一:調(diào)用 Beep() API 來發(fā)出聲音
Beep() 是在 kernel32.lib 中定義的,在MSDN 中的定義,Beep具有以下原型:
BOOL Beep(DWORD dwFreq, // 聲音頻率
DWORD dwDuration // 聲音持續(xù)時間);
用 C# 編寫以下原型:
[DllImport("kernel32.dll")]
public static extern bool Beep(int frequency, int duration);

示例二:枚舉類型和常量
MessageBeep() 是在 user32.lib 中定義的,在MSDN 中的定義,MessageBeep具有以下原型:
BOOL MessageBeep(UINT uType // 聲音類型
);

用C#編寫一下原型:
public enum BeepType
{
  SimpleBeep = -1,
  IconAsterisk = 0x00000040,
  IconExclamation = 0x00000030,
  IconHand = 0x00000010,
  IconQuestion = 0x00000020,
  Ok = 0x00000000,
}
uType 參數(shù)實際上接受一組預先定義的常量,對于 uType 參數(shù),使用 enum 類型是合乎情理的。
[DllImport("user32.dll")]
public static extern bool MessageBeep(BeepType beepType);

示例三:處理結(jié)構(gòu)
有時我需要確定我筆記本的電池狀況。Win32 為此提供了電源管理函數(shù),搜索 MSDN 可以找到GetSystemPowerStatus() 函數(shù)。
BOOL GetSystemPowerStatus(
  LPSYSTEM_POWER_STATUS lpSystemPowerStatus
);
此函數(shù)包含指向某個結(jié)構(gòu)的指針,我們尚未對此進行過處理。要處理結(jié)構(gòu),我們需要用 C# 定義結(jié)構(gòu)。我們從非托管的定義開始:
typedef struct _SYSTEM_POWER_STATUS {
BYTE  ACLineStatus;
BYTE  BatteryFlag;
BYTE  BatteryLifePercent;
BYTE  Reserved1;
DWORD BatteryLifeTime;
DWORD BatteryFullLifeTime;
} SYSTEM_POWER_STATUS, *LPSYSTEM_POWER_STATUS;
   然后,通過用 C# 類型代替 C 類型來得到 C# 版本。
struct SystemPowerStatus
{
  byte ACLineStatus;
  byte batteryFlag;
  byte batteryLifePercent;
  byte reserved1;
  int batteryLifeTime;
  int batteryFullLifeTime;
}
這樣,就可以方便地編寫出 C# 原型:
[DllImport("kernel32.dll")]
public static extern bool GetSystemPowerStatus(
  ref SystemPowerStatus systemPowerStatus);
   在此原型中,我們用“ref”指明將傳遞結(jié)構(gòu)指針而不是結(jié)構(gòu)值。這是處理通過指針傳遞的結(jié)構(gòu)的一般方法。
   此函數(shù)運行良好,但是最好將 ACLineStatus 和 batteryFlag 字段定義為 enum:
  enum ACLineStatus: byte
   {
    Offline = 0,
    Online = 1,
    Unknown = 255,
   }
   enum BatteryFlag: byte
   {
    High = 1,
    Low = 2,
    Critical = 4,
    Charging = 8,
    NoSystemBattery = 128,
    Unknown = 255,
   }
請注意,由于結(jié)構(gòu)的字段是一些字節(jié),因此我們使用 byte 作為該 enum 的基本類型

示例四:處理字符串


二 C# 中調(diào)用C++代碼
int 類型
[DllImport(“MyDLL.dll")]
//返回個int 類型
public static extern int mySum (int a1,int b1);
//DLL中申明
extern “C” __declspec(dllexport) int WINAPI mySum(int a2,int b2)
{
//a2 b2不能改變a1 b1
//a2=..
//b2=...
return a+b;
}

//參數(shù)傳遞int 類型
public static extern int mySum (ref int a1,ref int b1);
//DLL中申明
extern “C” __declspec(dllexport) int WINAPI mySum(int *a2,int *b2)
{
//可以改變 a1, b1
*a2=...
*b2=...
return a+b;
}


DLL 需傳入char *類型
[DllImport(“MyDLL.dll")]
//傳入值
public static extern int mySum (string astr1,string bstr1);
//DLL中申明
extern “C” __declspec(dllexport) int WINAPI mySum(char * astr2,char * bstr2)
{
//改變astr2 bstr 2 ,astr1 bstr1不會被改變
return a+b;
}


DLL 需傳出char *類型
[DllImport(“MyDLL.dll")]
// 傳出值
public static extern int mySum (StringBuilder abuf, StringBuilder bbuf );
//DLL中申明
extern “C” __declspec(dllexport) int WINAPI mySum(char * astr,char * bstr)
{
//傳出char * 改變astr bstr -->abuf, bbuf可以被改變
return a+b;
}

DLL 回調(diào)函數(shù)

BOOL EnumWindows(WNDENUMPROC lpEnumFunc, LPARAM lParam)

using System;
using System.Runtime.InteropServices;
public delegate bool CallBack(int hwnd, int lParam); //定義委托函數(shù)類型
public class EnumReportApp
{
[DllImport("user32")]
public static extern int EnumWindows(CallBack x, int y);
public static void Main() {
CallBack myCallBack = new CallBack(EnumReportApp.Report); EnumWindows(myCallBack, 0);
}
public static bool Report(int hwnd, int lParam)
{
Console.Write("Window handle is ");
Console.WriteLine(hwnd); return true;
}
}

DLL 傳遞結(jié)構(gòu)
BOOL PtInRect(const RECT *lprc, POINT pt);

using System.Runtime.InteropServices;
[StructLayout(LayoutKind.Sequential)]
public struct Point {
public int x;
public int y;
}
[StructLayout(LayoutKind.Explicit)]
public struct Rect
{
[FieldOffset(0)] public int left;
[FieldOffset(4)] public int top;
[FieldOffset(8)] public int right;
[FieldOffset(12)] public int bottom;
}
Class XXXX {
[DllImport("User32.dll")]
public static extern bool PtInRect(ref Rect r, Point p);
}

轉(zhuǎn)載于:https://www.cnblogs.com/micro-chen/p/5022099.html

總結(jié)

以上是生活随笔為你收集整理的【转帖】.Net中C#的DllImport的用法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。