• Jueves 17 de Octubre de 2019, 09:54

Autor Tema:  Importar Dll  (Leído 3096 veces)

E.Baley

  • Miembro activo
  • **
  • Mensajes: 44
    • Ver Perfil
Importar Dll
« en: Martes 18 de Marzo de 2008, 19:48 »
0
Hola amigos

Aprovecho para presentarme al foro. Soy un programador casual (sólo programo aplicaciones para mi mismo) y autodidacta (no soy informático) pero llevo bastante tiempo programando. La experiencia es un grado, aunque debo admitir que a veces me cuesta demasiado.
En fin, espero pasarme por aquí a menudo, ahora que conozco el foro, y aportar lo que buenamente pueda.

Venga, ahí va la primera pregunta:
¿ dónde puedo aprender a importar dlls compiladas en un programa C# ? (y a usar sus APIs claro). Concretando, ¿ conocéis algún buen tutorial en algún sitio donde lo expliquen ?

muchas gracias

E.Baley

  • Miembro activo
  • **
  • Mensajes: 44
    • Ver Perfil
Re: Importar Dll
« Respuesta #1 en: Miércoles 19 de Marzo de 2008, 15:15 »
0
Perdón por el lapsus, se me olvidó indicar que se trata de una dll de C++.
Me refiero a usar el "[DllImport ... " para dll "unmanaged"
¿ algún tutorial donde lo expliquen desde cero ?
He buscado en CodeProject y otros, pero sin mucho éxito. Aunque hay artículos donde explican algo, ninguno es del tipo "desde el principio".
gracias

RaYWoLF

  • Nuevo Miembro
  • *
  • Mensajes: 13
    • Ver Perfil
Re: Importar Dll
« Respuesta #2 en: Miércoles 26 de Marzo de 2008, 09:12 »
0
Lamentablemente yo tampoco he encontrado ninguna "biblia" de la utilizacion de dll de c++ en c#. De todas formas, salvo que tengas parametros raros tampoco es excesivamente complicado (en mi caso estoy desesperado con unos struct que tengo que enviar...).

En este post (http : // foros.solocodigo.com/index.php?showtopic=27767&st=0) puedes ver algun ejemplo y si tienes algun problema especifico postea que intentare ayudarte (si es que soy capaz, claro).

E.Baley

  • Miembro activo
  • **
  • Mensajes: 44
    • Ver Perfil
Re: Importar Dll
« Respuesta #3 en: Miércoles 26 de Marzo de 2008, 11:45 »
0
Gracias RaYWoLF

Claro, en su momento me leí ese post (y otros muchos) pero mi problema era que no partía de cero y no entendía la mayor parte de las cosas. He estado buceando unos días y he encontrado un poco por aquí, otro por allá ...

Bueno, al final encontré que el libro "C# a fondo" de Tom Archer (McGraw-Hill) tiene un capítulo (el 17) dedicado a Platform Invoke. A partir de esa base, revisando los artículos me he ido enterando más de la película.

Creo que el de Anaya (La biblia de C#) también tiene algo, pero ese no lo tienen en la biblioteca.

En fin, si quieres pon aquí esos structs infernales y les echaremos un ojo, a ver hasta dónde llegamos.

saludos.

RaYWoLF

  • Nuevo Miembro
  • *
  • Mensajes: 13
    • Ver Perfil
Re: Importar Dll
« Respuesta #4 en: Miércoles 26 de Marzo de 2008, 17:12 »
0
Pues a ver si puedo echarle un vistazo a esos libros que comentas. Yo tambien he leido un poco de aqui y otro poco de alla, a ver si con eso consigo terminar de atar cabos.

Sobre los structs, ya puse en el post que te comente la relacion entre tipos de datos que hacia, pero basicamente es esto:

Código: Text
  1.  
  2. Contenido del .h:
  3.  
  4. typedef struct {
  5. PICTURE_TYPE Picture_type;
  6. char Serial_number[8];
  7. BYTE Range;
  8. WORD Code_page;
  9. bool bRGB;
  10. DWORD Buffer_16bpp_size;
  11. } INFO;
  12.  
  13. typedef enum {
  14. NORMAL_FOTO,
  15. START_FOTO,
  16. STOP_FOTO
  17. } PICTURE_TYPE;
  18.  
  19. Mi codigo C#:
  20. [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
  21. struct INFO
  22. {
  23. public PICTURE_TYPE Picture_type;
  24. [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 8)]
  25. public string Serial_number;
  26. public byte Range;
  27. public ushort Code_page;
  28. public bool bRGB;
  29. public uint Buffer_16bpp_size;
  30. }
  31.  
  32. enum PICTURE_TYPE
  33. {
  34. NORMAL_FOTO,
  35. START_FOTO,
  36. STOP_FOTO
  37. }
  38.  
  39.  

En otro foro me han comentado que parece ser que .net con los structs no se lleva muy bien y que el soluciono algo similar creando un activex en vb6. Yo de vb6 no tengo ni idea la verdad, y tampoco se que hay de cierto en lo que me han dicho.

E.Baley

  • Miembro activo
  • **
  • Mensajes: 44
    • Ver Perfil
Re: Importar Dll
« Respuesta #5 en: Miércoles 26 de Marzo de 2008, 19:22 »
0
A ver, por lo poco que sé, los problemas pueden estar en:

1) Ya lo habrás pensado, pero lo más obvio e inmediato es que, al hacer la llamada de la API desde tu programa, debes pasar el struct como referencia. Supongo que será un parámetro out, y que después de la llamada el struct habrá quedado modificado para que tu dispongas de los datos.
Por tanto, desdde C#, no sólo tienes que declarar la API con sus parámetros "ref",  la llamada debe conterner también los "ref":

Código: Text
  1. // Al llamar al método
  2. Get_info(ref elFilename, ref laInfo);
  3.  

2) El segundo problema que se me ocurre es al serializar el string para pasarlo dentro del struct. Concretamente "public string Serial_number;"
Peeero, los strings en C# son inmutables (si te fijas, cualquier operación sobre un string devuelve una copia del original modificado). Por tanto esa propiedad del struct no podrá ser modificada.
Prueba a pasar un buffer StringBuilder (de System.text) como Serial_number, sería algo así como:

Código: Text
  1. [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
  2. struct INFO{
  3.     public PICTURE_TYPE Picture_type;
  4.     public StringBuilder Serial_number;
  5.     public byte Range;
  6.     public ushort Code_page;
  7.     public bool bRGB;
  8.     public uint Buffer_16bpp_size;
  9. }
  10.  

Como StringBuilder ya implementa ISerializable, no hace falta definir el "[MarshalAs( loquesea)]"

De momento no se me ocurre nada más ... si se me ocurre algo más ya lo pongo

RaYWoLF

  • Nuevo Miembro
  • *
  • Mensajes: 13
    • Ver Perfil
Re: Importar Dll
« Respuesta #6 en: Jueves 27 de Marzo de 2008, 11:25 »
0
Gracias por la respuesta.

Código: Text
  1.  
  2. Declaracion en el .h
  3. // return values:
  4. // 0 - ok
  5. // 1 - disk error
  6. API int Get_info(
  7. char *File_name, //IN
  8. INFO *Info //OUT
  9. );
  10.  
  11. Declaracion en C#:
  12. [DllImport("midll.dll", EntryPoint = "Get_info")]
  13. private unsafe static extern int Get_info(string File_name, ref INFO Info);
  14.  
  15. Ejecucion en C#:
  16. INFO info = new INFO();
  17. string fichero = "c:\\fichero.tif";
  18. int intResult = Get_info(fichero, ref info);
  19.  
  20.  

Sobre lo de pasarlos por referencia, como puedes ver el objeto INFO asi lo paso. El nombre del fichero no lo mando por referencia porque el propio string, hasta donde yo se, es equivalente a char * (de hecho con eso no hay problema porque el fichero si que lo encuentra correctamente).

Respecto a lo de utilizar el StringBuilder, efectivamente parece que seria la mejor opcion porque como tu comentas el string cada vez que lo modificas lo que hace es crear uno nuevo. Eso lo lei en este articulo (http :// msdn2.microsoft.com/es-es/magazine/cc301501(en-us).aspx), el problema es que al ejecutar el metodo Get_info me saca este error:

---------------
No se puede calcular la referencia del campo 'Serial_number' del tipo 'INFO': El campo de clase o el campo de estructura no puede ser del tipo StringBuilder. Normalmente se puede conseguir el mismo efecto utilizando un campo String y realizando una inicialización previa de éste en una cadena con una longitud que coincida con la longitud del búfer apropiado.
---------------

Aparte de eso, si lo declarase como StringBuilder sin mas (sin hacer el new porque dentro del struct no me deja), no podria especificarle un tamaño exacto, en este caso 8, no?. Otra cosa que probé fue a utilizar "fixed char Serial_number[8]" en lugar del string, pero tampoco parece que me devuelva resultados coherentes.

E.Baley

  • Miembro activo
  • **
  • Mensajes: 44
    • Ver Perfil
Re: Importar Dll
« Respuesta #7 en: Jueves 27 de Marzo de 2008, 12:32 »
0
Bueno, por lo menos ahora ya lo tengo más claro, el problema está identificado.
Necesitamos:
- Un struct pasado por referencia.
- El campo Serial_number del struct debe ser un string, ya inicializado, de 8 caracteres y modificable.

Podrías:

Código: Text
  1. // Declaración del Struct
  2. [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
  3. struct INFO{
  4.    public PICTURE_TYPE Picture_type;
  5.    public char[] Serial_number;
  6.    public byte Range;
  7.    public ushort Code_page;
  8.    public bool bRGB;
  9.    public uint Buffer_16bpp_size;
  10. }
  11.  
  12.  

Código: Text
  1. // Ejecucion en C#:
  2. string fichero = "c:\\fichero.tif";
  3.  
  4. INFO info = new INFO();
  5. info.Serial_number = new char[8]; // Aquí inicializamos ese campo
  6.  
  7. int intResult = Get_info(fichero, ref info);
  8.  

Como ya está identificado el problema, sólo queda averiguar cual es el tipo correcto que debes pasar, ya inicializado, al campo del Struct.

En el ejemplo anterior he pasado el "Serial_number" inicializado, pero dentro del Array de chars, cada posición no está inicializada todavía. (es decir, "Serial_number" está inicializado, pero Serial_number[1] no).

Si necesitas que también esto esté inicializado, puedes hacer:


Código: Text
  1. // Ejecucion en C#:
  2. string fichero = "c:\\fichero.tif";
  3.  
  4. INFO info = new INFO();
  5. string str_sernum = "12345678";
  6. char[] arr_sernum = pr.ToCharArray();
  7. info.Serial_number = arr_sernum; // Aquí inicializamos ese campo
  8.  
  9. int intResult = Get_info(fichero, ref info);
  10.  

Por lo demás, probar qué otros tipos se pueden pasar.

Por otra parte, el StringBuilder se puede también inicializaar de la misma forma.
Código: Text
  1. // Ejecucion en C#:
  2. string fichero = "c:\\fichero.tif";
  3.  
  4. INFO info = new INFO();
  5. StringBuilder SB_sernum = new StringBuilder(8); // inicializado y declarada su capacidad
  6. info.Serial_number = SB_sernum; // Aquí inicializamos ese campo
  7.  
  8. int intResult = Get_info(fichero, ref info);
  9.  

(El ejemplo era sólo para ver cómo se inicializa, porque el compilador nos ha dicho ya que un StringBuilder no va a servir. En cualquier caso, yo lo probaría porque no cuesta nada).

Suerte.

RaYWoLF

  • Nuevo Miembro
  • *
  • Mensajes: 13
    • Ver Perfil
Re: Importar Dll
« Respuesta #8 en: Jueves 27 de Marzo de 2008, 16:45 »
0
Efectivamente, en c++ la funcion recibe un puntero a char (el nombre del fichero, que con un string parece que va bien) y un puntero a un objeto tipo INFO (el struct), por lo que necesitamos enviarlo por referencia ya que el metodo modifica el contenido de dicho struct.

Si utilizo char[] en lugar de string (tambien lo habia probado), aunque lo inicialice tal y como dices, me devuelve este error:

Excepcion tipo -> SafeArrayTypeMismatchException
"La matriz especificada no pertenece al tipo esperado."

Respecto a lo del StringBuilder, tambien probe a inicializarlo tal y como lo has hecho, pero como te comenté antes salta una excepcion.

Gracias por el tiempo que le estas dedicando, que aunque no hayamos conseguido demasiados avances por lo menos se intenta ;-)

RaYWoLF

  • Nuevo Miembro
  • *
  • Mensajes: 13
    • Ver Perfil
Re: Importar Dll
« Respuesta #9 en: Lunes 31 de Marzo de 2008, 09:20 »
0
Al final he solucionado mi problema creandome una dll en c++/cli porque no veia fin a este problema.

Gracias por la ayuda E.Baley  ;)

E.Baley

  • Miembro activo
  • **
  • Mensajes: 44
    • Ver Perfil
Re: Importar Dll
« Respuesta #10 en: Lunes 31 de Marzo de 2008, 12:15 »
0
Bueno me alegra que lo hayas solucionado.
Espero no encontrarme con un problema así.

sl2

KM

  • Nuevo Miembro
  • *
  • Mensajes: 1
    • Ver Perfil
Re: Importar Dll
« Respuesta #11 en: Martes 11 de Noviembre de 2014, 19:11 »
0
Lamentablemente yo tampoco he encontrado ninguna "biblia" de la utilizacion de dll de c++ en c#. De todas formas, salvo que tengas parametros raros tampoco es excesivamente complicado (en mi caso estoy desesperado con unos struct que tengo que enviar...).

En este post (http : // foros.solocodigo.com/index.php?showtopic=27767&st=0) puedes ver algun ejemplo y si tienes algun problema especifico postea que intentare ayudarte (si es que soy capaz, claro).

Me preguntabas si conseguiste enviar los srtuct en C# , ando desesperada con lo mismo . ¿Pudiste conseguirlo?