2010-04-02 2 views
5

Ho un metodo che voglio importare da una DLL e ha una firma:DllImport e char *

BOOL GetDriveLetter(OUT char* DriveLetter) 

Ho provato

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

e

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

ma nessuno dei due ha restituito nulla nella variabile DriveLetter.

risposta

6

Sembra che la funzione GetDriveLetter si aspetti un char* che punta alla memoria sufficiente per contenere la lettera di unità.

Penso che il modo più semplice per affrontare questo problema è quello di passare un grezzo IntPtr e avvolgere le chiamate a GetDriveLetter in un'API, che si occupa della gestione delle risorse e la conversione ad un 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

Che cosa significa UnmanagedType.I1? – Malfist

+0

@Malfist, Il valore I1 indica al CLR di eseguire il marshalling del valore come un intero di 1 byte. In realtà in questo esempio non era corretto poiché I4 è il valore corretto (aggiornato un po 'fa). Per quanto riguarda il motivo per cui controllare questo post di blog che ho scritto su marshalling valori bool: http://blogs.msdn.com/jaredpar/archive/2008/10/14/pinvoke-and-bool-or-should-i-say-bool .aspx – JaredPar

+0

Quando eseguo I4, ottengo MarshalDirectiveException – Malfist

0

Lo StringBuilder è probabilmente la strada da percorrere, ma è necessario impostare la capacità del costruttore stringa prima di chiamare la funzione. Dato che C# non ha idea di quanta memoria usi GetDriveLeter, devi assicurarti che StringBuilder abbia spazio sufficiente. Il marshaller passerà quindi un char* assegnato a quella lunghezza alla funzione e lo rimetterà in coda allo 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; 
} 

Vedere il p/invoke sample for GetWindowText(), per un esempio.

+0

Non restituisce la stringa corretta, diversamente dalla risposta accettata. – Malfist

+0

Cosa succede se aggiungi CharSet = CharSet.Ansi all'attributo DllImport? Cioè se ti interessa dal momento che hai una soluzione funzionante. – shf301

+0

aggiungendo CharSet.Ansi a DllImport non fa alcuna differenza. – Malfist

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