2013-08-08 36 views
7

Tại sao mã sau không hoạt động?Tại sao cuộc gọi này đến AddDllDirectory thất bại với "Tham số không chính xác"?

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 

Trả lời

15

AddDllDirectory() là một rất bổ sung gần đây cho winapi. Nó chỉ được đảm bảo có sẵn trong Windows 8, nhận được nó trên các phiên bản Windows trước đó đòi hỏi một bản cập nhật, KB2533623. Hãy nhớ điều này khi bạn chọn yêu cầu sản phẩm của mình.

Nó không bình thường theo nhiều cách, nó không theo mô hình bình thường đối với các hàm winapi chấp nhận một chuỗi. Điều này làm cho chức năng có sẵn trong hai phiên bản, phiên bản ANSI có phiên bản A được nối và phiên bản Unicode có phần nối W. AddDllDirectory() không có thư nối, chỉ có phiên bản Unicode tồn tại. Nó không phải là rõ ràng với tôi cho dù đó là cố ý hoặc giám sát, với tỷ lệ cược cao cho cố ý. Việc khai báo hàm bị thiếu trong các tiêu đề của Windows 8 SDK, thực sự rất khác thường.

Vì vậy, khai báo ban đầu của bạn không thành công vì bạn đã gọi phiên bản Unicode nhưng trình gỡ lỗi pinvoke đã truyền một chuỗi ANSI. Bạn có thể đã may mắn vì chuỗi có một số lượng ký tự lẻ với đủ số không may mắn để không gây ra một AccessViolation.

Sử dụng thuộc tính CharSet trong khai báo [DllImport] là bắt buộc để trình gỡ lỗi pinvoke truyền chuỗi Unicode.

2

Sau một số thử nghiệm, nó xuất hiện các công việc sau:

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

Bạn cần phải xác định rằng unicode được sử dụng trong các thuộc tính DllImport,

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

Ah, đó là lý do tại sao tôi cần chỉ định loại chuỗi không được quản lý nếu tôi không đặt CharSet? Nó thậm chí mơ hồ bắt đầu có ý nghĩa. Có nói rằng, tôi nghĩ Unicode là mặc định? – mavnn

+0

Không, ANSI là mặc định (http://msdn.microsoft.com/en-us/library/7b93s42f.aspx), điều này thật kỳ lạ vì bạn chỉ sử dụng nó ở nơi bạn hoàn toàn phải (ví dụ: GetProcAddress). –

Các vấn đề liên quan