NET: Como convertir el CLR una app en “AnyCPU” en “32bits”

Os propongo un escenario:

  • Aplicación desarrollada en .NET, hace mucho tiempo, y a decir verdad, con la mitad de los conocimientos que tenemos ahora.
  • Por desgracia, se compiló como “AnyCPU” (lo que se ha demostrado como un error a lo largo del tiempo).
  • Ahora lo lanzas, y te encuentras con un: “Error en microsoft.jet.oledb.4.0”. Tras leer, te das cuenta que esto se arregla recompilando en “x86”
  • … Solo tengo el ejecutable, y unas horas para presentar el programa (música de terror de fondo…)

Bueno, pues hay un trucoquillo para marcar un ejecutable de .NET, compilado en AnyCPU, como un ejecutable x86, ya que realmente, solo hay que cambiar un campo en la cabecera (más o menos). ¿Cómo?, ahora te lo explico:

  • Doy por sentado que tienes el SDK de desarrollo del NET o el Visual Studio en cualquier de sus sabores (con el componente “Developer Tools -> Windows Development Tools -> .NET Development Tools” instalado)
  • Te metes en: “Program Files\Microsoft SDKs\Windows\v6.1\Bin” (ojo el v6.1 es para NET 3.5, para NET 4.x cambiará obviamente) y allí tienes que encontrar un fichero “corflags.exe”.
  • Ejecutas:
    corflags /32bit+ <RutaATuEjecutableANYCPU>

    Y tachán. Ejecutable en 32bits :).

Referencias:

  • http://stackoverflow.com/questions/1507268/force-x86-clr-on-any-cpu-net-assembly
  • http://stackoverflow.com/questions/242304/where-should-i-download-corflags-exe-from
Please follow and like us:

Cuando Double.MaxValue, no es Double.MaxValue

Creo que es uno de los primeros post que voy a escribir por absoluta desesperación. Y el título lo dice todo.

Estamos desarrollando una aplicación en mi empresa, donde usamos un librería “open source” construida de manera intachable. Bien estructurada, con sus clases, con sus interfaces, y todo en NET 2.0.

Ahora viene lo bueno, dentro de la librería, hay un:

public const double Missing = Double.MaxValue;

Esta línea, parece encarnar el mal, y tiene el número #630 dentro del sistema de bugtracking del proyecto (a partir de ahora el número del mal). En ciertos equipos (si, en ciertos, sin diferenciación mayor que ser otro equipo), provoca que el programa se salga (mejor dicho: explote), sin generar ninguna excepción (lo que implica un error por debajo incluso del NET) y sin dejar ningún registro de error. En cambio, si ponemos:

Si hacemos una asignación quitando el alias:

public const double Missing = 1.7976931348623157E+308;

Tenemos otro crash silencioso al ejecutar el programa. Incluso rebajando el exponente, tenemos el mismo fallo. Pero esperen, que viene lo mejor:

public const double Missing = 999999999999999999;

Entonces, todo el felicidad, los pájaros cantan y las nubes se levantan… No falla.

¿¿¿Porqué???. De verdad que no lo entiendo, y los oscuros mundos del NET me tienen frito.

Pues no termino de entender el porque. Puedo conjeturar que viene por la representación que le da .NET, no es representable por algún nivel más bajo de la máquina, o algún redondeo que implique un overflow. Pero la verdad que no he encontrado nada por la red, y menos aun por los foros de la librería. Pueden ser muchos factores, y me estaré dejando muchos sin tener en cuenta, pero desde luego ahora mismo estoy falto de ideas.

Please follow and like us:

Excel y .NET, malos amigos (III): ¿Como poner una imagen en un rango de celdas?

Otra nueva guerra con Excel, desde C#. Ahora el problema era introducir una imagen en un rango de celdas. Un verdadero problema, ya que la imagen tenia que ajustarse a ellas aunque se deformara. Además tenía que funcionar en Office 2003 y 2007. ¿Más madera?, no importa soy informático :P.

Pues bien, primer intento, me pongo manos a la obra y a tirar líneas:

// Rango donde se intertará la imagen
Microsoft.Office.Interop.Excel.Range r1;
r1 = (Microsoft.Office.Interop.Excel.Range) objSheet.get_Range("F5", "AB37");
r1.Select(); //Es necesario seleccinar un rango para poder insertar

// Objeto de todas las imagenes del excel
Microsoft.Office.Interop.Excel.Pictures oPictures =
(Microsoft.Office.Interop.Excel.Pictures)objSheet.Pictures(System.Reflection.Missing.Value);

//La ruta de la imagen donde esta la imagen a insertar,
//OJO es necesario indicar bien la ruta, de lo contrario marcará el siguiente error
//"Error en el método Insert de la clase Pictures" y pues eso despista ya que solo es
//la ruta y no la implementacion del método
string pathTEMP_BMP = System.IO.Path.GetTempFileName();
this._datos.im.Save(pathTEMP_BMP, System.Drawing.Imaging.ImageFormat.Bmp);

// Crear un objeto Picture de Office
Microsoft.Office.Interop.Excel.Picture p =
oPictures.Insert(pathTEMP_BMP, System.Reflection.Missing.Value);
// Redimensionar
p.Width = (double) r1.Width;
p.Height = (double) r1.Height;

Bueno, pues un medio “Fail”. Funciona bien en 2003, pero cuando se abre con Excel 2007, la imagen no se ajusta al rango “r1” de celdas. Miro a la pantalla con resignación torera y exclamo mi mítico: “Me cago en tó”.

Vale, no desesperemos, tras bucear un poco por internet, veo este articulo que me da otra buena idea. No usar el objeto “Pictures” de Excel, si no usar el “Shapes”. Vamos a intentarlo:

// Eliminamos apartir de la línea 17 en adelante y incluimos esto
objSheet.Shapes.AddPicture(pathTEMP_BMP, 
               Microsoft.Office.Core.MsoTriState.msoFalse, 
               Microsoft.Office.Core.MsoTriState.msoCTrue,
               float.Parse(r1.Left.ToString()), float.Parse(r1.Top.ToString()), 
               float.Parse(r1.Width.ToString()), float.Parse(r1.Height.ToString())); 

Perfecto, ahora si funciona bien en 2003, y 2007. Pero lo que cuesta hacer la cosas bien :).

Please follow and like us:

Como poner un label transparente sobre un picturebox en .NET

Programando, y programando me he encontrado con muchas cosas curiosas, entre ellas esta.

Imagina que quieres poner un texto encima de una imagen, lo normal sería, poner un picturebox, y luego poner encima un label pero si pones un label sobre un picturebox o cualquier otra imagen o control, pasan cosas como esta:

Fallo marcado en rojo

Fallo marcado en rojo

Como veis en la captura de arriba (programa que me he hecho en 5 minutos), esto es un problema como la copa de un pino, ya que se ve gris. Bueno no realmente, se ve del color del Form en el cual están alojados el picturebox y el label. Y este el problema, el “parent” del label es el Form, por lo que al hacer la transparencia, que la esta haciendo, la hace con su padre y no con la imagen que tiene encima, de ahí el color gris.

¿Como lograr entonces la transparencia?, pues hay dos métodos, uno sencillo que es cambiar el “parent” del label y poner el picturebox, por lo que la transparencia la tratará de hacer con el picturebox, y otra, escribir el texto en el evento “Paint” del control picturebox que es más complejo pero infinitamente mas potente.

Os adjunto el código para que nos entendamos, con comentarios:

private void Form1_Load(object sender, EventArgs e)
        {
            // Metodo 1º
            // ---------
            // Sencillo y barato... al menos es el que uso para cosas rápidas

            // Inicialización chorra
            this.label1.Text = "Esta no funciona...";
            this.label2.Text = "Esta si funciona...";

            // No funciona
            // ¿PERO QUE COÑO?
            this.label1.BackColor = Color.Transparent;

            // Funciona
            // Me cago en tó... ¿pero porqué?
            this.label2.Parent = this.pictureBox1;
            this.label2.BackColor = Color.Transparent;

        }

        private void pictureBox1_Paint(object sender, PaintEventArgs e)
        {
            // Metodo 2º
            // ---------
            // Bastante mas complicado pero con muchas mas posibilidades
            Font fuente = new Font("Verdana", 8);
            SolidBrush brocha = new SolidBrush(Color.Black);

            e.Graphics.DrawString("Este si funciona, pero es mas complejo", fuente, brocha, 30, 110);

        }

Si queréis echar un ojo al programa os lo adjunto también: transparenciasLabel.

Please follow and like us:

Excel y .NET, malos amigos: Cambiar el rango de datos a un gráfico

Como casi todos los hemos programado algo para .NET, hemos visto la potencia que tiene. Pero cuando ponemos de nuevo los pies en la tierra es cuando tenemos que volver a usar los objetos COM de Windows.

Arrrrggg… Malditos. ¡Luego me preguntarán que porqué odio a muerte el Office!.

Imaginaros el caso: Un excel “plantilla”, donde solo hay que rellenar ciertos datos, pero con unas columnas de datos de longitud dinámica, puede haber desde 10 a 300. Como no, la cosa se complica, también quieren un gráfico que sea variable (es decir, si solo hay 5 datos, que muestre 5, y si hay mas pues mas…). Todo esto se arregla fácilmente con una macro o con una complicada función de esas que trae excel.

Pero ya que el excel lo rellena un programa en .NET (C# para ser mas exactos) lo vamos ha hacel elegantemente:

// Elegir el Gráfico a modificar, es curioso pero si tipo lo declarais con "Chart" en vez de "_Chart" también funciona
Microsoft.Office.Interop.Excel._Chart chart = (Microsoft.Office.Interop.Excel._Chart)objWorkbook.Charts["Mi gráfico"];

// Ahora a cambiar las series que tienen que estar definidas, se podria utilizar el nombre tambien
// FILA es un double donde esta la fila donde acaban los datos
serie = (Microsoft.Office.Interop.Excel.Series) chart.SeriesCollection(1);
serie.XValues = objSheet.get_Range("A4", "A" + Math.Floor(Fila));
serie.Values = objSheet.get_Range("C4", "C" + Math.Floor(Fila));
// Otra serie que tiene el gráfico
serie = (Microsoft.Office.Interop.Excel.Series) chart.SeriesCollection(2);
serie.Values = objSheet.get_Range("D4", "D" + Math.Floor(Fila));

Tachán… tus gráficos con datos dinámicos en un par de líneas. Eso si, tras mucho pensar 🙂

Please follow and like us:

.NET: Como hacer una única función de “Close” para multiples paneles

Os pongo en situación: una aplicación escrita en Visual C# 2005 con múltiples paneles a modo de ventanas flotantes en el form principal. Por necesidades del cliente, ahora se necesita que todos estos paneles tengan un botón de “salida”, o “close”.

Imaginaros, tengo 10 paneles, ¿tengo que hacer 10 funciones?. No hombre… es muy sencillo:

  • Poner los botones en cada panel. Haz doble click sobre uno, y escribe el código siguiente:
    private void btnCerrar_Click(object sender, EventArgs e)
    {
    System.Windows.Forms.Button btn = (Button)sender;
    btn.Parent.Visible = false;
    }
  • Ahora te vas a cada boton y le asignas esta función en cada evento click. Ya está.

Como veras, se puede usar para cerrar panels (en este caso hacerlos invisibles), mover cosas, cerrar un form, y todo lo que se te ocurra que sea muy repetivivo. Espero que os sirva de ayuda.

Please follow and like us:

Usando SQLite en tus aplicaciones

Aveces, te planteas aplicaciones, que necesitarían un lugar donde almacenar mucha información, en muchos casos, simplemente por tenerla ordenada y accesible la incorporación de una base de datos es muy recomendable.
Pero, incluir una base de datos, resulta muy engorroso, de hecho muchas veces incluso es un problema. Os pongo el caso, de necesitar de una pequeña agenda que te vas a instalar en tu PC de casa… Ves sus requisitos y ves que necesita instalar un MySQL o similar. Sencillamente no me lo instalaría (como la mayoría de la gente).

Mucha gente me contestaría, que se podría usar un texto plano, un XML, un archivo binario, o cientos de tipos de soluciones que no necesitaran de tener una base de datos en tu maquina… cierto. ¿Pero y si el volumen de datos empieza a ser un problema?.

Una solución puede ser SQLite, que es una solución intermedia. Es un desarrollo intermedio, una base de datos en un fichero, sin dependencias y todo en una dll.  Ademas hay un desarrollo para ADO.NET, para integrarlo con el Visual Studio, que hace las cosas muy sencillas.

Es una solución intermedia, ya que yo es recomendable usarlo para cosas que requieran mucha fiabilidad (sobre todo de tiempo respuesta) pero para pequeños proyectos o aplicaciones con poco estrés, te solucionará la vida.

Please follow and like us: