2016-12-16 28 views
4

在F#中我使用的是外部的DLL(在這種情況下,SDL圖形庫)我進口我需要的方法如下...F#空值傳遞給非託管導入的DLL

[<DllImport("SDL2.dll", CallingConvention = CallingConvention.Cdecl)>] 
extern int SDL_QueryTexture(nativeint texture, uint32& format, int& access, int& w, int& h) 

這工作正常並且我可以成功地使用以下方法調用該方法...

let result = SDLDefs.SDL_QueryTexture(textTexture, &format, &access, &w, &h) 

問題是本機SDL方法接受許多指針參數的空值。這在某些場景中是必需的(其功能類似於重載方法)。我找不到任何方法從F#傳遞空值中調用這些方法。

例如,這將失敗,並「沒有空的合適值」

let result = SDLDefs.SDL_QueryTexture(textTexture, &format, null, &w, &h) 

我看了一下屬性[AllowNullLiteral]但似乎我只能把它應用到我定義的類型,而不是我導入的DLL中使用的預定義類型。

有什麼辦法可以做到這一點?

+1

使用'nativeptr',而不是'INT&'對於那些需要是指針'null',然後用'NativePtr.read' /'NativePtr.write'獲取/設定值。 –

+1

@Fyodor你能舉個例子嗎? 'extern int SDL_QueryTexture(nativeint texture,uint32&format,nativeptr access,int&w,int&h)'不能編譯。 – Moog

+0

已發佈一個答案。很抱歉,很長時間,有點忙。 –

回答

2

如果要指定空值,則需要使用「原始指針」,這些指針由nativeintnativeptr<T>類型表示。

[<DllImport("SDL2.dll", CallingConvention = CallingConvention.Cdecl)>] 
extern int SDL_QueryTexture(nativeint texture, uint32& format, nativeint access, int& w, int& h) 

// Call without null 
let access = 42 
let pAccess = NativePtr.stackalloc<int> 1 
NativePtr.write pAccess access 
SQL_QueryTexture(textTexture, &format, NativePtr.toNativeInt pAccess, &w, &h) 
let returnedAccess = NativePtr.read pAccess 

// Call with null 
SQL_QueryTexture(textTexture, &format, null, &w, &h) 

注:小心stackalloc。在堆棧中分配內存非常方便,因爲您不需要明確釋放它,但是一旦退出當前函數,指向它的指針就會失效。因此,如果您確信函數不會存儲指針並稍後嘗試使用,則只能將這些指針傳遞給外部函數。

如果你需要傳遞一個指向真正的堆內存的指針,它不會在任何地方,你需要Marshal.AllocHGlobal。但不要忘記釋放! (或者:-)

let access = 42 
let pAccess = Marshal.AllocHGlobal(sizeof<int>) 
NativePtr.write (NativePtr.ofNativeInt pAccess) access 
SQL_QueryTexture(textTexture, &format, pAccess, &w, &h) 
Marshal.FreeHGlobal(pAccess) 
相關問題