外部函数

本文介绍在本机代码中调用函数的 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& 声明将向其传递 byrefuint,即作为托管指针。 若要获取托管指针,请使用 & 运算符的地址。

或者,你可能希望手动管理数据类型的封送,并仅使用非托管类型声明外部函数。

// Using unmanaged types
[<DllImport("kernel32.dll", CallingConvention = CallingConvention.StdCall, ExactSpelling = true)>]
extern int GetBinaryTypeW(nativeint lpApplicationName, uint* lpBinaryType);

可以使用 Marshal.StringToHGlobalUni 将 .NET 字符串转换为本机格式,并接收可提供给 lpApplicationName 的指针(nativeint)。

若要获取指向整数的指针,请使用 && 运算符或 fixed 关键字的指针。

另请参阅