c#的dllimport使用方法詳解


DllImport是System.Runtime.InteropServices命名空間下的一個屬性類,其功能是提供從非托管DLL(托管/非托管是微軟的.net framework中特有的概念,其中,非托管代碼也叫本地(native)代碼。與Java中的機制類似,也是先將源代碼編譯成中間代碼(MSIL,Microsoft Intermediate Language),然后再由.net中的CLR將中間代碼編譯成機器代碼。導出的函數的必要調用信息

DllImport屬性應用于方法,要求最少要提供包含入口點的dll的名稱

只有入口點的DLL名稱:

	[DllImport("standerMFC.dll")]public static extern  int PReadUID(ref HHFC_SET stru);[StructLayout(LayoutKind.Sequential)]public struct HHFC_SET{[MarshalAs(UnmanagedType.LPStr)]public String Uid;[MarshalAs(UnmanagedType.I4)]    public int code;}
DllImport的定義如下:
代碼如下:

[csharp]?view plaincopy
  1. [AttributeUsage(AttributeTargets.Method)]??
  2. public?class?DllImportAttribute:?System.Attribute??
  3. {??
  4. ????public?DllImportAttribute(string?dllName)?{…}?//定位參數為dllName??
  5. ????public?CallingConvention?CallingConvention;?//入口點調用約定??
  6. ????public?CharSet?CharSet;???????????????????????????????????//入口點采用的字符接??
  7. ????public?string?EntryPoint;??//入口點名稱??
  8. ????public?bool?ExactSpelling;???//是否必須與指示的入口點拼寫完全一致,默認false??
  9. ????public?bool?PreserveSig;??//方法的簽名是被保留還是被轉換??
  10. ????public?bool?SetLastError;??//FindLastError方法的返回值保存在這里??
  11. ????public?string?Value?{?get?{…}?}??
  12. }??

用法示例:

代碼如下:

[csharp]?view plaincopy
  1. [DllImport("kernel32")]??
  2. private?static?extern?long?WritePrivateProfileString(string?section,string?key,string?val,string?filePath); ?

以上是用來寫入ini文件的一個win32api。??????????

用此方式調用Win32API的數據類型對應:DWORD=int或uint,BOOL=bool,預定義常量=enum,結構=struct。?

DllImport會按照順序自動去尋找的地方:?

1、exe所在目錄?

2、System32目錄?

3、環境變量目錄所以只需要你把引用的DLL 拷貝到這三個目錄下 就可以不用寫路徑了 或者可以這樣server.MapPath(.\bin\*.dll)web中的,同時也是應用程序中的 后來發現用[DllImport(@"C:\OJ\Bin\Judge.dll")]這樣指定DLL的絕對路徑就可以正常裝載。 

????這個問題最常出現在使用第三方非托管DLL組件的時候,我的也同樣是這時出的問題,Asp.Net Team的官方解決方案如下: 首先需要確認你引用了哪些組件,那些是托管的,哪些是非托管的.

托管的很好辦,直接被使用的需要引用,間接使用的需要拷貝到bin目錄下.

非托管的處理會比較麻煩.實際上,你拷貝到bin沒有任何幫助,因為CLR會把文件拷貝到一個臨時目錄下,然后在那運行web,而CLR只會拷貝托管文件,這就是為什么我們明明把非托管的dll放在了bin下卻依然提示不能加載模塊了.  

具體做法如下:

1、首先我們在服務器上隨便找個地方新建一個目錄,假如為C:\DLL  

2、然后,在環境變量中,給Path變量添加這個目錄  

3、最后,把所有的非托管文件都拷貝到C:\DLL中.  或者更干脆的把DLL放到system32目錄  對于可以自己部署的應用程序,這樣未償不是一個解決辦法,然而,如果我們用的是虛擬空間,我們是沒辦法把注冊PATH變量或者把我們自己的DLL拷到system32目錄的。同時我們也不一定知道我們的Dll的物理路徑。  DllImport里面只能用字符串常量,而不能夠用Server.MapPath(@"~/Bin/Judge.dll")來確定物理路徑。ASP.NET中要使用DllImport的,必須在先“using System.Runtime.InteropServices;”不過,我發現,調用這種"非托管Dll”相當的慢,可能是因為我的方法需要遠程驗證吧,但是實在是太慢了。經過一翻研究,終于想到了一個完美的解決辦法首先我們用

代碼如下:
[csharp]?view plaincopy
  1. [DllImport("kernel32.dll")]??
  2. private?extern?static?IntPtr?LoadLibrary(String?path);??
  3. [DllImport("kernel32.dll")]??
  4. private?extern?static?IntPtr?GetProcAddress(IntPtr?lib,?String?funcName);??
  5. [DllImport("kernel32.dll")]??
  6. private?extern?static?bool?FreeLibrary(IntPtr?lib); ?

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

以下自定義類的代碼完成LoadLibrary的裝載和函數調用

代碼如下:
[csharp]?view plaincopy
  1. public?class?DllInvoke???
  2. ????{??????????????
  3. ????????[DllImport("kernel32.dll")]???
  4. ????????private?extern?static?IntPtr?LoadLibrary(String?path); ?
  5. ????????[DllImport("kernel32.dll")]?????
  6. ????????private?extern?static?IntPtr?GetProcAddress(IntPtr?lib,?String?funcName); ??
  7. ????????[DllImport("kernel32.dll")]???????
  8. ????????private?extern?static?bool?FreeLibrary(IntPtr?lib);???????
  9. ??
  10. ????????private?IntPtr?hLib;????
  11. ????????public?DllInvoke(String?DLLPath)?????
  12. ????????{?????????????
  13. ????????????hLib?=?LoadLibrary(DLLPath);????
  14. ????????}?????????
  15. ??
  16. ????????~DllInvoke()???????
  17. ????????{??????????
  18. ????????????FreeLibrary(hLib);????
  19. ????????}??????????
  20. ??
  21. ????????//將要執行的函數轉換為委托????
  22. ????????public?Delegate?Invoke(String?APIName,Type?t)???????
  23. ????????{?????????????
  24. ????????????IntPtr?api?=?GetProcAddress(hLib,?APIName);?????
  25. ????????????return?(Delegate)Marshal.GetDelegateForFunctionPointer(api,t);???????
  26. ????????}??
  27. ????} ?

下面代碼進行調用

代碼如下:
[csharp]?view plaincopy
  1. public?delegate?int?Compile(String?command,?StringBuilder?inf);??
  2. ????????????//編譯??
  3. ????????????DllInvoke?dll?=?new?DllInvoke(Server.MapPath(@"~/Bin/Judge.dll"));??
  4. ????????????Compile?compile?=?(Compile)dll.Invoke("Compile",?typeof(Compile));??
  5. ????????????StringBuilder?inf;??
  6. ????????????compile(@“gcc?a.c?-o?a.exe“,inf);//這里就是調用我的DLL里定義的Compile函數??

大家在實際工作學習C#的時候,可能會問:為什么我們要為一些已經存在的功能(比如Windows中的一些功能,C++中已經編寫好的一些方法)要重新編寫代碼,C#有沒有方法可以直接都用這些原本已經存在的功能呢?答案是肯定的,大家可以通過C#中的DllImport直接調用這些功能。???
DllImport所在的名字空間 using System.Runtime.InteropServices;????
MSDN中對DllImportAttribute的解釋是這樣的:可將該屬性應用于方法。DllImportAttribute 屬性提供對從非托管 DLL?
導出的函數進行調用所必需的信息。作為最低要求,必須提供包含入口點的 DLL 的名稱。??? DllImport 屬性定義如下:

代碼如下:

[csharp]?view plaincopy
  1. namespace?System.Runtime.InteropServices?????
  2. ?{??? ??
  3. ?????[AttributeUsage(AttributeTargets.Method)]?????
  4. ?????public?class?DllImportAttribute:?System.Attribute????
  5. ?????{??? ???
  6. ?????????public?DllImportAttribute(string?dllName)??
  7. ?????????{...}??? ? ??
  8. ??
  9. ?????????public?CallingConvention?CallingConvention;?????
  10. ?????????public?CharSet?CharSet;??? ??
  11. ?????????public?string?EntryPoint;??? ??
  12. ?????????public?bool?ExactSpelling;??? ???
  13. ?????????public?bool?PreserveSig;??? ? ??
  14. ?????????public?bool?SetLastError;??? ???
  15. ?????????public?string?Value?{?get?{...}?}??? ??
  16. ?????}?????
  17. ?}??
說明: ? ??

1、DllImport只能放置在方法聲明上。?
2、DllImport具有單個定位參數:指定包含被導入方法的 dll 名稱的?
dllName 參數。?????
3、DllImport具有五個命名參數:??
a、CallingConvention?
參數指示入口點的調用約定。如果未指定 CallingConvention,則使用默認值?
CallingConvention.Winapi。
b、CharSet 參數指示用在入口點中的字符集。如果未指定 CharSet,則使用默認值?
CharSet.Auto。????   
c、EntryPoint 參數給出 dll 中入口點的名稱。如果未指定?
EntryPoint,則使用方法本身的名稱。?????    
d、ExactSpelling 參數指示 EntryPoint?
是否必須與指示的入口點的拼寫完全匹配。如果未指定 ExactSpelling,則使用默認值 false。?????    
e、PreserveSig?
參數指示方法的簽名應當被保留還是被轉換。當簽名被轉換時,它被轉換為一個具有 HRESULT返回值和該返回值的一個名為 retval?
的附加輸出參數的簽名。如果未指定 PreserveSig,則使用默認值 true。?????    
f、SetLastError 參數指示方法是否保留?
Win32"上一錯誤"。如果未指定 SetLastError,則使用默認值 false。?????  
4、它是一次性屬性類。??????
  

5、此外,用 DllImport 屬性修飾的方法必須具有 extern 修飾符。

----------------------------------------------------------------------------------------------------------------------

托管與非托管

托管代碼與非托管代碼

眾所周知,我們正常編程所用的高級語言,是無法被計算機識別的。需要先將高級語言翻譯為機器語言,才能被機器理解和運行。
在標準C/C++中,編譯過程是這樣的:
enter description here
源代碼首先經過預處理器,對頭文件以及宏進行解析,然后經過編譯器,生成匯編代碼,接著,經過匯編,生成機器指令,最后將所有文件連接起來。這種編譯方式的優點在于,最終直接生成了機器碼,可以直接被計算機識別和運行,無需任何中間運行環境,但缺點也在于,由于不同平臺能夠識別的機器碼不同,因此程序的跨平臺能力較差。
而在Java語言中,源代碼并沒有被直接翻譯成機器碼,而是編譯成了一種中間代碼(字節碼Bytecode)。因此,運行Java程序需要一個額外的JRE(Java Runtime Enviromental)運行環境,在JRE中存在著JVM(Java Virtual Mechinal,Java虛擬機),在程序運行的時候,會將中間代碼進一步解釋為機器碼,并在機器上運行。

使用中間代碼的好處在于,程序的跨平臺性比較好,一次編譯,可以在不同的設備上運行。

托管/非托管是微軟的.net framework中特有的概念,其中, 非托管 代碼也叫本地(native)代碼。與Java中的機制類似,也是先將源代碼編譯成中間代碼(MSIL,Microsoft Intermediate Language),然后再由.net中的CLR將中間代碼編譯成機器代碼。

而C#與Java的區別在于,Java是先編譯后解釋,C#是兩次編譯。

托管 的方式除了擁有跨平臺的優點之外,對程序的性能也產生一定的影響。但程序性能不在本文討論的范圍,這里不在贅述。
此外,在.net中,C++也可以進行托管擴展,從而使C++代碼也依賴于.net和CLR運行,獲得托管代碼的優勢。

托管資源與非托管資源

在上一節中,我們講到,托管代碼與非托管代碼相比,有下列不同:

  1. 編譯運行過程不同
  2. 跨平臺能力不同
  3. 程序性能不同

本節中,我們會涉及到托管和非托管的另一個區別:

  1. 釋放資源的方式不同

在C/C++中,資源都是需要手動釋放的,比如,你new了一個指針,用過之后就需要delete掉,否則就會造成內存泄露。
而在Java中,不必考慮資源釋放的問題,Java的垃圾回收機制(GC,Garbage Collection)會保證失效的資源被自動釋放。
而C#的機制與Java類似,運行于.net平臺上的代碼,分配的資源一般會自動由平臺的垃圾回收器釋放,這樣的資源就是托管資源。
但是一些例外的資源,如System.IO.StreamReader等各種流、各種連接所分配的資源,需要顯式調用Close()或Dispose()釋放,這種資源就叫做非托管資源。

托管與非托管的混合編程

在C#的三大難點之前傳:什么時候應該使用C#?中我提到過,C#的一大優勢在于Windows平臺下的界面編程。但由于C#并不是很普及,經常出現底層或后臺代碼采用C/C++編寫的情況,此時,若選擇C#作為界面語言,則必然遇到一個C#調用C++代碼的問題。
比較普遍的解決方案就是,先將C/C++的代碼生成為DLL動態運行庫,再在C#中調用。
舉個例子
在C中:

#include 
#include void DisplayHelloFromDLL()
{printf ("Hello from DLL !\n");
}void CallHelloFromDLL(char* cp)
{printf (cp);printf ("\n");*cp='a';cp++;printf (cp);printf ("\n");
}

在C#中:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;namespace TestConsole
{using System;using System.Runtime.InteropServices;     // DLL supportclass Program{[DllImport(@"TestLib.dll")]public static extern void DisplayHelloFromDLL();[DllImport(@"TestLib.dll", CallingConvention = CallingConvention.Cdecl)]public static extern void CallHelloFromDLL(StringBuilder s);static void Main(){Console.WriteLine("This is C# program");DisplayHelloFromDLL();StringBuilder sb = new StringBuilder(100);CallHelloFromDLL(sb);Console.WriteLine(sb);}
}

在混合編程中,涉及了幾個要點。

  1. 如何在DLL中將函數接口暴露出來?
    有兩種方式,一種是采用__declspec(dllexport)的聲明,另一種是編寫額外的def文件,如
    ;導出DLL函數
    LIBRARY testLib
    EXPORTS 
    DisplayHelloFromDLL
    CallHelloFromDLL
    
  2. DLL與C#之間如何進行數據傳送?
    這個問題其實很復雜,像int,double這種基本的數據類型,是很好傳遞的。到了byte和char,就有點復雜了,更復雜的還有string和stringBuilder,以及結構體的傳遞等。
    若傳遞的是指針,有兩種方法,一種是采用托管的方式,使用Intptr存儲指針,并使用ref獲得地址(&);另一種是在C#中編寫非托管的代碼,用unsafe聲明:

    unsafe
    {
    //非托管代碼
    }
    

    在非托管代碼中,即可進行指針相關的操作。
    若傳遞的是函數指針,由于C#中沒有函數指針的概念,因此采用委托(delegate)的方式。?
    若傳遞的是自定義結構體,也可以采用ref的方式傳遞。
    這個如果有機會的話,我會單獨整理一下。

  3. extern “C”、CallingConvention =CallingConvention.Cdecl)等必要聲明。
    這里面也牽涉到復雜的語言機制,本文不再贅述。

參考文獻:
[譯]C++, Java和C#的編譯過程解析
編譯原理


本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/458445.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/458445.shtml
英文地址,請注明出處:http://en.pswp.cn/news/458445.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

each函數循環數據表示列舉,列舉循環的時候添加dom的方法

var dotBox $(#bannerNum);var item <li></li>;var itemSize $(#bannerBack p).length;var dotBoxWidth itemSize*24;$(#bannerBack p).each(function () { dotBox.append(<li></li>); dotBox.find(li).eq(0).addClass(current);});這里要根…

使用lxml代替beautifulsoup

深入使用過lxml的都會深深地喜歡上它,雖然BeautifulSoup很流行,但是深入了解lxml后,你就再也不會使用bs了 我覺得beautifulsoup不好用,速度也慢(雖然可以使用lxml作為解析器了).另外soup.find_all這種簡直就是手工時代的操作(很多人使用find find_all這幾個函數, 其實它們使用起…

QT調用dll且進入DLL src code調試

qt應用程序AA.exe調用qt寫的BB.DLL時&#xff0c;進入BB.DLL src code調試 1、debug生成AA.exe 2、將debug生成的AA.exe整包debug folder放到BB.dll的debug生成的文件夾中 3、設置BB.dll這個project&#xff1a;項目----運行-----Executable中選擇BB.dll的debug文件夾中的AA.ex…

php安裝編譯時 configure: error: Cannot find OpenSSL's evp.h

yum install error: protected multilib versions errorsudo yum downgrade openssl 降級sudo yum install openssl-devel 另外參考yum install -y ncurses-devel yum install openssl openssl-develyum install openssl openssl-devel --setoptprotected_multilibfalse ln -s …

laravel項目中css樣式表的背景圖片不顯示

剛學laravel&#xff0c;遇到了很多坑&#xff0c;感覺laravel是挺強大的。 建好后臺項目&#xff0c;奈何css樣式表的背景圖片不顯示 .mainhd {background: url(../images/sky/body_bg.png) repeat-x 0px 0px; } 按理上面的寫法沒錯&#xff0c;因為是從別的后臺搬過來的&…

KVC KVO

1、KVC&#xff0c;即是指 NSKeyValueCoding&#xff0c;一個非正式的Protocol&#xff0c;提供一種機制來間接訪問對象的屬性。而不是通過調用Setter、Getter方法訪問。KVO 就是基于 KVC 實現的關鍵技術之一。 Demo&#xff1a; interface myPerson : NSObject { …

VS2010中 C++創建DLL圖解

一、DLL的創建 創建項目: Win32->Win32項目&#xff0c;名稱&#xff1a;MyDLL 選擇DLL (D) ->完成. 1、新建頭文件testdll.htestdll.h代碼如下&#xff1a;#ifndef TestDll_H_#define TestDll_H_#ifdef MYLIBDLL#define MYLIBDLL extern "C" _declspec(dllimp…

js理解 call( ) | apply( ) | caller( ) | callee( )

被js的這幾個方法搞的this暈頭轉向&#xff0c;下定決心搞清楚&#xff1b;1、call( )和apply( ):兩者都可以將函數綁定到另外一個對象上去運行&#xff0c;只是參數的傳遞方式不同&#xff0c;兩者都可以使當前函數擁有另一個對象的屬性和方法&#xff0c;實現js下的繼承&…

上傳SVN丟失.a文件的問題

iOS項目上傳到svn中&#xff0c;.a文件丟失 用Cornerstone工具&#xff0c;解決這個問題 1.打開Cornerstone左上角&#xff0c;點Cornerstone->Preferences->Subversion 2.Global lgnores下面有一個Use default global ignores 默認這里方框中會打鉤&#xff08;這就是.a…

使用公用表表達式的遞歸查詢

微軟從SQL2005起引入了CTE(Common Table Expression)以強化T-SQL。公用表表達式 (CTE) 具有一個重要的長處&#xff0c;那就是可以引用其自身。從而創建遞歸 CTE。遞歸 CTE 是一個反復運行初始 CTE 以返回數據子集直到獲取完整結果集的公用表表達式。 當某個查詢引用遞歸 CTE 時…

C#委托實現C++ Dll中的回調函數

from:https://blog.csdn.net/ferrycooper/article/details/63261771很多的Dll都是C和C寫的&#xff0c;那么如果C#想要調用Dll中的函數怎么辦&#xff0c;尤其是Dll函數其中一個參數是函數指針的&#xff0c;即里面有回掉函數的用C#怎么實現&#xff1f; C中的回掉函數在C#中有…

安裝Birt方法

安裝BIRT 方法&#xff1a; 博客地址&#xff1a;http://www.mamicode.com/info-detail-850588.html 注意&#xff1a;在 Install new Software 中輸入地址&#xff1a;http://download.eclipse.org/birt/update-site/4.2-interim 看好了 出來的四項要全部選中 &#xff0c;然后…

iOS NSString和NSDate轉換

后臺返回的時間字符串不是標準的時間而是計算機時間的時候&#xff0c;我們需要將它們轉換為標準時間&#xff0c;再進行轉換。 //字符串轉為時間&#xff0c;時間格式自己定 NSString * time "1501776000"; //時間字符串 NSInteger num [time integerValue]; …

15個最好的HTML5前端響應式框架(2014)

文中的多個框架基于SASS創建&#xff0c;SCSS是一種比LESS更簡潔的樣式表編程語言&#xff0c;它能夠編繹成CSS&#xff0c;可復用CSS代碼&#xff0c;聲明變量&#xff0c;甚至是函數&#xff0c;類Ruby/Python的語法。參見&#xff1a; LESS vs SASS&#xff1f;選擇哪種CSS樣…

DLL導出類和導出函數

from:https://blog.csdn.net/goodluckmt/article/details/526912971、動態庫DLL中的類或者函數有時候要被其他的庫調用&#xff0c;因此需要被其他庫調用的類或者函數需要進行導出。 2、首先編寫需要導出的DLL&#xff0c;新建一個工程設置應用程序類型為DLL3、類的代碼如下 頭…

Nginx做web服務器linux內核參數優化

Nginx做web服務器linux內核參數優化Nginx提供web服務時Linux內核參數調整是必不可少的&#xff0c;其中在優化方面就需要我們格外的注意。在下面就是對Linux內核參數優化的詳細介紹&#xff0c;希望大家有所收獲。關于Linux內核參數的優化&#xff1a;net.ipv4.tcp_max_tw_buck…

iOS系統發布時間

發布日期 版本編號 更改2017年9月12日 iOS11 GM seed2017年6月19日 iOS10.3.32016年11月9日 iOS10.2 Beta2 發布iOS10.2測試版版2016年11月1日 iOS10.2 Beta1 發布iOS10.2測試版版2016年10月25日 iOS10.1 發布iOS10.1正式版2016年9月22日 iOS10.1 Beta 發布iOS10.1測試版2016年…

Tomacat服務器的安裝和配置

一&#xff0c; Tomcat服務器的下載地址(Apache Tomcat的官網): http://tomcat.apache.org/download-70.cgi 這里為了穩定性安裝的版本為7.0. 截止目前版本已經發行到了9.0. 二&#xff0c; 解壓下載的壓縮包之后直接進入傻瓜式的安裝。   下載文件的全名&#xff1a; apach…

函數指針與回調函數詳解

函數指針與回調函數詳解 1.什么是函數指針&#xff1f; 函數&#xff08;的&#xff09;指針就是指針。這個指針存放一個函數的地址&#xff0c;而函數的名稱就該函數的入口&#xff0c;即地址。這類似于數組名就是數組的首地址。我們可以通過反匯編直觀的查看到函數名和函數地…

【轉載】Direct3D基礎知識

原文&#xff1a;Direct3D基礎知識 重新從頭開始學習DX,以前太急于求成了,很多基礎知識都沒掌握就開始寫程序了,結果出了問題很難解決.1. D3D體系結構D3D與GDI處與同一層次,區別在于,D3D可以使用HAL(Hardware Abstraction Layer)通過DDI來訪問圖形硬件,充分發揮硬件性能.…