2010-04-02 6 views
5

Ich habe eine Methode, die ich aus einer DLL importieren möchten, und es hat eine Signatur von:DllImport und char *

BOOL GetDriveLetter(OUT char* DriveLetter) 

I

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

und

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

, aber keiner der Einträge in der DriveLetter-Variablen zurückgegeben.

Antwort

6

Es scheint, dass die Funktion GetDriveLetter eine char* erwartet, die auf genügend Speicher verweist, um den Laufwerksbuchstaben zu enthalten.

Ich denke, der einfachste Weg, um dieses Problem zu nähern ist ein rohes IntPtr und wickelt die Anrufe GetDriveLetter in einer API, die Pflege zu einem string der Ressourcenverwaltung und Konvertierung nimmt zu übergeben.

[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

Was bedeutet der UnmanagedType.I1? – Malfist

+0

@Malfist, Der Wert I1 weist die CLR an, den Wert als eine 1-Byte-Ganzzahl zu speichern. Es war in diesem Beispiel tatsächlich falsch, da I4 der richtige Wert ist (vor ein paar Tagen aktualisiert). Um herauszufinden, warum diesen Blog-Eintrag ich auf Marshalling Bool Werte schrieb: http://blogs.msdn.com/jaredpar/archive/2008/10/14/pinvoke-and-bool-or-should-i-say-bool .aspx – JaredPar

+0

Wenn ich es I4 mache, bekomme ich MarshalDirectiveException – Malfist

0

Die Stringbuilder ist wahrscheinlich der Weg zu gehen, aber Sie haben die Fähigkeit des Strings Builder zu setzen, bevor Sie die Funktion aufrufen. Da C# keine Ahnung hat, wie viel Speicher GetDriveLeter verwendet, müssen Sie sicherstellen, dass der StringBuilder über genügend Speicherplatz verfügt. Der Marshaller übergibt dann einen char*, der dieser Länge zugewiesen ist, an die Funktion und führt ihn zurück zum 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; 
} 

Siehe das p/invoke sample for GetWindowText(), für ein Beispiel.

+0

Gibt im Gegensatz zur angenommenen Antwort nicht die richtige Zeichenfolge zurück. – Malfist

+0

Was passiert, wenn Sie CharSet = CharSet.Ansi zum DllImport-Attribut hinzufügen? Das ist, wenn Sie sich interessieren, da Sie eine funktionierende Lösung haben. – shf301

+0

Hinzufügen von CharSet.Ansi zum DllImport macht keinen Unterschied. – Malfist

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