2013-08-08 11 views
7

Perché il seguente codice non funziona?Perché questa chiamata a AddDllDirectory fallisce con "Il parametro non è corretto"?

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 

risposta

15

AddDllDirectory() è molto aggiunta recente al winapi. È garantito che sia disponibile solo in Windows 8, per scaricarlo nelle versioni precedenti di Windows è necessario un aggiornamento, KB2533623. Tieni questo a mente quando selezioni i requisiti del tuo prodotto.

È insolito in più di un modo, non segue il modello normale per le funzioni winapi che accettano una stringa. Il che rende disponibile la funzione in due versioni, la versione ANSI con A in aggiunta e la versione Unicode con aggiunta di W. AddDllDirectory() non ha una lettera aggiuntiva, esiste solo la versione Unicode. Non è chiaro per me se ciò sia stato intenzionale o un controllo, con alte probabilità di intenzionalità. La dichiarazione di funzione manca nelle intestazioni SDK di Windows 8, in effetti molto insolite.

Quindi la dichiarazione originale non è riuscita perché hai chiamato la versione Unicode ma il marshaller pinvoke ha passato una stringa ANSI. Probabilmente sei stato fortunato perché la stringa aveva un numero dispari di caratteri con abbastanza zeri fortunati da non causare un AccessViolation.

L'utilizzo della proprietà CharSet nella dichiarazione [DllImport] è richiesto in modo che il marshaller pinvoke passi una stringa Unicode.

2

Dopo alcuni esperimenti, sembra le seguenti opere:

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

È necessario specificare che Unicode è utilizzato nel attributo DllImport,

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

Ah, è questo il motivo per cui devo specificare il tipo di stringa non gestita se non setto il CharSet? Inizia anche vagamente a dare un senso. Detto questo, ho pensato che Unicode fosse l'impostazione predefinita? – mavnn

+0

No, ANSI è l'impostazione predefinita (http://msdn.microsoft.com/en-us/library/7b93s42f.aspx), il che è un po 'strano dal momento che lo si utilizza solo dove è assolutamente necessario (ad esempio, GetProcAddress). –

Problemi correlati