Why does the following code not work?
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
AddDllDirectory() is a very recent addition to the winapi. It is only guaranteed to be available in Windows 8, getting it on earlier Windows versions requires an update, KB2533623. Do keep this is mind when you select your product requirements.
It is unusual in more than one way, it doesn't follow the normal pattern for winapi functions that accept a string. Which makes the function available in two versions, the ANSI version that has an A appended and the Unicode version that has a W appended. AddDllDirectory() has no appended letter, only the Unicode version exists. It isn't clear to me whether that was intentional or an oversight, with high odds for intentional. The function declaration is missing from the Windows 8 SDK headers, very unusual indeed.
So your original declaration failed because you called the Unicode version but the pinvoke marshaller passed an ANSI string. You probably got lucky because the string had an odd number of characters with enough lucky zeros to not cause an AccessViolation.
Using the CharSet property in the [DllImport] declaration is required so the pinvoke marshaller passes a Unicode string.
You need to specify that unicode is used in the DllImport attribute,
[<DllImport("kernel32", CharSet=CharSet.Unicode)>]
extern int AddDllDirectory(string NewDirectory)
After some experimentation, it appears the following works:
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With