八 平台呼叫

2021-10-05 14:51:52 字數 4031 閱讀 8302

並不是windows api呼叫的所有特性都可用於.net。舊的windows api呼叫是這樣,新功能也是這樣。也許開發人員會編寫一些dll,匯出非託管的方法,在c#中使用它們。

要重用乙個非託管庫,其中不包含com物件,只包含匯出的功能,就可以使用平台呼叫(p/invoke)。有了p/invoke,clr會載入dll,其中包含應呼叫的函式,並編組引數。

要使用非託管函式,首先必須確定匯出的函式名。為此,可以使用dumpbin工具和/exports選項。例如,命令:

dumpbin /exports c:\windows\system32\kernel32.dll | more
列出dll kernel32.dll中所有匯出的函式。這個示例使用windows api函式createhardlink來建立到現有檔案的硬連線。使用此api呼叫,可以用幾個檔名引用相同的檔案,只要檔名在乙個硬碟上即可。這個api呼叫不能用於.net core,因此必須使用平台呼叫。

為了呼叫本機函式,必須定義乙個引數數量相同的c#外部方法,用非託管方法定義的引數型別必須用託管**對映型別。

在c++中,windows api呼叫createhardlink有如下定義:

bool createhardlink(

lpctstr lpfilename,

lpctstr lpexistingfilename,

lpsecurity_attributes lpsecurityattributes);

這個定義必須對映到.net資料型別上。非託管**的返回型別是bool;它僅對映到bool資料型別。lpctstr定義了乙個指向const字串的long指標。windows api給資料型別使用hungarian命名約定。lp是乙個long指標,c是乙個常量,str是以null結尾的字串。t把型別標誌為泛型型別,根據編譯器設定為32位還是64位,該型別解析為lpcstr(ansi字串)或lpwstr(寬unicode字串)。c字串對映到.net型別string。lpsecurrty_attributes是乙個long指標,指向securrty_attributes型別的結構。因為可以把null傳遞給這個引數,所以把這種型別對映到intptr是可行的。該方法的c#宣告必須用extern修飾符標記,因為在c#**中,這個方法沒有實現**。相反,該方法的實現**在dll kernel32.dll中,它用屬性[dllimport]引用。.net宣告createhardlink的返回型別是bool,本機方法createhardlink返回乙個布林值,所以需要一些額外的澄清。因為c++有不同的boolean資料型別(例如,本機bool和windows定義的bool有不同的值),所以特性[marshalas]指定.net型別bool應該對映為哪個本機型別:

[dllimport("kernel32.dll",setlasterror = true,entrypoint = "createhardlink",charset = charset.unicode)]

[return:marshalas(unmanagedtype.bool)]

public static extern bool createhardlink(string newfilename,string existingfinename,intptr securityattributes);

注意:**非常有助於從本機**到託管**的轉換。

可以用[dllimport]屬性指定的設定在表17-2中列出。

為了使createhardlink方法更易於在.net環境中使用,應該遵循如下規則:

在接下來的例子中,類fileutility中的公共方法createhardlink可以由.net應用程式使用。這個方法的檔名引數,與本機windows api方法createhardlink的順序相反。第乙個引數是現有檔案的名稱,第二個引數是新的檔案。這類似於框架中的其他類,如file.copy。

因為第三個引數用來傳遞新檔名的安全特性,此實現**不使用它,所以公共方法只有兩個引數。返回型別也改變了。它不通過返回false值來返回乙個錯誤,而是丟擲乙個異常。如果出錯,非託管方法createhardlink就用非託管api setlasterror設定錯誤號。要從.net中讀取這個值,[dllimport]欄位setlasterror設定為true。在託管方法createhardlink中,錯誤號是通過呼叫marshal.getlastwin32error讀取的。要從這個號中建立乙個錯誤訊息,應使用system.componentmodel命名空間中的win32exception類。這個類通過建構函式接受錯誤號,並返回乙個本地化的錯誤資訊。如果出錯,就丟擲ioexception型別的異常,它有乙個型別win32exception的內部異常。應用公共方法createhardlink的fileiopermission特性,檢查呼叫程式是否擁有必要的許可:

[securitycritical]

internal static class nativemethods}}

public static class fileutility

這個庫使用如下依賴項和命名空間:

依賴項system.security.permissions

命名空間

system

system.io

system.runtime.interopservices

system.security

system.security.permissions

警告:

platforminvoke示例在linux上成功編譯,但沒有執行,因為在linux作業系統上找不到庫kernel32.dll。

現在可以使用這個類輕鬆地建立硬連線。如果程式的第乙個引數傳遞的檔案不存在,就會得到乙個異常,提示「系統無法找到指定的檔案」。如果檔案存在,就得到乙個引用原始檔案的新檔名。很容易驗證它:在乙個檔案中改變文字,它就會出現在另乙個檔案中:

if (args.length != 2)

trycatch (ioexception ex)

}

在windows上呼叫本地方法時,通常必須使用windows控制代碼。windwos控制代碼是乙個32位或64位值,根據控制代碼型別,不允許使用一些值。在.net 1.0中,控制代碼通常使用intptr結構,因為可以用這種結構設定每乙個可能的32位值。然而,對於一些控制代碼型別,這會導致安全問題,可能還會出現執行緒競態條件,在終結階段洩漏控制代碼。所以.net 2.0引入了safehandle類。safehandle類是乙個抽象的基類,用於每個windows控制代碼。microsoft.win32.safehandles命名空間中的派生類是safehandlezeroorminus、oneisinvalid和safehandleminusoneisinvalid。顧名思義,這些類不接受無效的0或-1值。進一步派生的控制代碼型別是safefilehandle、safewaithandle、safencrypthandle和safepipehandle,可以供特定的windows api呼叫使用。

例如,為了對映windows api createfile,可以使用以下宣告返回乙個safefilehandle。當然,通常可以使用.net類file和fileinfo。

internal static extern safehandle createfile(string filenmae,

[marshalas(unmanagedtype.u4)]fileaccess fileaccess,

[marshalas(unmanagedtype.u4)]fileshare fileshare,

intptr securityattributes,

[marshalas(unmanagedtype.u4)]filemode creationdisposition,

int flags,

safehandle template);

64位平台轉32位平台總結

一般都是32位平台轉到64位平台,可是我們剛好相。我們公司最近做的分布式檔案系統,以前是在 64位平台下 以為現在的伺服器很少有 32位平台,也就沒有過多的考慮,現在由於客戶需要,不得不修改至 32位平台。現在總結如下,共大家學習。1 資料型別的定義 一般我們都用 typedef 定義資料型別 ty...

11平台天梯 原理分析 11平台天梯原理分析

寫作緣由 elo ratings elo排名制度是當今對弈水平評估的公認的權威方法。它最初由物理學教授 arpad elo 創立,故命名為埃羅排名。埃羅排名最早應用於西洋棋和圍棋,目前已廣泛用於西洋棋 圍棋 足球 籃球等運動。elo演算法先是在網遊wow取得了成功,現在11平台引進elo演算法實現了...

2017 8 15總結1 平台

description 程式設計計算所需柱子總長是多少。input 第一行包含整數n,1 n 100,表示平台的數量。接下來n行,每行三個數y,x1和x2用來描述每個平台的位置,y表示高度,x1,x2表示兩個端點的x座標,三個數都是正整數,並且小於等於10000,同時滿足x2 x1 1 也就是說平台...