使用平台呼叫(P Invoke)

2021-09-30 11:31:10 字數 2260 閱讀 1227

使用平台呼叫

p/invoke,它的全名叫平台呼叫(platform invoke),用於呼叫dll 中實現的非託管的單調(flat)程式設計介面,被稱為使用c或c++ 呼叫約定(calling conventions)。最有名的例子是win32 程式設計介面,這是乙個巨大的庫,它公開了windows 所有的內建功能。

為了呼叫單調的非託管程式設計介面,必須首先定義準備呼叫的函式,可以分成兩步:第一步,用system.runtime.interopservices 命名空間下的 dllimport 特性(attribute),能夠定義包含想匯入函式的 .dll,加上一些其他的可選特性;第二步,用關鍵字extern,加以 c 風格函式呼叫的簽名,這樣,指定了返回型別為f# 型別,和函式的名字,最後是用括號括起來的引數型別和引數名。結果這個函式就能像外部的.net 方法一樣進行呼叫。

下面的例子演示了如何匯入windows 函式messagebeep,並呼叫:

open system.runtime.interopservices

// declare a function found in an external dll

["user32.dll")>]

extern

boolmessagebeep(uint32 beeptype)

// call this method ignoring the result

messagebeep(0ul) |> ignore

注意使用平台呼叫,最棘手的問題就是要找出要呼叫函式的簽名。在 **上有 c# 和 vb .net 中常用程式設計介面的簽名的清單,f# 中需要的簽名也相類似。這個站點是乙個維基百科(wiki),因此可以自由新增 f# 簽名。

下面的**演示了如何使用平台呼叫,目標函式期望乙個指標,有關設定指標需要注意幾點。當定義函式時,需要在型別名字的後面加星號(*),表示傳遞指標;在函式呼叫之前,還要定義乙個可變識別符號,表示指標指向的記憶體區域,它可能不是全域性的,但是在頂層,必須是函式定義的一部分。這就是為什麼定義函式main,識別符號status 是函式定義的一部分;最後,必須使用位址運算子(&&),保證傳遞給函式的是指標而不是值本身。

提示編譯這段**總是有警告,因為使用了位址運算子(&&)。要抑制這個警告,可以使用編譯器開關--nowarn 51,或者命令#nowarn 51。

opensystem.runtime.interopservices

// declare a function found in an external dll

["advapi32.dll")>]

extern boolfileencryptionstatus(string filename, uint32* status)

let main() =

//declare a mutable idenifier to be passed to the function

letmutable status = 0ul

// call thefunction, using the address of operator with the

// secondparameter

fileencryptionstatus(@"c:\test.txt", && status) |>ignore

printfn"%d" status

main()

這個例子的執行結果如下(假設在 c: 盤根目錄下有乙個檔案test.txt,加過密的):

1ul注意

平台呼叫也可以執行在 mono 平台上,語法與 f# 中的完全一樣,而難點在於保證要呼叫的庫在所有的目標平台上都可用,且遵循在所有不同的平台上庫的不同的命名約定。更多有關解釋的細節,請看上的文章。

dllimport 特性有一些有用的函式,能夠設定用來控制如何呼叫非託管的函式。表 14-1 做了彙總。

表 14-1 dllimport 上有用的特性

特性名描述charset

定義了傳送字串資料的字符集,可以是 charset.auto、charset.ansi、charset.unicode

entrypoint

設定呼叫函式的名字。如果沒有給定名字,那麼,關鍵字 extern 後面的名字就作為預設定義的函式名。

setlasterror

這是乙個邏輯值,指定是否遇到任何錯誤都應該傳送,因此,通過呼叫 marshell.getlastwin32error() 方法檢查可用性。

注意因為有 com 元件,沒有等價的.net 的非託管程式設計介面的數量在持續減少,因此,在準備呼叫函式前檢查一下是否有等價的託管函式,通常會節省大量時間。

平台呼叫P INVOKE 一 基礎篇

平台呼叫技術 p invoke 主要用於處理在託管 中呼叫c c 庫函式及win32 api函式等非託管函式的情形 一 基本要素 乙個簡單例子 c 宣告 extern c declspec dllexport int multiply int factora,int factorb 實現 int m...

C 高階與初心 (二)P Invoke平台呼叫

最近某個專案要採集交易終端的資訊用於監管,主要廠商給出了api,c 版的。開啟hard模式!c 呼叫c 的dll基本就兩種方法 加乙個vc 專案包一層,或者使用p invoke 平台呼叫 前者對於純c 的客戶端來說,增加了複雜性。那就只剩下平台呼叫了。使用平台呼叫的過程比較艱辛,主要遇到了兩個問題 ...

奇異的Pinvoke呼叫

我們的乙個c 專案需要呼叫c 的dll,通過pinvoke進行方法呼叫。其中的乙個方法及其引數的定義是這樣的 structlayoutattribute layoutkind sequential public struct xvid gbl info t dllimportattribute xv...