使用平台叫用(P/Invoke)

來源:互聯網
上載者:User

標籤:style   code   http   tar   ext   color   

使用平台叫用

 

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
[<DllImport("User32.dll")>]
extern boolMessageBeep(uint32 beepType)

// call this method ignoring the result
MessageBeep(0ul) |> ignore

 

注意

使用平台叫用,最棘手的問題就是要找出要調用函數的簽名。在http://pinvoke.net 網站上有 C# 和 VB .NET 中常用編程介面的簽名的清單,F# 中需要的簽名也相類似。這個網站是一個維基百科(wiki),因此可以自由添加 F# 簽名。

 

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

 

提示

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

 

openSystem.Runtime.InteropServices

 

// declare a function found in an external dll

[<DllImport("Advapi32.dll")>]

extern boolFileEncryptionStatus(string filename, uint32* status)

 

let main() =

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

    let mutable 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# 中的完全一樣,而痛點在於保證要調用的庫在所有的目標平台上都可用,且遵循在所有不同的平台上庫的不同的命名規範。更多有關解釋的細節,請看http://www.mono-project.com/Interop_with_Native_Libraries上的文章。

 

DllImport 特性有一些有用的函數,能夠設定用來控制如何調用非託管的函數。表 14-1 做了匯總。

 

表 14-1 DllImport 上有用的特性

 

特性名

描述

CharSet

定義了傳送字串資料的字元集,可以是 CharSet.Auto、CharSet.Ansi、CharSet.Unicode

EntryPoint

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

SetLastError

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

 

注意

因為有 COM 組件,沒有等價的.NET 的非託管編程介面的數量在持續減少,因此,在準備調用函數前檢查一下是否有等價的託管函數,通常會節省大量時間。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.