Grabar un imagen ISO a un DVD nativamente con Windows 7

Post original en JASoft.org: http://www.jasoft.org/Blog/post/Grabar-un-imagen-ISO-a-un-DVD-nativamente-con-Windows-7.aspx

La verdad es que hace años que no utiliza una grabadora de CD o DVD. Mi portátil ultra-ligero ni siquiera trae una incorporada, así que tengo una externa USB que utilizo muy de vez en cuando para leer algún CD o DVD que me hacen llegar. El resto del tiempo uso llaves USB, pero desde hace años utilizo Dropbox y por lo tanto prácticamente ni eso.

Ayer iba a instalar un Ubuntu en un portátil viejo que tengo que quiero regalar, e intenté hacerlo desde una llave USB con el famoso Universal USB Installer que ellos mismos promocionan. El resultado fue una llave USB estupenda de las rápidas estropeada para siempre. No sé qué demonios hace ese programa pero literalmente me fundió la llave USB. No fui capaz de recuperarla ni con herramientas de bajo nivel ni en Windows ni en Linux. Un fastidio.

Así que no me quedó más remedio que grabar un CD con la última versión de Ubuntu para poder instalarlo en el equipo viejo. El caso es que como utilizo la unidad de DVD para grabar no tenía a mano ningún software ni me apetecía tampoco instalar uno sólo para eso.

Resulta que, por fortuna, Windows 7 trae instalado de serie una utilidad poco conocida que permite grabar directamente a un CD o un DVD cualquier imagen en formato .ISO que tengamos.

Para ello, en una instalación por defecto lo único que tenemos que hacer es pulsar con el botón derecho del ratón sobre un archivo .iso y nos dará la opción de grabarlo a un CD o DVD:

grabarISO_1

Esta es la teoría. En la práctica no suele ser así. El motivo es que si tienes cualquier programa al que se haya asociado la extensión .iso, entonces esta opción dejará de estar disponible.

Yo, por ejemplo, tengo siempre instalado el mejor compresor del mundo, 7-ZIP, y lo asocio con este tipo de archivos porque me deja inspeccionar su contenido fácilmente, pero hay muchos otros programas por ahí que si quieres se relacionan con la extensión. por ejemplo, Virtual CloneDrive, otro de los clásicos que instalo de inmediato en todos mis equipos.

No obstante conseguir que funcione la utilidad de grabación de ISO a disco es muy sencillo incluso en ese caso. Basta con usar la opción «Abrir con» y ahí está:

grabarISO_2

Pulsa para aumentar

Al hacerlo se nos ofrecerá el diálogo de grabación del disco en el que podremos elegir la unidad de destino y si queremos verificar los contenidos grabados al terminar:

grabarISO_3

Más fácil imposible. Pulsamos en «Quemar» y se pone a ello:

grabarISO_4

Uso desde línea de comandos

La utilidad se puede lanzar también desde la línea de comandos ya que es un ejecutable que se encuentra en la carpeta CWindowsSystem32 o equivalente, y se llama IsoBurn.exe:

grabarISO_5

Pulsa para aumentar

Como vemos la sintaxis es muy sencilla y tiene un modificador /Q para hacerlo de modo silencioso.

¡Espero que te sea útil!

Todo sobre AutoEventWireUp en páginas ASP.NET Web Forms

Post original en JASoft.org: http://www.jasoft.org/Blog/post/Todo-sobre-AutoEventWireUp-en-paginas-ASPNET-Web-Forms.aspx

En la directiva de página de los Web Forms de ASP.NET existe un atributo importante denominado AutoEventWireUp. Por defecto está establecido como True. Esto quiere decir que la infraestructura de la página se encargará automáticamente de enlazar los eventos de la página con aquellos métodos definidos en ésta que tengan los nombres y las firmas apropiados.

Por ejemplo, si tenemos un método definido de esta manera:

   1: private void Page_Load(object sender, System.EventArgs e)

   2: {

   3:  

   4: }

Se llamará de manera automática al cargar la página (evento Load del ciclo de vida de la página).

Lo mismo en Visual Basic:

   1: Public Sub Page_Load(ByVal Sender As System.Object, ByVal e As System.EventArgs)

   2:  

   3: End Sub

CablesEstos métodos tiene la misma firma que un evento estándar de tipo EventHandler, es decir, no devuelven nada y toman como parámetros un objeto y un objeto de tipo EventArgs. Su nombre es Page_ seguido del nombre del evento del ciclo de vida de la página que queremos capturar: Init, PreLoad, Load, Render, etc…

Es muy cómodo y nos facilita la vida.

Pero ¿qué pasa si establecemos AutoEventWireUp a False?

Esto desactiva la conexión automática entre los eventos y los métodos Page_, por lo tanto nos dejarán de funcionar todos ellos y no responderán la carga de la página, el gestor de errores, etc…

Para que vuelvan a funcionar tendremos que hacer más trabajo manual.

En el caso de Visual Basic es muy fácil por que lo único que tendremos que hacer es sacar partido a la claúsula Handles e indicar con ella a qué evento responde cada método de los que tenemos definidos. Así que, en el ejemplo del evento de carga de la página, con añadir Handles Me.Load al final de su definición ya estará listo:

   1: Public Sub Page_Load(ByVal Sender As System.Object, ByVal e As System.EventArgs) Handles Me.Load

   2:  

   3: End Sub

Y lo mismo con los demás métodos. Muy fácil. Además el propio Visual Studio nos ayudará mucho con ello ya que nos ofrece una lista desplegable con los nombres de los eventos de la página y define cada uno de ellos por nosotros de manera automática.

En el caso de C# la cosa es un poco más complicada ya que tendremos que sobrescribir el métodos OnInit de la página, que se llama al inicializar la página por parte de la infraestructura de ASP.NET, y en éste debemos asignar manualmente un manejador para cada evento que nos interese.

Así,  para nuestro ejemplo para la carga de la página, lo asignaríamos a la función anterior sobrescribiendo el método OnInit, así:

   1: override protected void OnInit(EventArgs e)

   2: {

   3:     this.Load += new System.EventHandler(this.Page_Load);

   4: }

Lo  mismo haríamos con otros posibles eventos a controlar en el ciclo de vida de la página.

Es sencillo pero más tedioso.

¿Por que querríamos desactivar AutoEventWireUp?

Bueno, en condiciones normales no nos interesa hacer esto ya que como hemos visto nos facilita la vida un poco. Sin embargo usar esta característica tiene como contrapartida que perdemos un poco de rendimiento, ya que la infraestructura de página debe usar reflexión y además llamar al método CreateDelegate para asignar dinámicamente el evento. Esto no es demasiado importante en términos de rendimiento en cualquier sitio normal, pero si nuestra aplicación va a estar sometida a cargas muy grandes de usuarios, y nos interesa sacarle el máximo rendimiento para hacerla muy escalable, cualquier pequeña optimización ayuda.

Por lo tanto en esos casos puede que nos interesa desactivar el enlazado automático de eventos de página.

Podemos hacerlo en la propia página usando la directiva de página @page:

   1: <% @Page AutoEventWireup="false" %>

Si queremos deshabilitarlo para toda la aplicación o para una carpeta completa en concreto podemos utilizar también el archivo de configuración web.config, en concreto la sección pages del mismo:

   1: <configuration>

   2:    <system.web>

   3:       <pages autoEventWireup="false" />

   4:    </system.web>

   5: </configuration>

Con esto quedará deshabilitado para todas las páginas influidas por el web.config en cuestión (toda la aplicación si está en el raíz o una carpeta y sus subcarpetas si está dentro de algún directorio).

Un detalle importante: AutoEventWireUp funciona no sólo para las páginas ASPX sino también con los controle de usuario (ASCX) que tengamos, así que tenlo en cuenta también en éstos.

¡Espero que te resulte útil!

¿Te ha gustado este post? – Aprende .NET con los cursos on-line tutelados de campusMVP:
   ·
Preparación del examen 70-515: Desarrollo Web con .NET 4.0 (Tutelado por mi)
   · Desarrollo Web con ASP.NET 4.0 Web Forms (Tutelado por mi)
   · ASP.NET 4.0 Web Forms desde cero (Tutelado por mi)
   · Desarrollo Web con ASP.NET MVC 3 
   · Silverlight 4.0 – Aplicaciones Ricas para Internet (RIA)
   · jQuery paso a paso para programadores ASP.NET
   · Visual Studio 2010 desde cero

Catálogos de WebParts Dinámicos

WebpartsNOTA: Estas técnicas no están documentadas y se basan en mis indagaciones sobre cómo conseguir crear catálogos dinámicos de WebParts. Todo surgió a raíz de la pregunta de un alumno de mi curso de preparación del examen de certificación 70-515 de ASP.NET.

¿Cómo puedo crear un catálogo de WebParts para una página personalizada al cual le pueda añadir yo los controles que quiera dinámicamente?. Es decir, que los controles que aparecerán en el catálogo en lugar de estar determinados de antemano como en los casos habituales (en un catálogo estático de WebParts), se puedan cargar desde una base de datos o similar.

La solución

Primero, para esto hay que crear nuestra propia clase plantilla de catálogo que es la que se encargará de contener a los controles que voy a ir añadiendo. Esta clase debe implementar la interfaz ITemplate. Ello implica implementar el método InstantiateIn de esta interfaz que será llamado por la infraestructura de página cuando se deba inicializar el catálogo. Es en ese momento cuando se deben añadir los controles que deseemos a la colección de controles de la plantilla.

Dado que no tenemos forma de añadirlos desde este método tendremos que definir una colección de controles para almacenarlos temporalmente y añadirlos antes de esa instanciación. Después en la inicialización los añadiremos a la colección de controles real de la plantilla. En definitiva el código de esta clase queda así (en VB):

   1: Public Class miPlantillaDeCatalogo

   2:   Implements ITemplate

   3:  

   4:   Private _controles As New Collection()

   5:  

   6:   Public Sub InstantiateIn(ByVal container As System.Web.UI.Control) 

   7:     Implements System.Web.UI.ITemplate.InstantiateIn

   8:     If _controles.Count > 0 Then

   9:       Dim ctl As Control

  10:       For Each ctl In _controles

  11:         container.Controls.Add(ctl)

  12:       Next

  13:     End If

  14:   End Sub

  15:  

  16:   'Expongo la propiedad Controls

  17:   Public ReadOnly Property Controls() As Collection

  18:     Get

  19:       Return _controles

  20:     End Get

  21:   End Property

  22: End Class

Luego entenderemos mejor su funcionamiento.

De acuerdo. Los controles catálogo están contenidos en controles de zona. Éstos son también plantillas que se usan simplemente para mostrar los catálogos. A su vez estos controles de zona están contenidos en controles de tipo CatalogZone que son los que podemos arrastrar y soltar desde la barra de herramientas de ASP.NET.

Sabiendo esto debemos crear un control de zona personalizado que nos permita contener al catálogo antes definido. Al igual que antes tenemos que implementar la interfaz ITemplate, y como antes tampoco tenemos forma de indicar en la inicialización qué catálogo vamos a usar, por lo que tendremos que establecerlo mediante una propiedad personalizada. El código de la clase queda así:

   1: Public Class MiPlantillaDeZona

   2:   Inherits WebPart

   3:   Implements ITemplate

   4:  

   5:   Private _catalogo As miPlantillaDeCatalogo

   6:  

   7:   Public Property Catalogo() As miPlantillaDeCatalogo

   8:     Get

   9:       Return _catalogo

  10:     End Get

  11:     Set(ByVal value As miPlantillaDeCatalogo)

  12:       _catalogo = value

  13:     End Set

  14:   End Property

  15:  

  16:   Public Sub InstantiateIn(ByVal container As System.Web.UI.Control) 

  17:      Implements System.Web.UI.ITemplate.InstantiateIn

  18:     Dim dcp As New DeclarativeCatalogPart()

  19:     dcp.WebPartsTemplate = _catalogo

  20:     dcp.ID = "Mi catálogo"

  21:     dcp.Title = "Catálogo personalizado"

  22:     container.Controls.Add(dcp)

  23:   End Sub

  24: End Class

Como vemos lo que se hace es exponer una propiedad para almacenar el catálogo que queremos usar, y luego durante la inicialización de la plantilla, lo añadimos a los controles de ésta.

Ahora ya tenemos todo lo de base que necesitamos. Nos falta añadir controles a nuestro catálogo y asociarlo a un control CatalogZone que ya tendremos previamente en la página. Podemos hacerlo por ejemplo en el evento Load del formulario Web:

   1: Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs)_ 

   2:    Handles Me.Load

   3:   Dim tmpl As New miPlantillaDeCatalogo()

   4:   Dim wp1 As New MiWebpart()

   5:   wp1.ID = "Usuario actual WP"

   6:   tmpl.Controls.Add(wp1)

   7:   Dim mpz As New MiPlantillaDeZona()

   8:   mpz.Catalogo = tmpl

   9:   CatalogZone1.ZoneTemplate = mpz

  10: End Sub

Como vemos lo que se hace es instanciar un catálogo personalizado. Luego se instancia el control Webpart que queremos añadir al catálogo y se añade a la colección de controles del catálogo. Se crea nuestra plantilla de zona personalizada, asignándole el catálogo para su correcta inicialización. Finalmente se asigna esta zona como plantilla de zona para el control catálogo de la página, que es el que se encarga de gestionar la infraestructura subyacente para poder añadir los controles.

Por cierto, es necesario ponerle un identificador al Webpart o romperá la aplicación.

Controles de servidor

El código anterior funciona bien si lo que tenemos en el catálogo son controles que heredan de Webpart y por lo tanto son Webarts "puras". Pero ¿qué pasa si quiero añadir a mi catálogo personalizado controles de servidor normales (que no son webParts) o incluso controles de usuario (que tampoco son Webparts)?.

La infraestructura de Webparts de ASP.NET usa la clase GenericWebpart para envolver este tipo de controles y poder utilizarlos, pero nosotros no lo tenemos tan fácil para usar esto directamente, así que para conseguirlo he tenido que hacer también mucha prueba y error. El resultado es el siguiente:

   1: Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) _

   2:     Handles Me.Load

   3:   Dim tmpl As New miPlantillaDeCatalogo()

   4:   Dim wp1 As GenericWebPart

   5:   Dim uc1 As UserControl

   6:   uc1 = LoadControl("~/usuarioActual.ascx")

   7:   uc1.ID = "uc1"

   8:   uc1.Attributes.Add("Title", "Usuario actual")

   9:   wp1 = WebPartManager1.CreateWebPart(uc1)

  10:   wp1.ID = "Usuario actual UC"

  11:  

  12:   tmpl.Controls.Add(wp1)

  13:   Dim mpz As New MiPlantillaDeZona()

  14:   mpz.Catalogo = tmpl

  15:   CatalogZone1.ZoneTemplate = mpz

  16: End Sub

En este caso la cosa se complica un poco.

Lo primero es instanciar el control que queremos usar. En mi caso he usado un control de usuario que se limita a mostrar el nombre del usuario actual. Para ello usamos el método LoadControl de la página. Ahora nos toca envolver ese control en un Webpart genérico. Pero para ello no podemos usar el constructor de esta clase, que es lo que hace ASP.NET por debajo, ya que éste es interno y protegido. Así que tenemos que usar el método CreateWebPart del WebPartManager que tengamos en la página. Para ello antes, hay que asignarle un identificador al control u obtendremos un error. Además le añadiremos un atributo "Title" con la descripción que queremos que aparezca en el catálogo (esta última me costó mucho Reflector para llegar a ella), o de otro modo el usuario no sabrá distinguir unos controles de otros en el catálogo.

Una vez creado el Webpart genérico es necesario asignarle un identificador, y ya podemos añadirlo a nuestro catálogo personalizado y proceder como antes.

¡Espero que te sea útil!

No se puede quitar Facebook de mi Windows Phone: ¿cómo arreglarlo?

Post original en JASoft.org: http://www.jasoft.org/Blog/post/No-se-puede-quitar-Facebook-de-mi-Windows-Phone-191;como-arreglarlo.aspx

Windows Phone es sin duda el mejor sistema operativo móvil si eres un usuario intensivo de las redes sociales más conocidas, es decir, Facebook, Twitter y LinkedIn. El motivo es que Windows Phone 7.5 "Mango" se integra por completo con éstas y las incorpora como ciudadano de primera al resto del teléfono.

live-tilesAsí, por ejemplo, tus contactos de LinkedIn o Facebook aparecen en tu agenda y los consolida de forma que toda la información que posees de cada contacto en cada red social y en tu agenda se muestra de manera unificada. Además puedes seguir las actualizaciones de gente concreta o grupos de gente concreta directamente desde la agenda o, mejor aún, colocándolos como "tiles" o ladrillos en tu página principal. Yo por ejemplo tengo un grupo formado por mi gente más cercana (familiares y amigos) y en su "Live Tile" me aparece automáticamente información sobre qué están haciendo o si comentan algo de interés tanto en Twitter, Facebook como LinkedIn. En el mismo lugar se me notifica si me acaban de enviar un correo o si tengo una llamada perdida. No tengo ni que entrar a verlo pues me sale directamente en el ladrillito. Además en el caso de facebook su chat se integra con la mensajería del teléfono por lo que siempre tienes a tus amigos a un clic para hablar con ellos (si quieres, claro).

Por desgracia una limitación del teléfono es, en mi opinión, no poder hacer capturas de pantalla, así que no puedo enseñártelo en acción en mi teléfono, pero te dejo este vídeo para que veas de qué va el asunto.

Otro problema es que el otro día de repente dejaron de funcionarme los "Live Tiles" y no recibía actualizaciones en los ladrillitos. No sé todavía a qué fue debido pero me puse en contacto con el soporte de Windows Phone en Twitter y les conté mis penas para que me ayudaran. Me dijeron que quitara todas las cuentas de redes sociales y que las volviera a añadir pero dejando LinkedIn de última. Sospecho que saben que LinkedIn de vez en cuando da algún problema, y debe de haber un bug que hace que no se ejecuten el resto de notificaciones. Así que ya sabes: si añades cuentas a tu Windows Phone deja siempre LinkedIn para el final.

El caso es que las quité y todo volvió a funcionar de maravilla, aunque fue un fastidio porque se tarda un rato si, como yo, tienes miles de contactos en la agenda.

La cuestión es que logré quitar sin problema mi cuenta de Twitter y la de LinkedIn, pero a la hora de quitar la la de Facebook todo el tiempo obtenía un error que decía que era imposible quitar la cuenta de Facebook y que lo intentara de nuevo. Tras reiniciar el terminal varias veces, blasfemar un poco y buscar en Internet infructuosamente, encontré la solución. Y ésta no era precisamente directa.

Si te encuentras con este problema haz lo siguiente:

1.- Navega a www.live.com y autentícate con la misma cuenta que hayas usado para el teléfono.

2.- Pulsa el enlace de "Perfil" que aparece debajo de tu nombre en Live:

Live_Perfil

3.- En la columna del lateral izquierdo encontrarás una columna con algunas de las conexiones que tienes en tu cuenta, básicamente Live Messenger (que siempre está) y otras redes sociales como Facebook o Twitter:

Live_Conexiones

Pulsa en "Gestionar" ("Manage" en la figura, ya que tengo Live en inglés) y te aparecerán todas las conexiones que tengas:

Live_Conexiones_Editar

4.- Pulsa en editar la conexión de Facebook:

Live_Facebook_Quitar

5.- Usa el enlace de la parte inferior para quitar la conexión por completo. Al cabo de unos segundos verás el resto de cuentas conectadas y un mensaje que dice que la cuenta de Facebook ha sido quitada:

Live_Facebook_Quitada

6.- Reinicia tu teléfono.

7.- En el teléfono vete a Configuración·Cuentas y pulsa un segundo con el ´dedo sobre tu cuenta de Live (la que usas para trabajar con el teléfono). En el menú contextual elige la opción de sincronizar. Al hacerlo se detectará el cambio que hiciste en la cuenta de Live.

8.- Pulsa con el dedo un segundo en la cuenta de Facebook hasta que salga el menú contextual y elige la opción de eliminarla.

Ahora debería quitarse sin problemas.

¡Espero que te sea útil!