2010-04-02 14 views
5

Mam metodę chcę zaimportować z pliku DLL i ma podpis:DllImport i char *

BOOL GetDriveLetter(OUT char* DriveLetter) 

próbowałam

[DllImport("mydll.dll")] 
    public static extern bool GetDriveLetter(byte[] DriveLetter); 

i

[DllImport("mydll.dll")] 
    public static extern bool GetDriveLetter(StringBuilder DriveLetter); 

, ale żadne z nich nie zwróciło niczego w zmiennej DriveLetter.

Odpowiedz

6

Wygląda na to, że funkcja GetDriveLetter oczekuje wartości char*, która wskazuje na wystarczającą ilość pamięci do zapisania litery dysku.

Myślę, że najprostszym sposobem podejścia do tego problemu jest zdać surowy IntPtr i owinąć wywołań GetDriveLetter w API, które dba o zarządzaniu zasobami i konwersji do string.

[return:MarshalAsAttribute(UnmanagedType.Bool)] 
private static extern bool GetDriveLetter(IntPtr ptr); 

public static bool GetDriveLetter(out string drive) { 
    drive = null; 
    var ptr = Marshal.AllocHGlobal(10); 
    try { 
    var ret = GetDriveLetter(ptr); 
    if (ret) { 
     drive = Marshal.PtrToStringAnsi(ptr); 
    } 
    return ret; 
    } finally { 
    Marshal.FreeHGlobal(ptr); 
    } 
} 
+0

Co oznacza wartość UnmanagedType.I1? – Malfist

+0

@Malfist, Wartość I1 mówi CLR, aby zarządzał wartością jako 1-bajtową liczbą całkowitą. W tej próbce było niepoprawnie, ponieważ I4 jest poprawną wartością (zaktualizowaną nieco wcześniej). Dlaczego warto sprawdzić ten wpis na blogu, który napisałem na temat ustawiania wartości bool: http://blogs.msdn.com/jaredpar/archive/2008/10/14/pinvoke-and-bool-or-should-i-say-bool .aspx – JaredPar

+0

Kiedy robię I4, otrzymuję MarshalDirectiveException – Malfist

0

StringBuilder jest chyba do zrobienia, ale trzeba ustawić pojemność konstruktora ciąg przed wywołaniem funkcji. Ponieważ C# nie ma pojęcia, ile pamięci użyje GetDriveLeter, należy się upewnić, że StringBuilder ma wystarczająco dużo miejsca. Marshall przekaże następnie char* przypisaną tej długości do funkcji i przekaże ją do StringBuilder.

[return:MarshalAsAttribute(UnmanagedType.I4)] 
private static extern bool GetDriveLetter(StringBuilder DriveLetter); 

public static bool GetDriveLetter(out string driverLetter) { 
    StringBuilder buffer = new StringBuilder(10); 
    bool ret = GetDriveLetter(buffer); 
    driveLetter = buffer.ToString(); 
    return ret; 
} 

Zobacz przykład p/invoke sample for GetWindowText().

+0

Nie zwraca poprawnego ciągu, w przeciwieństwie do zaakceptowanej odpowiedzi. – Malfist

+0

Co się stanie, jeśli dodasz CharSet = CharSet.Ansi do atrybutu DllImport? To jest ważne, ponieważ masz działające rozwiązanie. – shf301

+0

dodanie CharSet.Ansi do DllImport nie robi różnicy. – Malfist

0
[DllImport("mydll.dll")] 
public static extern bool GetDriveLetter([MarshalAs(UnmanagedType.LPStr)] string DriveLetter)