2013-08-08 32 views
7

次のコードはなぜ機能しませんか?"Parameter is incorrect"でAddDllDirectoryへの呼び出しが失敗するのはなぜですか?

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 

答えて

15

AddDllDirectory()は非常にあります最近のwinapiへの追加。これは、Windows 8でのみ使用可能であることが保証されています。以前のWindowsバージョンで取得するには、更新プログラムKB2533623が必要です。あなたの製品要件を選択するときは、これを心に留めてください。

複数の方法で珍しいことですが、文字列を受け入れるwinapi関数の通常のパターンに従いません。これにより、の2つのバージョンで機能が使用可能になり、ANSIバージョンにはAが付加され、UnicodeバージョンにはWが付加されます。 AddDllDirectory()には追加された文字はありません。Unicodeバージョンのみが存在します。それが故意であるのか、それとも意図的に高い確率で見落としているのかは私には分かりません。関数宣言はWindows 8 SDKヘッダーにはありませんが、実際は非常に珍しいです。

したがって、Unicodeバージョンを呼び出したために元の宣言が失敗しましたが、pinvoke marshallerがANSI文字列を渡しました。文字列にAccessViolationを引き起こさない幸運な零点を持つ奇数の文字が含まれているため、あなたはたぶん幸運に思っています。

[DllImport]宣言のCharSetプロパティを使用すると、pinvoke marshallerがUnicode文字列を渡す必要があります。

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 
7

あなたはユニコードをDLLIMPORT属性で使用されていることを指定する必要があり、

​​
+0

ああ、CharSetを設定しないとアンマネージ文字列型を指定する必要があるのはなぜですか?それは漠然としても意味をなさない。私はUnicodeがデフォルトだと思ったのですが? – mavnn

+0

いいえ、ANSIはデフォルト(http://msdn.microsoft.com/en-us/library/7b93s42f.aspx)です。絶対に必要な場所(例:GetProcAddress)でしか使用できないため、奇妙です。 –

関連する問題