外部函数
本文介绍在本机代码中调用函数的 F# 语言支持。
语法
[<DllImport( arguments )>]
extern declaration
备注
在前面的语法中,arguments
表示提供给 System.Runtime.InteropServices.DllImportAttribute
属性的参数。 第一个参数是一个字符串,表示包含此函数的 DLL 的名称,不带 .dll 扩展名。 可以为 System.Runtime.InteropServices.DllImportAttribute
类的任何公共属性提供其他实际参数,例如调用约定。
假设你有一个包含以下导出函数的本机 C++ DLL。
#include <stdio.h>
extern "C" void __declspec(dllexport) HelloWorld()
{
printf("Hello world, invoked by F#!\n");
}
可以使用以下代码通过 F# 调用此函数。
open System.Runtime.InteropServices
module InteropWithNative =
[<DllImport(@"C:\bin\nativedll", CallingConvention = CallingConvention.Cdecl)>]
extern void HelloWorld()
InteropWithNative.HelloWorld()
与本机代码的互操作性称为平台调用,是 CLR 的一项功能。 有关详细信息,请参阅与非托管代码交互操作。 该部分的信息适用于 F#。
在外部函数中定义参数
使用返回值或参数声明外部函数时,请使用类似于 C 的语法。可以选择使用托管声明(CLR 将在本机和 .NET 类型之间执行一些自动转换)和非托管声明,这些声明在某些情况下可能会提供更好的性能。 例如,可通过两种不同的方式声明 Windows 函数 GetBinaryTypeW:
// Using automatic marshaling of managed types
[<DllImport("kernel32.dll",
CallingConvention = CallingConvention.StdCall,
CharSet = CharSet.Unicode,
ExactSpelling = true)>]
extern bool GetBinaryTypeW([<MarshalAs(UnmanagedType.LPWStr)>] string lpApplicationName, uint& lpBinaryType);
MarshalAs(UnmanagedType.LPWStr)
指示 CLR 在调用函数时在 .NET string
和 Windows 本机字符串表示形式之间执行自动转换。 uint&
声明将向其传递 byref
的 uint
,即作为托管指针。 若要获取托管指针,请使用 &
运算符的地址。
或者,你可能希望手动管理数据类型的封送,并仅使用非托管类型声明外部函数。
// Using unmanaged types
[<DllImport("kernel32.dll", CallingConvention = CallingConvention.StdCall, ExactSpelling = true)>]
extern int GetBinaryTypeW(nativeint lpApplicationName, uint* lpBinaryType);
可以使用 Marshal.StringToHGlobalUni 将 .NET 字符串转换为本机格式,并接收可提供给 lpApplicationName
的指针(nativeint
)。
若要获取指向整数的指针,请使用 &&
运算符或 fixed
关键字的指针。