2010-05-18 75 views
2

我有一個非託管DLL公開一個函數,它需要一個指向數據結構的指針。我有創建數據結構並調用dll函數沒有任何問題的C#代碼。在函數調用dll的時候,指針是正確的。C#到非託管dll數據結構interop

我的問題是,該DLL保持指針結構,並在稍後的時間點使用數據結構指針。當DLL來使用指針時,它變得無效(我假設.net運行時已將內存移到其他地方)。

這個問題有什麼可能的解決方法?

可能的解決辦法我能想到的是:

  • 修正數據結構莫名其妙的存儲位置?我不知道你會如何在C#中做到這一點,或者即使可以。
  • 手動分配內存,以便我可以控制它,例如使用Marshal.AllocHGlobal
  • 更改DLL函數合約以複製結構數據(這是我目前正在做的短期更改,但我不想根本改變dll,只要我可以幫助它這不是我的代碼開始)。

還有其他更好的解決方案嗎?

回答

2

您可以使用AllocHGlobal分配結構,該結構將其放入非託管內存中,GC不會移動它或釋放它。您也可以使用像this這樣的輔助類來將GC引腳存儲到內存中,因此在未被固定之前它不會被移動或釋放。

+0

這就是我傾向於做的,+1的幫助函數的鏈接。我正在考慮做些什麼幫助功能。 – 2010-05-18 20:13:20

0

如果沒有在手的DLL來試試這個,很難說這是否可行。我會嘗試讓對象在您的C#類中「固定」,這樣內存掛起爲您的應用程序的生活。然後將靜態對象傳遞給DLL。

+0

靜態實例不保證放在內存中。特別是,他們很可能會被提升到更高一代,從而得到感動。 – 2010-05-18 19:28:44

1
+0

所以有一種方法可以標記現在要移動的內存。我也看到它迫使你使用'不安全'的關鍵字。使用「不安全」可視化手動分配內存有什麼缺點嗎? – 2010-05-18 20:08:41

+0

正如MSDN所說的「使用不安全的代碼引入安全和穩定性風險」(其他含義:http://msdn.microsoft.com/en-us/library/t2yzs44b(v=VS.80).aspx)。恐怕你的問題的答案是「要看情況」。如果您的應用程序需要在較低信任環境中運行(例如Web服務器),則不安全不是一種選擇,但是我認爲p/invoke不會被允許。如果這主要是一個託管應用程序,那麼在C#中使用不安全和做更多的事情是一條可行的路。但它可能歸結爲任何你感覺最舒服的地方。 – 2010-05-18 20:21:36

1
  • 分配內存手動使我有控制在其上例如使用Marshal.AllocHGlobal

非常接近。

在這個特定情況下,我會P/Invoke LocalAlloc分配內存塊並使用StructureToPtr來初始化它。

更新:由於您可以編輯DLL我會更改DLL以提供AllocXXX和FreeXXX函數。

0

GCHandle類旨在處理這種確切的情況。本質上,您將結構的副本放入堆中,然後使用GCHandleType.Pinned調用GCHandle.Alloc。當DLL完成該結構時,請致電GCHandle.Free。給DLL函數的對象的地址,通過它GCHandle.AddrOfPinnedObject。只要固定,GC不會移動它。

相關問題