Gmail lento en IE7

Published 117 weeks, 17 hours ago
Tue Dec 11 2007

Seguimos de troubleshooting. Completamente harto de que Firefox arrancara con la velocidad de un caracol cojo, que la carga de una nueva pestaña bloqueara todo el navegador (a ver cuándo narices hacen que las pestañas se procesen en hilos diferentes) y por último pero mucho más molesto reventara frecuente y aleatoriamente en el ordenador de la oficina, decidí pasarme completamente a Internet Explorer 7. Y estoy de lo más contento desde entonces: no hecho nada de menos a ese navegador tan idolatrado por muchos.

Pero tenía una espinita clavada en medio de tanta felicidad: cuando usaba GMail desde IE7, mi equipo se ralentizaba. Mucho. La carga de trabajo del procesador se disparaba más de un 50%, IE7 prácticamente dejaba de responder, y todo el resto de aplicaciones abiertas sufrían por la carga adicional. Llegué a un punto en el que usaba un Firefox portable para acceder a GMail e IE7 para todo lo demás.

Hasta que he dado con el culpable: McAfee. Está instalado como antivirus corporativo, e incluye una toolbar para IE7 llamada Site Advisor; que funciona bastante bien en casi todos los sitios... excepto con GMail, que le pone como una moto. Es el McAfee SiteAdvisor el que incrementa el consumo de recursos en el sistema y ralentiza todo. La solución, por si a alguien más le ocurre, es sencilla:

  1. Abrir IE7, y mostrar la barra de herramientas de SiteAdvisor si está oculta, mediante el menú Herramientas, Barras de Herramientas, McAfee SiteAdvisor.
  2. Expandid el menú del SiteAdvisor y elegid la opción "Lista de no advertidos..."
  3. En el cuadro de diálogo siguiente, agregad el sitio google.com a la lista de sitios de confianza.
  4. Cerrar el SiteAdvisor, cerrad IE7.
  5. Abrid IE7 y entrar en GMail.
Y, como diría Hiro Nakamura, yatta!!

Password olvidada en Ubuntu

Published 117 weeks, 1 day ago
Mon Dec 10 2007

Maldición. Acabo de pasar momentos de cierto pánico: arranco Ubuntu en mi portátil dispuesto a probar KDE en lugar de Gnome, a sugerencia de Joma; y al intentar logarme en el sistema descubro que se me ha olvidado la contraseña, por falta de uso.

Después de googlear un rato, doy con algo que parece la solución, y me dispongo a intentarlo, lleno de un escéptico pesimismo: la solución propuesta es demasiado simple para Linux: no hay que editar ficheros, ni recompilar nada. Sencillamente, tenemos que reiniciar la máquina en modo de recuperación, y una vez en línea de comandos (y en modo root) introducimos el comando passwd. Éste nos pide la nueva contraseña y una confirmación de la misma y ya está: salimos con exit, se reinicia la máquina y ya tenemos la nueva contraseña lista para poder entrar.

Todo lo cual ha sido increíblemente útil, pero no se puede decir que sea muy seguro. Lo suyo es que el comando passwd me hubiera pedido antes la antigua contraseña de root... ¿y cómo es que la contraseña del usuario principal y la de root son la misma?

Inevitable disclaimer.- No me estoy metiendo con nadie, son dudas genuinas que tengo y que me gustaría que alguien me aclarara...

Preferencias en Visual Studio 2005 compatibles con 2008

Published 118 weeks, 5 days ago
Thu Nov 29 2007

Probando, probando, resulta que acabo de comprobar que los settings de Visual Studio 2005 se pueden importar sin problemas en Visual Studio 2008 Express.

Como sin duda ya sabréis, desde VS 2005 el manejo de los settings (configuraciones de entorno, en cristiano), es importable y exportable mediante ficheros .vssettings, en formato XML. Dentro de estos ficheros guardamos todas nuestras preferencias en el uso del IDE, desde la configuración de inicio del IDE (mostrar el entorno vacío, en mi caso), hasta el esquema de colores y fuentes en el editor de texto; pasando por la ruta por defecto para la creación de soluciones, el formato de la ayuda online, el control de código fuente, y un muy largo etcétera de opciones.

Por esta razón, si migramos de equipo o si usamos Visual Studio es más de una máquina es buena idea que hagamos una copia de seguridad de nuestros settings: mediante Herramientas -> Importar y Exportar Configuraciones accedemos a un wizard que nos permite importar configuraciones, exportarlas o restaurar las configuraciones que trae el IDE por defecto. Dicha copia de seguridad se almacena en un fichero .vsssettings, como hemos visto antes; que podemos importar en otras máquinas para disfrutar rápidamente de nuestras preferencias.

Y lo que me ha dado por probar esta mañana es importar los settings del Visual Studio 2005 del trabajo e importarlos en Visual Studio 2008 Express Edition. El proceso es exactamente el mismo, y VS2008 no ha dado ningún error al recibir el nuevo conjunto de preferencias. Pero se han producido dos circunstancias curiosas:

  1. VS2008 tiene, por defecto, un conjunto de preferencias mucho más reducido que el de un Visual Studio completo. Al importar estos settings, el conjunto de preferencias de VS2008 ha aumentado espectacularmente.
  2. Al tener instalado ReSharper en VS2005, el control del IntelliSense lo lleva dicho plugin, y no Visual Studio. Por tanto, en mis preferencias el IntelliSense aparece como desactivado. Para activarlo de nuevo, sencillamente iremos al menú Tools -> Options (VS2008 de momento no está en castellano, que yo sepa); y dentro del cuadro de diálogo que nos muestra el árbol con todas las opciones de personalización elegiremos Text Editor -> All Languages -> General. En esa opción marcaremos como verdaderas las opciones Auto list Members y Parameter Information y ya tendremos IntelliSense en VS2008.

ClearType en Windows XP

Published 141 weeks, 8 hours ago
Tue Jun 26 2007

A partir de la última versión de Microsoft Reader y de forma más evidente en Internet Explorer 7, Microsoft ha introducido su nueva tecnología de renderizado de fuentes, llamada ClearType. ClearType mejora la legibilidad de las fuentes hasta en un 300%, y se nota un contraste clarísimo entre las páginas Web que vemos mediante Internet Explorer al texto que tenemos en un documento abierto con Microsoft Word, por ejemplo.

Pero ahora he descubierto el ClearType Tuner, un applet para el Panel de Control de Windows XP que permite usar la tecnología ClearType en todas las ventanas, menús y aplicaciones de Windows. No, no es algo precisamente nuevo... pero hasta ahora yo no lo conocía, y espero que alguno de vosotros tampoco. Si todos os sabíais ya el chiste, mala suerte. :)

Apellidos aleatorios (y falsos)

Published 164 weeks, 4 days ago
Fri Jan 12 2007
Respondiendo al desafío planteado por Jon Galloway en su excelente blog, aquí está mi solución para generar apellidos falsos y aleatorios. El código está repleto de comentarios, eso sí en inglés de momento, los traduciré en cuanto pueda. Estás invitado, por supuesto, a hacer preguntas, críticas, o incluso mejor un buen refactorizado! =)

class Program
{
    
//Un arraylist que contiene todos los posibles digramas (ver más abajo)
    //(Nota: digram en inglés es la combinación de dos caracteres, no sé si en español será sílaba)
    private static ArrayList AllDigrams = new ArrayList();
    
//Un arraylist que contiene todas las letras posibles (ver más abajo)
    
private static ArrayList AllLetters = new ArrayList();
    
//Una semilla aleatoria para el generador aleatorio principal
    
private static Random rSeed = new Random()
    
//Un array multidimensional que especifica la estructura principal de un apellido. 
    // "A" representa una vocal, "B" una consonante
    //"AB representa un digrama de vocal + consonante, etc...
    //Estas combinaciones las he hecho a mano, puedes añadir, modificar o quitar 
    //combinaciones para ajustar el tipo de apellidos que se obtengan
    
private static string[,] SurnameRandomTypes = new string[106]
            {
                {
"A",  "BA""B",  "A",  "BA"""},
                {
"B",  "A",  "BA""",   "",   ""},
                {
"A",  "BA""A",  "B",  "A",  "BB"},
                {
"A",  "B",  "B",  "A",  "BA"""},
                {
"A",  "BB""AB""A",  "",   ""},
                {
"BA""B""B",  "A",  "B",  "A"},
                {
"B",  "AB""A",  "BB""A",  "AB"},
                {
"B",  "AB""B",  "A",  "BB""AB"},
                {
"A",  "BB""A",  "B",  "AB"""},
                {
"AB""AA""B",  "A",  "B",  "A"},
            }
;

    static void Main()
    {
        
bool exit = false;
        
//Cargamos TODOS los posibles digrams en memoria, 
        //en el arraylist AllDigrams
        
LoadDigrams();
        
//Lo mismo para las letras posibles, 
        //en el arraylist AllLetters
        
LoadLetters();
        do
        
{
            
for (int 0i <20i++)
            {
                Console.WriteLine(
"Apellido Aleatorio:    {0}"
                    GenerateRandomSurname())
;
            
}
            Console.WriteLine(
"Pulsa ENTER para generar otro lote, X para salir");
            string 
sInput Console.ReadLine();
            if 
(sInput.ToString() == "x" || sInput.ToString() == "X")
                exit 
= true;
        
while (exit == false);
        
Console.ReadLine();
    
}

    
/// <summary>
    /// Éste método genera un apellido aleatorio y lo devuelve.
    /// </summary>
    /// <returns></returns>
    
static string GenerateRandomSurname()
    {
        
string sRet "";
        
Random r;
        
//Nueva semilla aleatoria para el generador de números
        
= new Random(rSeed.Next(11000));
        
//y obtenemos un índice al azar
        //para el array multidimensional SurnameRandomTypes
        
int rndIndex r.Next(09);
        
//Entonces leemos las distintas "columnas" de  
        //esa "fila" y decidimos si necesitamos una vocal, 
        //una consonante, un digrama vocal-consonante, 
        //o lo que sea
        
for (int 0i < 6i++)
        {
            
switch(SurnameRandomTypes[rndIndex, i])
            {
                
case "AA":
                    sRet +
getDigram(DigramType.TwoVowels);
                    break;
                case 
"AB":
                    sRet +
getDigram(DigramType.VowelAndConsonant);
                    break;
                case 
"BA":
                    sRet +
getDigram(DigramType.ConsonantAndVowel);
                    break;
                case 
"BB":
                    sRet +
getDigram(DigramType.TwoConsonants);
                    break;
                case 
"A":
                    sRet +
getLetter(LetterType.Vowel);
                    break;
                case 
"B":
                    sRet +
getLetter(LetterType.Consonant);
                    break;
                default
:
                    
break;
            
}
        }
        
//Y devolvemos el apellido generado 
        //convirtiendo a mayúsculas la primera letra
        
return sRet.Substring(0,1).ToUpper() + 
            sRet.Substring(
1);
    
}

    
#region Letters and Digrams
    
    
#region Structs and Enums
    
/// <summary>
    /// Con esta enumeración sabremos de qué 
    /// está compuesto el digrama
    /// </summary>
    
private enum DigramType
    { TwoVowels, VowelAndConsonant, ConsonantAndVowel, TwoConsonants }

    
/// <summary>
    /// Con esta enumeración sabremos si una letra es una
    /// vocal o una consonante
    /// </summary>
    
private enum LetterType { Vowel, Consonant }

    
/// <summary>
    /// Un objeto digrama. Además del propio digrama ("th", por ejemplo)
    /// guardamos el rango de frecuencia en el que el digrama aparece 
    /// en el lenguaje inglés y su tipo
    /// </summary>
    
private struct Digram 
    {
        
public int iniRange;        //El principio de su rango.
        
public int endRange;        //El final de su rango.
        
public string Value;        //Su valor
        
public DigramType Type;     //Su tipo, según la enumeración DigramType
    
}

    
/// <summary>
    /// Una letra. Además de la propia letra ("a", por ejemplo)
    /// guardamos el rango de frecuencia en la que aparece  
    /// en el lenguaje inglés y su tipo
    /// </summary>
    
private struct Letter
    {
        
public int iniRange;        //El principio de su rango.
        
public int endRange;        //El final de su rango.
        
public string Value;        //Su valor.
        
public LetterType Type;     //Su tipo, según la enumeración LetterType
    
}
    
#endregion

    
/// <summary>
    /// Este método devuelve el valor  
    /// de un digrama aleatorio del tipo especificado
    /// </summary>
    /// <param name="type">El tipo de digrama que queremos obtener</param>
    /// <returns>El VALOR del digrama ("th", por ejemplo)</returns>
    
static string getDigram(DigramType type)
    {
        Random r 
= new Random(rSeed.Next(01000));
        
Digram nuDigram = new Digram();
        do
        
{
            
//Obtenemos un número aleatorio dentro del rango
            //TOTAL de TODOS los digramas
            
int freq r.Next(05548)//Ver LoadDigrams()
            
foreach (Digram digram in AllDigrams)
            {
                
//Y si el número aleatorio está dentro del  
                //rango de frecuencia del digrama actual, 
                //tenemos un ganador!
                
if (freq >digram.iniRange && freq <digram.endRange) 
                        nuDigram 
digram;
            
}
            
//Pero sólo si es del tipo que necesitamos
        
while (nuDigram.Type !type);
        return 
nuDigram.Value;
    
}

    
/// <summary>
    /// Obtenemos el VALOR de una sola letra del tipo especificado
    /// </summary>
    /// <param name="type">El tipo de letra que queremos obtener</param>
    /// <returns>El VALOR de la letra</returns>
    
static string getLetter(LetterType type) 
    {
        Random r 
= new Random(rSeed.Next(01000));
        
Letter nuLetter = new Letter();
        do
        
{
            
//Obtenemos un número aleatorio dentro del rango 
            //TOTAL de TODAS las letras
            
int freq r.Next(010025)//Ver LoadLetters()
            
foreach (Letter letter in AllLetters)
            {
                
//Y si el número aleatorio
                //está dentro del rango de frecuencias de
                //la letra actual, tenemos un ganador!
                
if (freq >letter.iniRange && freq <letter.endRange)
                        nuLetter 
letter;
            
}
            
//Pero sólo si es del tipo que necesitamos  
        
while (nuLetter.Type !type);
        return 
nuLetter.Value;
    
}

    
/// <summary>
    /// Simple comprobación booleana para ver si una letra determinada es
    /// una vocal o una consonante
    /// </summary>
    /// <param name="checkLetter">La letra a comprobar</param>
    /// <returns>True si es una vocal, false en cualquier otro caso</returns>
    
static bool IsAVowel(string checkLetter)
    {
        
switch(checkLetter.ToLower())
        {
            
case "a":
            
case "e":
            
case "i":
            
case "o":
            
case "u":
                
return true;
            default
:
                
return false;
        
}
    }

    
/// <summary>
    /// Gracias del departamento de Informática de la Universidad de Bristol
    /// (y a Google) he encontrado una lista de todas las letras del
    /// alfabeto inglés, con su frecuencia de uso.
    /// Como Random maneja enteros, he multiplicado todos estos valores * 100
    /// La suma de todos ellos debería ser 10.000, lo que hace que cuando calculamos
    /// el rango de números debería ser 10.000 + la cantidad de letras posibles;  
    /// porque el rango de la primera letra es de 0 a 1.231, y el siguiente  
    /// rango de letra empezará en 1.232 (el fin del anterior rango +1)
    /// En el caso de letras solas esto es correcto, y los rangos van desde
    /// 0 a 10.025. 
    /// 
    /// Pero, no sé porqué, en el caso de los digramas el rango va  
    /// de 0 a 5.548. El porcentaje de frecuencia de todos los digramas disponibles,
    /// todos ellos multiplicados por 100 y sumados NO da 10.000 como debiera.
    /// ¿Alguien sabe porqué? A no ser que la lista de digramas que tengo NO esté completa.
    /// </summary>
    
static void LoadLetters()
    {
        
// http://www.cs.bris.ac.uk/Teaching/Resources/COMS30124/Labs/freq.html
        // Porcentaje de frecuencia de letras
        //
        //  E 12.31      L 4.03     B 1.62
        //  T  9.59      D 3.65     G 1.61
        //  A  8.05      C 3.20     V 0.93
        //  O  7.94      U 3.10     K 0.52
        //  N  7.19      P 2.29     Q 0.20
        //  I  7.18      F 2.28     X 0.20
        //  S  6.59      M 2.25     J 0.10
        //  R  6.03      W 2.03     Z 0.09
        //  H  5.14      Y 1.88      

        
string[] _letterValue 
        
{
            
"e""l""b""t""d""g""a""c""v",
            
"o""u""k""n""p""q""i""f""x",
            
"s""m""j""r""w""z""h""y"
        
};
        int
[] _letterFreq 
        
{
            
123140316295936516180532093
            
794310527192292071822820,
            
659225106032039514188
        
};
        int 
lastEndRange 0;
        
//Recorriendo los arrays rellenados con esos datos
        //guardamos una colección de objetos Letra llamada AllLetters, 
        //asignando a cada Letra su rango, valor y tipo
        
for (int 0i < _letterFreq.Lengthi++)
        {
            Letter nuLetter 
= new Letter();
            
nuLetter.iniRange lastEndRange;
            
nuLetter.endRange lastEndRange + _letterFreq[i];
            
lastEndRange nuLetter.endRange + 1;
            
nuLetter.Value _letterValue[i];
            
nuLetter.Type IsAVowel(_letterValue[i]) ? 
                LetterType.Vowel : LetterType.Consonant
;
            
AllLetters.Add(nuLetter);
        
}
    }
     
    
/// <summary>
    /// Ver el comentario de LoadLetters
    /// </summary>
    
static void LoadDigrams()
    {
        
// http://www.cs.bris.ac.uk/Teaching/Resources/COMS30124/Labs/freq.html
        // Digramas ingleses y su porcentaje de frecuencia de uso
        //  TH  3.15   TO  1.11   SA  0.75   MA  0.56 
        //  HE  2.51   NT  1.10   HI  0.72   TA  0.56
        //  AN  1.72   ED  1.07   LE  0.72   CE  0.55
        //  IN  1.69   IS  1.06   SO  0.71   IC  0.55
        //  ER  1.54   AR  1.01   AS  0.67   LL  0.55
        //  RE  1.48   OU  0.96   NO  0.65   NA  0.54
        //  ES  1.45   TE  0.94   NE  0.64   RO  0.54
        //  ON  1.45   OF  0.94   EC  0.64   OT  0.53
        //  EA  1.31   IT  0.88   IO  0.63   TT  0.53
        //  TI  1.28   HA  0.84   RT  0.63   VE  0.53
        //  AT  1.24   SE  0.84   CO  0.59   NS  0.51
        //  ST  1.21   ET  0.80   BE  0.58   UR  0.49
        //  EN  1.20   AL  0.77   DI  0.57   ME  0.48
        //  ND  1.18   RI  0.77   LI  0.57   WH  0.48
        //  OR  1.13   NG  0.75   RA  0.57   LY  0.47 

        
string[] _digramValue 
        
{   
            
"th""to""sa""ma""he""nt""hi""ta",
            
"an""ed""le""ce""in""is""so""ic",
            
"er""ar""as""ll""re""ou""no""na",
            
"es""te""ne""ro""on""of""ec""ot",
            
"ea""it""io""tt""ti""ha""rt""ve",
            
"at""se""co""ns""st""et""be""ur",
            
"en""al""di""me""nd""ri""li""wh",
            
"or""ng""ra""ly"
        
};
        int
[] _digramFreq 
        
{
            
31511175562511107256,
            
17210772551691067155
            
1541016755148966554
            
145946454145946453
            
131886353128846353
            
124845951121805849
            
120775748118775748
            
113755747
        
};
        int 
lastEndRange 0;
        
//Recorremos los arrays de datos para rellenar
        //la colección de objetos Digram AllDigrams
        //asignándole a cada uno su rango,
        //valor y tipo de digrama
        
for (int 0i < _digramFreq.Lengthi++)
        {
            Digram nuDigram 
= new Digram();
            
nuDigram.iniRange lastEndRange;
            
nuDigram.endRange lastEndRange + 
                _digramFreq[i]
;
            
lastEndRange nuDigram.endRange + 1;
            
nuDigram.Value _digramValue[i];
            if 
(IsAVowel(_digramValue[i].Substring(01)) && 
                IsAVowel(_digramValue[i].Substring(
11)))
                    nuDigram.Type 
DigramType.TwoVowels;
            else if 
(!IsAVowel(_digramValue[i].Substring(01)) && 
                IsAVowel(_digramValue[i].Substring(
11)))
                    nuDigram.Type 
DigramType.ConsonantAndVowel;
            else if 
(IsAVowel(_digramValue[i].Substring(01)) && 
                !IsAVowel(_digramValue[i].Substring(
11)))
                    nuDigram.Type 
DigramType.VowelAndConsonant;
            else 
nuDigram.Type DigramType.TwoConsonants;
            
AllDigrams.Add(nuDigram);
        
}
    }
#endregion
}

Colorized by: CarlosAg.CodeColorizer

Actualización 13/01/2007.- Traducidos los comentarios del código fuente al español. Éste es un ejemplo de los apellidos que se generan:
  • Andaso
  • Estecon
  • Ovloso
  • Eleasawh
  • Athene
  • Tertore
  • Setolyiis
  • Face
  • Lirsuco
  • Rofsender

DataGrid de sólo lectura en Windows Forms

Published 205 weeks, 1 day ago
Mon Apr 03 2006
Las DataGrid en Windows Forms permiten al usuario, por defecto, editar los valores que muestran e incluso crear registros nuevos.

¿Y si queremos cargar una rejilla que sólo muestre datos, sin posibilidad de editarlos o de añadir nuevos datos?

Para ello, una de las cosas que podemos hacer es modificar las propiedades del DefaultView de la tabla con la que vamos a alimentar de datos a la rejilla. Por ejemplo, pongamos que tenemos un DataTable dtDatos que va a ser el DataSource de la rejilla. Si modificamos las propiedades AllowDelete, AllowEdit y AllowNew de la vista por defecto de la tabla origen de datos, tal que así:

dtDatos.DefaultView.AllowDelete = false;
dtDatos.DefaultView.AllowEdit = false;
dtDatos.DefaultView.AllowNew = false;
grdDatos.DataSource = this.dtDatos;

Colorized by: CarlosAg.CodeColorizer

la rejilla grdDatos no permitirá al usuario que modifique, borre o añada nuevos registros.

Por otro lado, si lo que queremos es que se seleccione la fila entera de la rejilla al clickar en cualquiera de sus celdas, implementamos el siguiente código en el evento CurrentCellChanged de la rejilla, que se dispara al cambiar de celda seleccionada.

private void grdDatos_CurrentCellChanged(object sender, EventArgs e)
{
    grdDatos.Select(grdDatos.CurrentRowIndex)
;
}

Colorized by: CarlosAg.CodeColorizer

Sencillamente, lo que hacemos es decirle a la rejilla que seleccione toda la fila, sabiendo qué fila es la que tiene que seleccionar gracias a la propiedad CurrentRowIndex.

Hacer invisible un formulario

Published 214 weeks, 6 days ago
Wed Jan 25 2006
Otro truco interesante, que me tuvo un poco martirizado hasta que lo encontré, es el siguiente. Imaginaos que estamos desarrollando una aplicación que va a residir en el área de notificación de Windows. Hay multitud de tutoriales en Internet al respecto, así que no profundizaré en ello. Pero un pequeño detalle me traía por la calle de la amargura: cuando hacía ALT+TAB, en la lista de ventanas disponibles aparecía la de mi aplicación; a pesar de ser invisible. Y yo sólo quería que la aplicación apareciera como visible,... bueno, pues cuando realmente fuera visible, si me perdonáis la perogrullada.

Tras mucho navegar, encontré lo siguiente:
//Impide que la aplicación sea visible al hacer ALT+TAB
private const int GWL_EXSTYLE (-20);
private const int 
WS_EX_TOOLWINDOW 0x80;
private const int 
WS_EX_APPWINDOW 0x40000;

[DllImport("user32", CharSet=CharSet.Auto)]
private static extern int GetWindowLong(IntPtr hWnd, int nIndex);

[DllImport("user32", CharSet=CharSet.Auto)]
private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int
    
dwNewLong);

private void 
frmMain_Activated(object sender, EventArgs e)
{
    SetWindowLong(
this.Handle, GWL_EXSTYLE, (GetWindowLong(this.Handle,
        GWL_EXSTYLE) | WS_EX_TOOLWINDOW) & ~WS_EX_APPWINDOW)
;
}

Colorized by: CarlosAg.CodeColorizer

Como podéis ver, este código API de Win32 lo único que hace es aplicar un estilo determinado a la ventana actual. Llamar a la API en el evento Activated del form asegura que la aplicación será invisible desde un buen principio. Por cierto, que esto está probado con una aplicación que tiene dos formularios, y el inicial sólo sirve para contener el menú contextual y el icono de la bandeja de notificación, por lo que nunca será necesario que sea visible.

La aplicación en concreto es una pequeña utilidad que sirve para rotar periódicamente el fondo de escritorio de Windows, y alguna otra cosilla hace, y que lleva rondando por mis equipos un montón de tiempo. Está casi terminada, al menos la versión 1.0, pero a ver cuándo tengo tiempo de adecentarla para poder enseñarla.

No ejecutar más de una vez el mismo proceso

Published 214 weeks, 6 days ago
Wed Jan 25 2006
Todos sabemos que, normalmente, el punto de arranque de una aplicación WinForms es la función Main(). Un pequeño truco que nos puede quitar muchos quebraderos de cabeza más adelante es impedir activamente que una aplicación pueda ejecutarse más de una vez. Para ello, podemos usar el siguiente código:

/// <summary>
///Punto de entrada de la aplicación
/// </summary>
[STAThread]
static void Main() 
{
if(Process.GetProcessesByName(
   Process.GetCurrentProcess().ProcessName).GetUpperBound(
0)==0)
   {
      Application.Run(
new frmMain());
   }
}

Colorized by: CarlosAg.CodeColorizer

La clave de todo esto está en la clase Process. Perteneciente al espacio de nombres System.Diagnostics, una de sus utilidades es obtener el nombre del proceso actual (mediante Process.GetCurrentProcess().ProcessName, que devuelve un tipo string) y otra es la de obtener todos los procesos de un determinado nombre (Process.GetProcessesByName, que devuelve un array de objetos Process). Efectivamente, lo que hace el if() en esa línea es buscar el proceso que estamos arrancando en la lista de procesos en uso en la máquina y si no lo encuentra, o lo que es lo mismo el tamaño del array devuelto por GetProcessesByName es 0, arranca la aplicación.