Why does this call cause an AddDllDirectory error with the parameter "Invalid parameter"?

Why is the following code not working?

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 
+7
f # pinvoke
source share
3 answers

AddDllDirectory () is the latest addition to winapi. It is guaranteed to be available only in Windows 8, to obtain it on earlier versions of Windows, update KB2533623 is required. Do not worry when you select product requirements.

This is unusual in more than one way; it does not match the normal pattern for winapi functions that accept a string. This makes the function available in two versions, the ANSI version, which has A added and the Unicode version with W. AddDllDirectory () does not have an attached letter, only the Unicode version exists. It is not clear to me whether it was intentional or supervisory, with high chances for intentional. The function declaration is missing from the Windows 8 SDK headers, which is very unusual.

Thus, your original ad failed because you called the Unicode version, but the pinvoke marker passed the ANSI string. You were probably lucky because there were an odd number of characters in the string with enough successful zeros to not cause AccessViolation.

Using the CharSet property in a [DllImport] declaration requires the pinvoke marker to pass a Unicode string.

+15
source share

You need to indicate that unicode is used in the DllImport attribute,

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

After some experiments, the following works appear:

 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 
+2
source share

All Articles