28 sept 2016

Calcular un hash MD5 y devolverlo en formato leíble

El uso de hashes es bastante común en programación, se puede utilizar para guardar una contraseña, (en este caso ya no es recomendable recurrir al MD5), se puede usar para guardar una cadena de verificación o firma e incluso para comparar archivos.

El framework .Net nos presenta una gran variedad de herramientas para calcular un hash, en este caso usaremos la clase MD5CryptoServiceProvider del namespace using System.Security.Cryptography.

Una duda que muchas veces aparece al intentar usar estos CryptoServiceProviders es cómo mostrar el hash para que sea leíble, ya que la función que utilizamos nos devuelveun Array de bytes.

Pues eso es sencillo, recurrimos a la función ToString() y como argumento pasamos "x2" con lo que por cada ítem del array obtendremos un valor hexadecimal de 2 dígitos.

Entonces la función se vería así:

public string MD5Hash(string texto)
{
 var resultado = new StringBuilder();
 using (var md5 = new MD5CryptoServiceProvider())
 {
  var hash = md5.ComputeHash(System.Text.Encoding.UTF8.GetBytes(texto);
  foreach (byte b in hash)
  {
   resultado.Append(b.ToString("x2"));
  }
 }
 return resultado.ToString();
}

2 jun 2016

Password prompt en aplicación de consola de .Net

Muchas veces utilizo aplicaciones de consola, principalmente cuando desarrollo un cliente para alguna API y necesito crear una aplicación de test para mi librería... pero algo que siempre me molestó es no poder enmascarar el password mientras se lo ingresa en la consola... así fue que un día decidí investigar y me encontré con una solución que tenía algunas fallas y le faltaba trabajo... pero recuerdo que lo tomé como base y luego de una buena edición lo uso en todos mis proyectos de aplicación de consola en los que se ingresa un password.

Creo que una de las formas más seguras de enmascarar un password es el que se usa en GNU/Linux, no mostrar nada al ingresar el password, de esa forma no sólo se ocultan los caracteres que conforman el password, pero también se oculta el largo de la cadena, pero hay quienes prefieren ver un asterisco por cada caracter, así que eso es configurable.



Veamos la función que lee y devuelve el password:

static string LeerPassword()
{
    // Caracter a mostrar en pantalla 
    const string mascara = "*";

    ConsoleKeyInfo key;
    var passwd = string.Empty;
    do
    {
        // Leer una tecla a la vez
        key = Console.ReadKey(true);

        if (key.Key != ConsoleKey.Backspace && key.Key != ConsoleKey.Enter)
        {
            // Agrego el caracter a la cadena
            passwd += key.KeyChar;
            Console.Write(mascara);
        }
        else if (key.Key == ConsoleKey.Backspace)
        {
            if (mascara.Length > 0)
            {
                // Si la máscara se imprime hay que borrarla
                Console.Write("\b \b");
            }
            if (!string.IsNullOrEmpty(passwd))
            {
                // Quitar el último caracter de la cadena
                passwd = passwd.Substring(0, passwd.Length - 1);
            }
        }
    }
    while (key.Key != ConsoleKey.Enter);

    return passwd;
}


Con esta simple función ya tenemos esta funcionalidad implementada, resta invocarla desde el punto donde queremos leer el password y listo!

static void Main(string[] args)
{
    Console.Clear();

    Console.WriteLine("Aprendiendo.Net - Enmascarar password");
    Console.WriteLine();
    Console.Write("Usuario: ");
    var usuario = Console.ReadLine();
    Console.Write("Password: ");
    var passwd = LeerPassword();

    /*
     * Validación y resto del código
     */

    Console.ReadLine();
}


Modificando el valor de la constante mascara en nuestra función LeerCodigo() podremos variar el caracter que se mostrará en pantalla al ingresar el password, incluso podemos usar un string vacío para lograr el efecto que nombraba respecto a las aplicaciones en GNU/Linux.

4 ago 2015

Entendiendo la estructura TimeSpan en C#

Una instancia de la estructura TimeSpan representa un periodo de tiempo pero también nos brinda una serie de propiedades y métodos útiles.

Para crear una instancia de TimeSpan tenemos varios constructores, por lo que deberemos buscar el más adecuado a nuestra necesidad.... podemos crear un TimeSpan a partir de ticks, o usando el constructor que más parámetros acepta, podemos crearlo a partir de un número de días, horas, minutos, segundos y milisegundos.

Otra forma de inicializar un TimeSpan es a partir se alguno de sus métodos estáticos cuyo nombre comienza con From, (Desde o A partir de en inglés), entonces podríamos inicializar untimeSpan a partir de un número de minutos usando TimeSpan.FromMinutes(double).

También podemos sumar y restar instancias de TimeSpan, pero como cada instancia es inmutable, el resultado de la operación lo asignaremos a otra variable.

Para realizar estas operaciones recurriremos al los métodos de instancia Add y Subtract los cuales aceptan un único parámetro de tipo TimeSpan, vamos un ejemplo de cada operación:

TimeSpan periodo1 = TimeSpan.FromHours(1);
TimeSpan periodo2 = TimeSpan.FromHours(3);

TimeSpan suma = periodo1.Add(periodo2); // suma representa un TimeSpan de 4 horas: 1 + 3

TimeSpan resta = periodo2.Subtract(periodo1); // resta representa un TimeSpan de 2 horas, 3 - 1



Algunas propiedades de TimeSpan son tan importantes como útiles a la hora de trabajar con intervalos de tiempo, me refiero a las propiedades que nos devuelven el valor de ese intervalo en cierta unidad, por ejemplo la cantidad de segundos totales correspondientes a ese periodo.
Estas propiedades son nombradas como TotalUnidadDeTiempo, por ejemplo TotalSeconds o TotalMinutes, veamos un ejemplo:

TimeSpan foo = TimeStamp.FromMinutes(2);
Console.WriteLine(foo.TotalSeconds.ToString()); // Se imprimirá 120



No debemos confundir estas propiedades con las que sólo reciben el nombre de la unidad de tiempo a la que representan, por ejemplo Hours o MilliSeconds, ya que éstas representan el valor de esa unidad, no la representación total del periodo en esa unidad.

Por ejemplo:

TimeSpan foo = TimeStamp.FromSeconds(70);
Console.WriteLine(foo.TotalSeconds.ToString()); // Se imprimirá 70
Console.WriteLine(foo.Seconds.ToString()); // Se imprimirá 10, ya que el TimeSpan representa un periodo de 1 minuto y 10 segundos



7 abr 2015

Convertir Ticks en Fecha y viceversa

Hoy quisiera publicar un tip que es prácticamente tonto, pero dado que he recibido la consulta y la solución puede no resultar de lo más intuitiva, aquí dejo una función para convertir Ticks en Fecha y Fecha en Ticks.


Antes que nada, qué son Ticks?

Un tick es el mínimo valor que representa un paso, equivalente a 100 nanosegundos, o sea en un mili segundo hay 10.000 ticks.



Public Function TicksToDateTime(ticks As Long) As DateTime
   ' Intuitivo sería tener una función DateTime.FromTicks(Long)
   Return New DateTime(ticks) 
End Function

Public Function DateTimeToTicks(date As DateTime) As Long
   Return date.Ticks
End Function


Como había anticipado, la solución es muy tonta!

En cuanto a tener una forma más intuitiva, podríamos crear un Método de Extensión, (Extension Method), que afecte la clase DateTime, de esa manera tener DateTime.FromTicks(Long).


19 nov 2013

Trace, la herramienta versátil para crear logs

Algo que siempre necesitamos es llevar líneas de log para saber qué está ocurriendo con nuestras aplicaciones y esto se vuelve prácticamente indispensable al trabajar con Windows Services o Servicios de Windows ya que al no tener UI se hace muy difícil saber qué ocurre...

Afortunadamente encontramos la clase Trace en el namespace System.Diagnostics, la cual nos permite de manera muy sencilla ir dejando líneas de log en nuestro código, veamos un ejemplo simple:


   Public Sub New()
      System.Diagnostics.Trace.WriteLine("Inicio de constructor")
      ' Proceso de datos
      System.Diagnostics.Trace.WriteLine("Fin de constructor")
   End Sub

Entonces para el propósito de este post lo que nos interesa es básicamente la capacidad de escribir de esta clase, para lo cual utilizaremos 2 métodos: Write() y WriteLine() cuya principal diferencia, como lo indica su nombre, es que uno escribe y el otro escribe y termina la línea.

Entonces ya sabemos como utilizar esta herramienta para escribir líneas de log, nos resta leer nuestro log, para lo cual Visual Studio cuenta con una ventana llamada Output o Salida (CTRL + W + O) en la cual se van imprimiendo las líneas de nuestro log... impecable si estamos trabajando en nuestro entorno de desarrollo, pero si debemos leer nuestro log desde una aplicación ya compilada (en modo Debug) podemos utilizar la herramienta Debug View que nos permite tener una ventana con nuestro log en la cual podremos usar filtros, resaltado de colores, etc.


23 jul 2012

SQL Server Error 4064 - La solución

Si bien éste no es un tip de .Net, sino que es de SQL Server, me pareció útil compartirlo.
No se puede abrir la base de datos predeterminada del usuario. Error de inicio de sesión.

Este error ocurre cuando intentamos iniciar sesión en SQL Server con un usuario cuya base de datos por defecto fue eliminada del servidor.
En un servidor muy cerrado en cuanto a su seguridad, este problema puede dar la impresión de ser muy dificil de resolver, y más si se trata del único usuario con el que tenemos acceso al servidor.


Sin embargo la solución en muy sencilla, en el SQL Server Management Studio, (Express o no), buscamos en el diálogo de inicio de sesión el botón "Opciones" con lo cual accederemos a las opciones de la conexión que deseamos abrir.

A continación nos ubicamos en la pestaña "Propiedades de la conexión" y buscamos el campo "Conectar con base de datos", el cual mostrará el valor , borramos ese valor y escribimos master, (o cualquier nombre válido de base de datos a la cual tengamos acceso en el servidor), hacemos click en el botón Conectar y listo!


7 jul 2012

Tip: Cómo saber cuántos días tiene un año en .Net?

Algunos programadores no lo tienen en cuenta, otros simplemente nunca lo necesitaron y otros no lo pensaron hasta que se chocaron con el problema... pero es un tip que puede ser útil, Cómo saber cuántos días tiene un año?

La respuesta se encuentra en la clase Calendar, del namespace System.Globalization, la cual contiene varios métodos y funciones de ayuda para operaciones de tiempo, pero la que nos importa en este momento es Calendar.GetDaysInYear(int Year).

Su uso? Depende de lo que necesitemos, pero a mi entender lo más lógico es utilizar la instancia de Calendar que se encuentra instanciada en nuestra CurrentCulture, por lo que se utilizaría de la siguiente manera:


En VB.Net:

Dim DiasDelAnio As Integer = CultureInfo.CurrentCulture.Calendar.GetDaysInYear(aux.Year)


En C#

int diasDelAnio = CultureInfo.CurrentCulture.Calendar.GetDaysInYear(aux.Year)

17 sept 2010

Como hacer un servicio de Windows auto instalable

Todos nos hemos encontrado en la situación de tener que instalar un servicio, y utilizar el comando installutil.exe, pero por qué no ahorrarnos un paso y hacer que el servicio sea auto instalable?



Este tip no tiene mayor secreto, simplemente es un atajo al installutil.exe dentro del ejecutable de nuestro servicio.

Lo que haremos será ir a la clase Program.cs en C# o Módulo Main.vb eb VB y modificar el método main de la siguiente manera:


static class Program
{
///
/// The main entry point for the application.
///

static void Main(String[] args)
{
if (args.Length > 0)
{
switch (args[0])
{
case "/install":
install();
break;
case "/uninstall":
uninstall();
break;
}
}
else
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[] { new SecurityProviderService() };
ServiceBase.Run(ServicesToRun);
}
}
}


Lo que hicimos fue agregarle a nuestro ejecutable la posibilidad de recibir parámetros, en éste caso /install o /uninstall, sólo nos resta crear los métodos para ejecutar éstas acciones y listo.


// Devuelve la ruta a installutil.exe
private static String installUtill()
{
return System.IO.Path.Combine(System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory(), "installutil.exe");
}

private static void uninstall()
{
if (System.IO.File.Exists(installUtill()))
{
System.Diagnostics.Process.Start(installUtill(), String.Format("/u \"{0}\"", System.Reflection.Assembly.GetExecutingAssembly().Location));
System.Diagnostics.Trace.WriteLine("Service uninstalled.");
}
else
throw new System.IO.FileNotFoundException("InstallUtil.exe not found");
}

private static void install()
{
if (System.IO.File.Exists(installUtill()))
{
System.Diagnostics.Process.Start(installUtill(), String.Format("\"{0}\"", System.Reflection.Assembly.GetExecutingAssembly().Location));
System.Diagnostics.Trace.WriteLine("Service installed.");
}
else
throw new System.IO.FileNotFoundException("InstallUtil.exe not found");
}


Muy simple, ahora cuando necesitemos instalar nuestro servicio simplemente lo haremos desde una consola ejecutando NombreDelServicio.exe /install

16 ago 2010

14 oct 2009

Como acceder a la propiedad Text de un control NumericUpDown

Problema con NumericUpDown y la propiedad Text

Hoy me encontré con un problemita trabajando sobre un formulario que contiene varios NumericUpDown. El tema es que se podía seleccionar un valor, luego borrarlo y el sistema no hacía una validación que indicara al usuario que debía introducir un valor.

Al empezar a hacer pruebas noté que el texto queda vacío, pero el valor no cambia, o sea que si el NumericUpDown tiene un valor de 75 y le borramos el texto, al acceder a la propiedad Value del mismo, ésta nos devuelve 75.

El problema para solucionar ese bug me lo encontré cuando intenté acceder a la propiedad Text, para chequear que la misma no contenga un String vacío... Oh sorpresa, no se puede acceder a esa propiedad porque es privada!!

Para acceder a la propiedad Text aprovecharemos de la herencia de esta clase, NumericUpDown es una subclase de Control, entonces al hacer un cast podemos acceder a la propiedad Text para hacer el chequeo.
Esto nos permite varias soluciones posibles, una que me pareció bastante elegante fue asignar un event handler, o manejador de eventos al evento TextChanged, al cual también accederemos mediante un cast a Control.


Solución:


Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
For Each c As Control In Me.Controls
If TypeOf c Is NumericUpDown Then
AddHandler c.TextChanged, AddressOf NumericUpDownControls_TextChanged
End If
Next
End Sub

Private Sub NumericUpDownControls_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs)
If CType(sender, Control).Text = String.Empty Then
CType(sender, Control).Text = CType(sender, NumericUpDown).Value.ToString()
End If
End Sub



Otra posible solución, más eficiente desde el punto de vista de reusabilidad sería crear un control que herede de NumericUpDown y ya implemente de por si este comportamiento; que a mi entender es una falta de parte del equipo que desarrolló el control.

8 jun 2009

Deshabilitar el Cortar / Copiar de líneas vacías en Visual Studio

Un comportamiento muy molesto de Visual Studio es cuando por error copias o cortas una línea vacía, o sin seleccionar nada... hasta hace un tiempo pensaba que era el comportamiento normal del IDE, pero un día hurgando en la ventana de opciones me encontré con que se puede desactivar.

Evitar copiar sin seleccionar en Visual Studio

7 may 2009

Extendiendo la clase List(Of T)

Hoy necesité exportar el contenido de una Lista a un DataTable, entonces pensé:


  1. Crear una tabla con la estructura necesaria

  2. Recorrer la lista secuencialmente y agregar filas a la tabla


Pero pensando como programador, se me ocurrió que seguramente volviera a necesitar esta función y posiblemente la necesitaría con diferentes tipos de listas.

Como era lógico, pensé en Generics, entonces me creé una función que recibe una System.Collections.Generic.List(Of T) y devuelve un System.Data.DataTable con la siguiente firma:

Public Function ListToDataTable(Of T)(List As System.Collections.Generic.List(Of T)) As System.Data.DataTable

después creé toda la lógica utilizando System.Reflection para examinar las propiedades, y aprovechando los CustomAttributes para poder ocultar propiedades, entonces para hacer un Test, hice una clase con la siguiente estructura:



Public Class MiClase

    Private mId As Integer
    Private mNombre As String
    Private mCantidad As Integer

    <System.ComponentModel.Browsable(False)> _
    Public Property Id() As Integer
        Get
            Return mId
        End Get
        Set(ByVal value As Integer)
            mId = value
        End Set
    End Property

    Public Property Nombre() As String
        Get
            Return mNombre
        End Get
        Set(ByVal value As String)
            mNombre = value
        End Set
    End Property

    Public Property Cantidad() As Integer
        Get
            Return mCantidad
        End Get
        Set(ByVal value As Integer)
            mCantidad = value
        End Set
    End Property

    Public Sub New()

    End Sub

    Public Sub New(ByVal Id As Integer, ByVal Nombre As String, ByVal Cantidad As Integer)
        mId = Id
        mNombre = Nombre
        mCantidad = Cantidad
    End Sub

End Class


como ven, la propiedad Id tiene un CustomAttribute, el System.ComponentModel.BrowsableAttribute seteado con el valor False, o sea que esa propiedad estaría excluida de la exportación.

Todo muy lindo, funcionó a la perfección... pero se me ocurrió algo mejor... usar Extension Methods o métodos de extensión, esa nueva posibilidad que nos brinda el .Net Framework 3.5 de extender clases sin la necesidad de tener el código fuente de la misma.

Usando extension methods sobre la clase System.Collections.Generic.List(Of T)

Entonces creé un módulo llamado ListExtension y le asigné el mismo Namespace de la lista, System.Collections.Generic.



Imports System.Reflection
Imports System.ComponentModel
Imports System.Runtime.CompilerServices

Namespace System.Collections.Generic
    Module ListExtension
        ''' <summary>
        ''' Gets a Datatable with all Browsable properties of T as columns containing all Items in the List.
        ''' </summary>
        ''' <typeparam name="T"></typeparam>
        ''' <param name="List">System.Collections.Generic.List(Of T)</param>
        ''' <returns>System.Data.DataTable</returns>
        ''' <remarks>http://aprendiendonet.blogspot.com</remarks>
        <Extension()> _
        Public Function ToDataTable(Of T)(ByVal List As List(Of T)) As DataTable
            Dim dt As New DataTable()

            Dim tipo As Type = GetType(T)
            Dim members As MemberInfo() = tipo.GetMembers() ' Obtenemos todos los Miembros de la clase correspondiente al tipo T

            For Each m As MemberInfo In members
                If m.MemberType = MemberTypes.Property Then ' Sólo nos interesan las propiedades
                    Dim skip As Boolean = False

                    Dim atts As Object() = m.GetCustomAttributes(GetType(BrowsableAttribute), False) ' Chequeamos si tiene BrowsableAttribute
                    If atts.Length > 0 Then
                        If CType(atts(0), BrowsableAttribute).Browsable = False Then
                            skip = True ' Seteamos un flag para no agregar la columna
                        End If
                    End If

                    If Not skip Then
                        Dim c As DataColumn = Nothing
                        Try
                            c = New DataColumn(m.Name, CType(m, PropertyInfo).PropertyType) ' Nueva columna con el nombre de la propiedad y el tipo de la misma
                        Catch ex As Exception
                            c = New DataColumn(m.Name, GetType(String)) ' En caso de error intento crearla como String
                        End Try
                        dt.Columns.Add(c)
                    End If
                End If
            Next

            For Each itm As T In List ' Recorro la lista y agrego una fila por cada item de la misma
                Dim r As DataRow = dt.NewRow()
                For Each c As DataColumn In r.Table.Columns
                    Dim aux As MemberInfo() = tipo.GetMember(c.ColumnName)
                    If aux.Length > 0 Then
                        r(c.ColumnName) = CType(aux(0), PropertyInfo).GetValue(itm, Nothing)
                    End If
                Next
                dt.Rows.Add(r)
            Next

            Return dt
        End Function

    End Module
End Namespace


Entonces ahora en toda mi solución tengo la posibilidad de exportar mis Listas a DataTable con tan solo llamar a este método de extensión:

Dim auxDT as DataTable = miLista.ToDataTable()

29 abr 2009

Como dejar un log en el Visor de Sucesos de Windows


Todos hemos visto el Visor de Sucesos de Windows, y a veces es una buena alternativa para guardar registros de nuestras aplicaciones, ya que nos evita el tener que definirnos una estructura de logs.

Suele ser muy útil cuando desarrollamos un Servicio de Windows y queremos llevar registro de excepciones o ciertas situaciones... por eso el ejemplo de hoy se trata de crear un log para nuestra aplicación utilizando la clase EventLog del Namespace System.Diagnostics.


Public Sub EscribirEventLog(ByVal Origen As String, ByVal Mensaje As String, ByVal Equipo As String, ByVal TipoDeEntrada As EventTipoDeEntrada)
If Not EventLog.SourceExists(Origen, Equipo) Then ' Si el origen no existe lo creamos
EventLog.CreateEventSource(Origen, "GNSys", Equipo)
End If

Dim eLog As New EventLog("GNSys", Equipo, Origen) ' Instanciamos la clase EventLog
eLog.WriteEntry(Mensaje, TipoDeEntrada, GetSafeShort(111), GetSafeShort(1)) ' Escribimos la entrada
End Sub




En el código anterior, (que por cierto es muy sencillo), en la línea que escribe nuestra entrada de log hay datos que deberemos definir en función de nuestras necesidades, veamos la línea y cómo está formada:

eLog.WriteEntry([Event], LogEntryType, GetSafeShort(111), GetSafeShort(1))

La firma del método WriteEntry es la siguiente:

Public Shared Sub WriteEntry(ByVal source As String, ByVal message As String, ByVal type As System.Diagnostics.EventLogEntryType, ByVal eventID As Integer, ByVal category As Short)

Viendo la siguiente imágen se puede ver qué es cada campo.

Detalles de una entrada en el Visor de Sucesos

28 abr 2009

Como leer y escribir en el Registro de Windows desde una aplicación .NET

Para trabajar sobre el registro de Windows utilizaremos las cases Registry y RegistryKey del Namespace Microsoft.Win32. Con éstas 2 clases podremos realizar todas tareas de lectura y escritura en el registro.
Este es un ejemplo muy sencillo, por lo tanto vamos a crear una clave Key, dentro crearemos un valor Value luego los eliminaremos. Después leeremos todos los Values que se encuentren en HKLM\Microsoft\Windows\CurrentVersion\Run, que son los que indican qué aplicaciones se ejecutan al iniciar Windows para todos los usuarios.

Debajo de estas líneas está el código, uno de los ejemplos más sencillos para leer y escribir en el Registro de Windows.

Trabajar con el Registro de Windows en nuestra aplicación .NET


Imports Microsoft.Win32
Public Class Form1

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
CrearKey()
End Sub

Private Sub CrearKey()
Dim KeyPath As String = "Software\Test"
Registry.CurrentUser.CreateSubKey(KeyPath)
End Sub


Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
CrearValue()
End Sub

Private Sub CrearValue()
Dim KeyPath As String = "Software\Test"
Dim ValueName As String = "TestValue"

Dim key As RegistryKey = Registry.CurrentUser.OpenSubKey(KeyPath, True) ' True indica que se abre para escritura
If key IsNot Nothing Then ' Si key es Nothing significa que no se encontró
key.SetValue(ValueName, "Esto es una prueba", RegistryValueKind.String)
Else
If MessageBox.Show(String.Format("No se encontró la clave 'HKCU\{0}'. Desea crearla?", KeyPath), "", MessageBoxButtons.YesNo, MessageBoxIcon.Question) = Windows.Forms.DialogResult.Yes Then
CrearKey() ' Creamos la clave y volvemos a intentar crear el valor
CrearValue()
End If
End If
End Sub


Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
EliminarValue()
End Sub

Private Sub EliminarValue()
Dim KeyPath As String = "Software\Test"
Dim ValueName As String = "TestValue"

Dim Key As RegistryKey = Registry.CurrentUser.OpenSubKey(KeyPath, True)

If Key IsNot Nothing Then
If Key.GetValueNames().Contains(ValueName) Then ' Buscamos el nombre del valor en la lista de todos los valores de la clave
Key.DeleteValue(ValueName) ' Borramos el valor
Else
MessageBox.Show(String.Format("No se encontró el valor '{0}'.", ValueName))
End If
Else
MessageBox.Show(String.Format("No se encontró la clave 'HKCU\{0}'.", KeyPath))
End If
End Sub

Private Sub Button4_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button4.Click
EliminarKey()
End Sub

Private Sub EliminarKey()
Dim KeyPath As String = "Software\Test"

Dim key As RegistryKey = Registry.CurrentUser.OpenSubKey(KeyPath)

If key IsNot Nothing Then
Registry.CurrentUser.DeleteSubKey(KeyPath) ' Borramos la sub clave
Else
MessageBox.Show(String.Format("No se encontró la clave 'HKCU\{0}'.", KeyPath))
End If
End Sub


Private Sub Button5_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button5.Click
LeerRegistro()
End Sub

Private Sub LeerRegistro()
Dim KeyPath As String = "Software\Microsoft\Windows\CurrentVersion\Run"
Dim key As RegistryKey = Registry.LocalMachine.OpenSubKey(KeyPath, False) ' Abrimos para sólo lectura

If key IsNot Nothing Then
Dim sb As New System.Text.StringBuilder()

Dim values As String() = key.GetValueNames() ' Obtenemos los nombres de todos los valores en la key
For Each value As String In values
sb.AppendLine(String.Format("{0} > {1} ({2})", value, key.GetValue(value), key.GetValueKind(value).ToString()))
Next

Me.TextBox1.Text = sb.ToString() ' Mostramos el resultado en nuestra TextBox Multilínea
End If
End Sub
End Class


Registro de Windows - Aprendiendo.NET

9 mar 2009

Como imprimir un formulario - Microsoft.VisualBasic.PowerPacks.Printing.PrintForm

Este código muestra una forma sencilla de imprimir un formulario, para lo cual utilizaremos la clase PrintForm, que se encuentra en el Namespace Microsoft.VisualBasic.PowerPacks.Printing.

Lo primero que haremos será chequear si tenemos la referencia, para lo cual haremos click con el botón derecho sobre nuestro cuadro de herramientas y en el menú seleccionaremos la opción Choose Items..., cuando se abra el diálogo para seleccionar las referencias buscaremos la que corresponde al namespace antes mencionado y si no está seleccionada la seleccionaremos en este momento.

Microsoft.VisualBasic.PowerPacks.Printing.PrintForm

Puede ocurrir que no se muestre en el cuadro de herramientas, para poder verla haremos un click con el botón derecho sobre el cuadro de herramientas y en el menú seleccionaremos la opción Show All, que nos agregará varias secciones al cuadro de herramientas, la que buscamos se encuentra bajo el título de VisualBasic PowerPacks.

Ahora ya podemos arrastrar este componente a nuestro form y crear el siguiente método para poder imprimir el formulario:

    Private Sub Imprimir()
PrintForm1.PrintAction = Printing.PrintAction.PrintToPreview ' Crea una vista previa
' PrintForm1.PrintAction = Printing.PrintAction.PrintToFile ' Imprime a un archivo
' PrintForm1.PrintAction = Printing.PrintAction.PrintToPrinter ' Envía a la impresora
PrintForm1.Print() ' Finalmente hacemos la impresión
End Sub

27 feb 2009

Utilizando el portapapeles de Windows en nuestras aplicaciones .NET

Para manejar el portapapeles de Windows, el .Net Framework provee la clase Clipboard, del namespace My.Computerla cual posee todo lo necesario para copiar y pegar archivos, textos, imágenes, etc.


Veamos como copiar elementos al portapapeles:


  • My.Computer.Clipboard.SetImage(PictureBox1.Image) - Copia la imagen del picturebox

  • My.Computer.Clipboard.SetText(WebBrowser1.DocumentText, TextDataFormat.Html) - Copia el código HTML del documento que estamos mostrando en el WebBrowser como texto y setea el formato de éste como HTML.

  • My.Computer.Clipboard.SetText(RichTextBox1.Rtf, TextDataFormat.Rtf) - Ídem anterior pero formato RTF.

  • My.Computer.Clipboard.SetText(TextBox1.Text) - Copia un texto cualquiera, sin formato.

  • My.Computer.Clipboard.SetData(MyClassInstance.GetType().Name, MyClassInstance) - Copia el objeto MyClassInstance al portapapeles.



Ahora tenemos que recuperar los objetos que copiamos al portapapeles:


  • PictureBox2.Image = My.Computer.Clipboard.GetImage() - Recupera la imagen copiada al portapapeles y la setea como Image en el PictureBox2.

  • WebBrowser2.DocumentText = My.Computer.Clipboard.GetText(TextDataFormat.Html) - Obtiene el texto con formato HTML

  • RichTextBox2.Rtf = My.Computer.Clipboard.GetText(TextDataFormat.Rtf) - Idem anterior con formato RTF.

  • TextBox2.Text = My.Computer.Clipboard.GetText() - Recupera un texto sin formato y lo asigna en TextBox2.Text

  • Dim MyClassNewInstance As MyClass = CType(My.Computer.Clipboard.GetData(GetType(MyClass).Name), MyClass) - Recupera el objeto de tipo MyClass que copiamos anteriormente.



Para limpiar ó vaciar el portapapeles utilizaremos:


  • My.Computer.Clipboard.Clear()



Algunos controles que podemos hacer sobre la info contenida en el portapapeles:


  • If My.Computer.Clipboard.ContainsImage() Then - Para saber si hay una imagen en el portapapeles

  • If My.Computer.Clipboard.ContainsText(TextDataFormat.Html) - Para saber si el portapapeles contiene un texto en formato HTML

  • If My.Computer.Clipboard.ContainsData(GetType(MyClass).Name) Then - Comprueba si hay un objeto del tipo MyClass en el portapapeles.



Al preguntar por My.Computer.Clipboard.ContainsText(), se puede preguntar por varios formatos, los mismos se especifican en el Enum TextDataFormat:


  • CommaSeparatedValue

  • Html

  • Rtf

  • Text

  • UnicodeText



Y ese sería un resumen de los usos más frecuentes del portapapeles, aunque también se puede utilizar de varias maneras más, estas son las que consideré más útiles.

Una aclaración con respecto a copiar y pegar objetos, yo utilicé como nombre del formato el nombre del tipo tal cual se devuelve por GetType().Name, en ese parámetro se puede escribir cualquier String, pero considero una buena práctica utilizar el nombre del tipo para que al recuperar sepamos qué es lo que estamos buscando.

11 feb 2009

Trabajando con Archivos y Carpetas: System.IO.Path

La clase System.IO.Path provee una serie de métodos para realizar las tareas más comunes a la hora de trabajar con rutas de archivos o directorios, a continuación veremos los métodos de esta clase y para qué sirve cada uno.



  • System.IO.Path.AltDirectorySeparatorChar : Devuelve el caracter alternativo usado como separador de directorios en el sistema actual. Generalmente "/".

  • System.IO.Path.ChangeExtension("C:\prueba.txt", "xml") : Cambia la extensión del archivo pasado como primer parámetro, en este ejemplo devuelve C:\prueba.xml.

  • System.IO.Path.Combine("C:\Directorio1\", "prueba.xml") : Combina ambas rutas para generar una sola. Atención al segundo parámetro porque si empieza con el separador de directorio no funcionará como esperamos.

  • System.IO.Path.DirectorySeparatorChar : Devuelve el caracter usado como separador de directorios en el sistema actual. Generalmente "\".

  • System.IO.Path.GetDirectoryName("C:\Directorio1\prueba.txt") : Devuelve la ruta al directorio según la ruta que recibe por parámetro. En este ejemplo devuelve "C:\Directorio1"

  • System.IO.Path.GetExtension("C:\Directorio1\prueba.xml") : Devuelve la extensión del archivo que recibe por parámetro, por el ejemplo ".xml" si el archivo no tiene extensión devuelve "".

  • System.IO.Path.GetFileName("C:\Directorio1\prueba.xml") : Devuelve el nombre del archivo especificado en el parámetro sin el resto de la ruta. En este ejemplo devuelve "prueba.xml". Si la ruta especificada termina con el separador de directorios, devuelve "".

  • System.IO.Path.GetFileNameWithoutExtension("C:\Directorio1\prueba.xml") : Idem que GetFileName() pero sin extensión. En el ejemplo "prueba"

  • System.IO.Path.GetFullPath("C:") Devuelve la ruta actual sobre la unidad C: Por ejemplo "C:\miApp\bin\Debug

  • System.IO.Path.GetFullPath("\prueba1") : Devuelve la ruta absoluta, toma en cuenta la unidad actual o la ruta actual.

  • System.IO.Path.GetInvalidFileNameChars() : Devuelve los caracteres que no pueden formar parte del nombre de un archivo

  • System.IO.Path.GetInvalidPathChars() : Devuleve los caracteres no válidos para una ruta.

  • System.IO.Path.GetPathRoot("C:\Directorio1\prueba.xml") : Devuelve la raíz de la ruta especificada, en este caso "C:\"

  • System.IO.Path.GetRandomFileName() : Devuelve un nombre randómico para usar como nombre de archivo o directorio.

  • System.IO.Path.GetTempFileName() : Devuelve un nombre de archivo temporal, apuntando al directorio especificado en %TEMP%. Por ejemplo "C:\Documents and settings\usuario\Configuración local\Temp\tmp131E.tmp"

  • System.IO.Path.GetTempPath() : Devuelve la ruta al directorio temporal, siguiendo con el ejemplo anterior, "C:\Documents and settings\usuario\Configuración local\Temp\"

  • System.IO.Path.HasExtension("C:\prueba.xml") : Devuelve un valor Boolean indicando si la ruta especificada contiene una extensión, en el ejemplo la extensión es ".xml" o sea que devuelve True

  • System.IO.Path.IsPathRooted("..\Directorio1\prueba.xml") : Devuelve un valor Boolean indicando si la ruta especificada es absoluta o no, en el ejemplo la ruta es relativa por lo que devuelve False

  • System.IO.Path.PathSeparator : Devuelve el separador de rutas, generalmente ";"

  • System.IO.Path.VolumeSeparatorChar : Devuelve el caracter separador de volúmenes, generalmente ":"


Estos son todos los miembors de la clase System.IO.Path con una breve descripción de cada uno.

6 feb 2009

Problema al crear un WebService: Failed to access IIS metabase - SOLUCIONADO

Intentando crear un WebService con C# me encontré con que cada vez que intentaba ejecutarlo IIS me devolvía el siguiente error: Failed to access IIS metabase problem.

Busqué por acá y por alla, descargué un código VBS pero nada... después de probar las mil y una soluciones encontré la solución definitiva, así que decidí publicarla aquí para tenerla siempre a mano y de paso le puede servir a alguien más.

La solución consiste en abrir una consola, ir al directorio de instalación del Framework, 2.0 en este caso y ejecutar un comando que hará una reinstalación de ASP.Net



C:\> cd WINDOWS\Microsoft.NET\Framework\v2.0.50727

C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\> aspnet_regiis.exe -i

Start installing ASP.NET (2.0.50727).
......................
Finished installing ASP.NET (2.0.50727).

C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\>



16 ene 2009

MethodInvoker: un delegado simple integrado en el framework

Muchas veces necesitamos hacer un Invoke, para las veces que necesitamos invocar un método simple, sin parámetros podemos usar el delegado MethodInvoker, que no es más que un Delegate sub sin parámetros:

Public Delegate Sub MethodInvoker()

O sea que si tenemos que utilizarlo podríamos por ejemplo ahcer lo siguiente:

Dim d as MethodInvoker = New MethodInvoker(AddressOf MyProcedimiento)


Simplemente un tip, que me fue útil, ya que hasta que lo encontré declaraba mi propio delegate.

14 ene 2009

101 Ejemplos de LINQ en VB.Net

Un muy buen recurso para aprender a dominar esta gran tecnología, tiene ejemplos de LINQ para SQL, Dataset, XML y Objetos, todos con código fácil de comprender.

Sin duda es un enlace que vale la pena tener a mano.



Enlace: http://msdn.microsoft.com/es-es/vbasic/bb688088(en-us).aspx