2010-04-02 9 views
5

tengo un método Quiero importar desde un archivo DLL y tiene una firma de:DllImport y char *

BOOL GetDriveLetter(OUT char* DriveLetter) 

He intentado

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

y

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

pero ninguno arrojó nada en la variable DriveLetter.

Respuesta

6

Parece que la función GetDriveLetter espera un char* que apunta a suficiente memoria para contener la letra de la unidad.

Creo que la forma más fácil de abordar este problema es pasar una prima IntPtr y envolver las llamadas a GetDriveLetter en una API que se encarga de la gestión de recursos y la conversión a 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

¿Qué significa UnmanagedType.I1? – Malfist

+0

@Malfist, el valor I1 le dice al CLR que marque el valor como un entero de 1 byte. En realidad, esta muestra era incorrecta, ya que I4 es el valor correcto (actualizado hace un momento). En cuanto a por qué echar un vistazo a esta entrada de blog que escribí sobre calcular los valores de bool: http://blogs.msdn.com/jaredpar/archive/2008/10/14/pinvoke-and-bool-or-should-i-say-bool .aspx – JaredPar

+0

Cuando lo hago I4, obtengo MarshalDirectiveException – Malfist

0

El StringBuilder es probablemente el camino a seguir, pero hay que ajustar la capacidad del generador de cadenas antes de llamar a la función. Como C# no tiene idea de cuánta memoria utilizará GetDriveLeter, debe asegurarse de que StringBuilder tenga suficiente espacio. El Marshaller luego pasará un char* asignado a esa longitud a la función y lo devolverá a 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; 
} 

Consulte el p/invoke sample for GetWindowText(), para ver un ejemplo.

+0

No devuelve la cadena correcta, a diferencia de la respuesta aceptada. – Malfist

+0

¿Qué sucede si agrega CharSet = CharSet.Ansi al atributo DllImport? Eso es si te importa ya que tienes una solución de trabajo. – shf301

+0

agregar CharSet.Ansi a DllImport no hace diferencia. – Malfist

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