为什么调用AddDllDirectory失败并显示“参数不正确”?

时间:2013-08-08 13:30:09

标签: .net f# pinvoke

为什么以下代码不起作用?

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

3 个答案:

答案 0 :(得分:17)

AddDllDirectory()是winapi的最新成员。它只保证在Windows 8中可用,在早期Windows版本上获取它需要更新KB2533623。选择产品要求时请注意这一点。

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

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

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

答案 1 :(得分:8)

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

[<DllImport("kernel32", CharSet=CharSet.Unicode)>]
extern int AddDllDirectory(string NewDirectory)

答案 2 :(得分: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