F# 将空值传递给非托管导入的 DLL
F# Passing Nulls to Unmanaged Imported DLL
在 F# 中,我使用外部 DLL(在本例中为 SDL 图形库),我正在导入我需要的方法,如下所示...
[<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# 调用这些方法。
例如,这失败 "does not have null as proper value"
let result = SDLDefs.SDL_QueryTexture(textTexture, &format, null, &w, &h)
我阅读了属性 [AllowNullLiteral],但似乎我只能将其应用于我定义的类型,而不是我导入的 DLL 中使用的预定义类型。
有什么办法可以做到这一点吗?
如果要指定null,需要使用"raw pointers",用nativeint
和nativeptr<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 )
在 F# 中,我使用外部 DLL(在本例中为 SDL 图形库),我正在导入我需要的方法,如下所示...
[<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# 调用这些方法。
例如,这失败 "does not have null as proper value"
let result = SDLDefs.SDL_QueryTexture(textTexture, &format, null, &w, &h)
我阅读了属性 [AllowNullLiteral],但似乎我只能将其应用于我定义的类型,而不是我导入的 DLL 中使用的预定义类型。
有什么办法可以做到这一点吗?
如果要指定null,需要使用"raw pointers",用nativeint
和nativeptr<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 )