2011-05-17 127 views
1

在更新第三方庫以在x64上正常工作(它使用指針的int)時,我正在查看P/Invoke簽名。P /調用指針指針?

其中一人需要

__out LPSCARDCONTEXT phContext 

這在WinSCard.h

typedef ULONG_PTR SCARDCONTEXT; 
typedef SCARDCONTEXT *PSCARDCONTEXT, *LPSCARDCONTEXT; 

定義我不是很熟悉C++,所以糾正我,如果我錯了。這意味着LPSCARDCONTEXT是一個指向ULONG_PTR的指針,它也是一個指針。這也解釋了爲什麼IntPtr phContext不起作用,並且ref IntPtr phContext在P/Invoke簽名中起作用。

我很困惑的設計。爲什麼指向需要/使用的指針?

回答

1

雖然我認爲@David Hefferman是絕對正確的,但他沒有提到的問題還有第二部分。

他沒有談論的部分是指向指針的指針確實存在,因爲它們有時用於從函數返回指針作爲參數。這裏有更詳細的discussion about the benefits of pointers-to-pointers

而且,原因,你需要使用ref關鍵字,以便從對C#代碼正確名帥的數據是,除非你使用REF,數據只封本機代碼。如果您需要將修改後的值接收到您的參數中(通過將該變量聲明爲指針這一事實來指示),則需要使用refout向P/Invoke API指示您需要編組數據在函數完成執行後,輸出的本地代碼。

+1

我不認爲你的最後一段是正確的。 「SCARDCONTEXT」讓我覺得它是一種不透明的手柄類型。然後,當使用簽名爲'__out LPSCARDCONTEXT phContext'的參數建議使用指針傳遞引用。我懷疑這實際上是C風格的代碼,並且沒有使用通過引用傳遞,因爲C只傳遞了值。 – 2011-05-17 15:52:57

+0

接受此爲答案。我不會評論答案/討論的其他部分。 – Stijn 2011-05-17 16:04:24

+0

@Stijn這個問題的主要問題是答案的正文是錯誤地使用術語元帥的最後一段。使用'ref'(無論如何它應該是'out'而不是'ref',但這是一個側面問題)不會導致編組。所有它確保參數的值IntPtr傳回給調用者。這裏沒有編組。 – 2011-05-17 16:11:51

2

你的理解不太對。 ULONG_PTR是一個至少與指針一樣寬的無符號整數類型。這意味着您可以從指向ULONG_PTR的任何指針進行投射並返回,而不會丟失信息。

ULONG_PTR的命名顯然欺騙了你,以爲它代表指針的時候,其實意圖是表明它是作爲作爲一個指針。

您可以將ULONG_PTR視爲與UIntPtr等效的C++。

我的猜測是你的函數正在從本地返回來管理一個SCARDCONTEXT值。你會的P/Invoke這樣的:

[DLLImport(...)] 
void MyFunc(out IntPtr Context); 

我選擇使用IntPtr而非UIntPtr因爲我想你永遠需要與價值做任何事情,因爲這可能是一個不透明的句柄。並且IntPtr通常會優於UIntPtr,因爲它符合CLS。

+0

我已經改變了使用* ref UIntPtr phContext *的簽名,它似乎仍然有效,我想它比一個負數作爲指針更有意義。 +1 – Stijn 2011-05-17 15:50:23

+0

@Stijn看到我更新的答案。我認爲你應該使用'out'而不是'ref'。 – 2011-05-17 15:56:09

2

關於理解API的一些想法。

SCARDCONTEXT定義爲ULONG_PTR是一種常用的技術,用於精確隱藏指針指向的內容。它不是一個指向LONG的指針,它是一個'unsigned long',包含指向某個結構的指針,因爲您不需要它的定義(opaque type)。當您將SCARDCONTEXT傳遞給其中一個智能卡功能時,它會內部轉換爲指向不透明結構的指針。當它將這些指針中的一個返回給你時,它會首先被轉換爲SCARDCONTEXT

這是基於C的API中的常見封裝技術,因爲您可以在SCARDCONTEXT上執行的操作與SCARDCONTEXT的定義分開存在,而不是像在基於對象的語言中那樣綁定成員函數。由於@DavidHeffernan explained,這可以工作,因爲ULONG_PTR確實是一個unsigned long,它可以包含一個指針。

所有這一切的要點是,您可以忽略SCARDCONTEXT包含指針的事實。把它當作一個不透明的價值。然後PSCARDCONTEXTLPSCARDCONTEXT變得更容易理解,因爲它們只是指向不透明值的指針。無需費心指向指針。

+0

因此,在編寫本機代碼時,開發人員不會接觸到SCARDCONTEXT的含義,但是在編寫託管代碼時,開發人員(編寫P/Invoke部分)會暴露於含義中。正確? – Stijn 2011-05-17 16:22:08

+0

@Stijn在兩個管理的非託管代碼中,'SCARDCONTEXT'只是一個值。除了識別某些東西之外,它並沒有真正的「意義」。但是在p/invows窗口中,api函數(它們除非它們是基於com的,總是以C風格函數爲導向的),它們來自.net)面向對象),你需要跨越兩種不同風格的代碼。所以你必須意識到在Windows API中使用的代碼「成語」。那就是我想解釋的。其他人已經做了很好的解釋爲什麼使用指針(從函數返回一個值)以及p/invoke簽名應該是什麼。 – 2011-05-18 08:47:45

+0

@Stijn順便說一句,如果你不知道它,你可以在[pinvoke.net](http://pinvoke.net)找到一套相當完整的p/invoke函數簽名。點擊左側導航欄上的「winscard」條目,查看人們爲其提供簽名的功能。 – 2011-05-18 08:56:56