2013-08-08 6 views
7

Warum funktioniert der folgende Code nicht?Warum schlägt dieser Aufruf von AddDllDirectory mit "Parameter ist falsch" fehl?

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 

Antwort

15

AddDllDirectory() ist eine sehr neuer Zusatz zum winapi. Es ist nur garantiert in Windows 8 verfügbar sein, erfordert es ein Update, KB2533623. Behalten Sie dies im Hinterkopf, wenn Sie Ihre Produktanforderungen auswählen.

Es ist in mehr als einer Hinsicht ungewöhnlich, es folgt nicht dem normalen Muster für Winapi-Funktionen, die eine Zeichenfolge akzeptieren. Das macht die Funktion in zwei Versionen, die ANSI-Version, die ein A angehängt hat und die Unicode-Version, die ein W angehängt hat. AddDllDirectory() hat keinen angehängten Buchstaben, nur die Unicode-Version existiert. Es ist mir nicht klar, ob das beabsichtigt war oder ein Versehen, mit hohen Wahrscheinlichkeiten. Die Funktionsdeklaration fehlt in den Windows 8 SDK-Headern, was sehr ungewöhnlich ist.

Ihre ursprüngliche Deklaration ist fehlgeschlagen, da Sie die Unicode-Version aufgerufen haben, aber der Pinvoke Marshaller eine ANSI-Zeichenfolge übergeben hat. Sie haben wahrscheinlich Glück gehabt, weil die Zeichenkette eine ungerade Anzahl von Zeichen mit genügend glücklichen Nullen hatte, um keine AccessViolation zu verursachen.

Die Verwendung der CharSet-Eigenschaft in der [DllImport] -Deklaration ist erforderlich, damit der Pinvoke-Marshaller eine Unicode-Zeichenfolge übergibt.

2

Nach einigen Experimenten scheint es, folgende Arbeiten:

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

Sie müssen die Unicode angeben wird im DllImport Attribut verwendet,

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

Ah, muss ich deshalb den nicht verwalteten String-Typ angeben, wenn ich das CharSet nicht setze? Es fängt sogar an, einen Sinn zu ergeben. Nachdem ich das gesagt hatte, dachte ich, Unicode wäre der Standard? – mavnn

+0

Nein, ANSI ist der Standard (http://msdn.microsoft.com/en-us/library/7b93s42f.aspx), was irgendwie komisch ist, da Sie es nur dort verwenden, wo Sie es unbedingt brauchen (z. B. GetProcAddress). –

Verwandte Themen