7

为什么下面的代码不起作用?

open System
open System.Runtime.InteropServices
open System.ComponentModel

[<DllImport("kernel32")>]
extern int AddDllDirectory(string NewDirectory)

[<EntryPoint>]
let main argv = 
    let result = AddDllDirectory("c:\\")
    if result = 0 then
        printfn "%A" <| Win32Exception(Marshal.GetLastWin32Error())
        // Prints: "System.ComponentModel.Win32Exception (0x80004005): The parameter is incorrect"
    System.Console.ReadLine() |> ignore
    0 // return an integer exit code
4

3 回答 3

17

AddDllDirectory() 是最近添加到 winapi 的。它只保证在 Windows 8 中可用,在较早的 Windows 版本上获取它需要更新 KB2533623。当您选择您的产品要求时,请记住这一点。

它在不止一个方面是不寻常的,它不遵循接受字符串的 winapi 函数的正常模式。这使得该函数在两个版本中可用,附加了 A 的 ANSI 版本和附加了 W 的 Unicode 版本。AddDllDirectory() 没有附加字母,只有 Unicode 版本存在。我不清楚这是故意还是疏忽,故意的可能性很大。Windows 8 SDK 标头中缺少函数声明,这确实非常不寻常。

因此,您的原始声明失败了,因为您调用了 Unicode 版本,但 pinvoke 编组器传递了一个 ANSI 字符串。您可能很幸运,因为该字符串有奇数个字符和足够的幸运零,不会导致 AccessViolation。

需要在 [DllImport] 声明中使用 CharSet 属性,以便 pinvoke 编组器传递 Unicode 字符串。

于 2013-08-08T13:53:35.283 回答
8

您需要在 DllImport 属性中指定使用 unicode,

[<DllImport("kernel32", CharSet=CharSet.Unicode)>]
extern int AddDllDirectory(string NewDirectory)
于 2013-08-08T13:42:35.627 回答
2

经过一些实验,似乎有以下工作:

open System
open System.Runtime.InteropServices
open System.ComponentModel

[<DllImport("kernel32")>]
extern int AddDllDirectory([<MarshalAs(UnmanagedType.LPWStr)>]string NewDirectory)

[<EntryPoint>]
let main argv = 
    let result = AddDllDirectory("c:\\Zorrillo")
    if result = 0 then
        printfn "%A" <| Win32Exception(Marshal.GetLastWin32Error())
    else
        printfn "%s" "Woohoo!"
    System.Console.ReadLine() |> ignore
    0 // return an integer exit code
于 2013-08-08T13:40:55.013 回答