2010-10-04 5 views
7

Necesito llamar a una función desde una API contenida en un dll. prototipo de la función se ve de la siguiente manera ....Cómo cancelar void * con la invocación de plataforma

int func(char* name, void* value); 

donde el contenido del valor del puntero pueden referirse a cualquier tipo depende del nombre pasado. No estoy seguro de cómo configurar el puerto de entrada de Dll para corregir este vacío *. Ihave estado experimentando con IntPtr que parece funcionar cuando planees el valor es un entero, pero no puedo recuperar los valores correctamente para flotadores etc.

Estoy tratando de importar la función como esta ...

[DllImport("dllname.dll", CharSet = CharSet.Ansi)] 
public static extern int func(string name, ref IntPtr value); 

nota pls ese valor es una salida. Un puntero a un valor de cualquier tipo, es decir, la dirección en una región global de memoria de un valor de un tipo conocido (conocido por el que llama). En un programa C, se esperaría que la persona que realiza la llamada emitiera este vacío * al tipo deseado y la desreferencia para obtener el valor real almacenado allí. Las respuestas dadas hasta ahora parecen basarse en la suposición de que la función escribirá el resultado en la ubicación del puntero pasado. Mi culpa no fue muy específica. Lo siento. C# no es mi bolsa, y ni siquiera sé si IntPtr es el camino a seguir aquí ...

Respuesta

2

No es necesario el ref - IntPtr es la manera de pasar void* a código nativo.

[DllImport("dllname.dll", CharSet = CharSet.Ansi)] 
public static extern int func(string name, IntPtr value); 

EDIT: El código C se puede utilizar la entrada de escribir en la memoria requerida. El problema que enfrenta es que el código administrado sepa cuánta memoria asignar para cada tipo de valor de retorno posible. A continuación, se puede asignar un bloque de tamaño apropiado utilizando Marshal.AllocHGlobal o Marshal.AllocCoTaskMem, liberado (según el método de asignación que utilice) utilice a través de FreeHGlobal o FreeCoTaskMem, una vez que el código administrado se realiza con el valor de salida.

Consulte la respuesta de @Alex Farber para ver un ejemplo.

+0

Debería haber sido más específico, lo siento. El valor IntPtr es una salida. En el caso de esta función, será un puntero a un valor que puede ser de cualquier tipo. Se espera que la persona que llama sepa el tipo que intentan recuperar. – matt

+0

@matt - la respuesta sigue siendo la misma - ver edición. –

+0

@matt - echa un vistazo a @ Hans responde y comenta: esta es su mejor apuesta. –

10

La mejor manera de abordar esto es proporcionar sobrecargas de la función para que todo quede absolutamente limpio en el lado C#. De esta manera:

[DllImport("dllname.dll", CharSet = CharSet.Ansi)] 
public static extern int func(string name, out int value); 
[DllImport("dllname.dll", CharSet = CharSet.Ansi)] 
public static extern int func(string name, out float value); 
// etc, one each for each type 
+0

de acuerdo, siempre que el código C se pueda modificar esta es la mejor solución. –

+0

@Steve: no es necesaria ninguna modificación del código C. Solo ve el puntero que pasa el marcador de Pinvoke. –

+0

, entonces esta es la mejor solución y el +1 es aún más merecido –

2
 
[DllImport("dllname.dll", CharSet = CharSet.Ansi)] 
public static extern int func(string name, IntPtr value); 

... 

// n - number of bytes which is enough to keep any type used by function 
IntPtr ptr = Marshal.AllocHGlobal(n); 
func(name, ptr); 

// Use Marshal.ReadByte, Marshal.ReadInt32 ... or Marshal.Copy 
// to copy from ptr filled by func to managed variable. For example: 
byte b = Marshal.ReadByte(ptr); 

Marshal.FreeHGlobal(IntPtr); 
0

A veces, puede ser más fácil de utilizar este enfoque.

Declaración:

[DllImport("dllname.dll", CharSet = CharSet.Ansi)] 
public static extern int func([MarshalAs(UnmanagedType.LPTStr)] string name, [MarshalAs(UnmanagedType.AsAny)] object value); 

Ejemplo de uso para pasar un valor:

func("some string", (int)12); 
func("some string", (double)12); 

Ejemplo de uso para pasar una cadena:

func("some string", "test"); 

Ejemplo de uso para pasar una variable:

int value = 12; 
func("some string", value); 
Cuestiones relacionadas