<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;DU8FQ387eyp7ImA9WxBUGUU.&quot;"><id>tag:blogger.com,1999:blog-5754664854663769426</id><updated>2010-03-07T19:50:12.103+01:00</updated><title>Crazy Pointer</title><subtitle type="html">Blog sobre desarrollo de videojuegos, programación y tecnología.</subtitle><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://www.crazypointer.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://www.crazypointer.com/" /><link rel="next" type="application/atom+xml" href="http://www.blogger.com/feeds/5754664854663769426/posts/default?start-index=26&amp;max-results=25&amp;redirect=false&amp;v=2" /><author><name>Ricky</name><uri>http://www.blogger.com/profile/18324470751965509112</uri><email>rickyah@gmail.com</email></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>50</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/CrazyPointer" /><feedburner:info uri="crazypointer" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><geo:lat>43.5411111</geo:lat><geo:long>-5.6644444</geo:long><link rel="license" type="text/html" href="http://creativecommons.org/licenses/by-sa/2.5/" /><logo>http://rickyah.googlepages.com/CrazyPointer_favicon.png</logo><entry gd:etag="W/&quot;Dk8ERH0_cCp7ImA9WxJVGUw.&quot;"><id>tag:blogger.com,1999:blog-5754664854663769426.post-5674627388056971987</id><published>2009-07-06T23:09:00.001+02:00</published><updated>2009-07-06T23:13:25.348+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-07-06T23:13:25.348+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Nocturnal" /><category scheme="http://www.blogger.com/atom/ns#" term="C++" /><title>Nocturnal Initiative Events (1/2): Introducción</title><content type="html">&lt;p&gt;En la siguiente mini-serie de entradas estudiaremos la implementación de un sistema de Eventos en C++ que ha seguido el código de Nocturnal&lt;/p&gt;  &lt;h2&gt;Introducción Eventos&lt;/h2&gt;  &lt;p&gt;En este caso concreto, por evento me refiero a una implementación del patrón Observer: &lt;a href="http://lh5.ggpht.com/_y5KbcXiMsPA/SlJoGzvHGBI/AAAAAAAAAYI/EcDQcJlL6ew/s1600-h/observer%20pattern%5B2%5D.png"&gt;&lt;img title="Observer Pattern (tamaño original)" style="border-top-width: 0px; display: block; border-left-width: 0px; float: none; border-bottom-width: 0px; margin-left: auto; margin-right: auto; border-right-width: 0px" height="262" alt="Observer Pattern (tamaño original)" src="http://lh3.ggpht.com/_y5KbcXiMsPA/SlJoHrnGHkI/AAAAAAAAAYM/j8nC-m0GyBI/observer%20pattern_thumb%5B2%5D.png?imgmax=800" width="360" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;El patrón Observer define una relación uno-muchos entre objetos, de forma que un objeto (el sujeto, subject) envía una notificación a uno o varios objetos (los observadores, observer) cuando ocurre un cambio de estado en el subject. &lt;/p&gt;  &lt;p&gt;Para ello los observers han de registrarse previamente con el subject, para establecer que quieren ser notificados. Con este patrón evitamos que los observers tengan que realizar un pooling periódico para preguntarle al subject si ha cambiado su estado, y a la vez tenemos acceso al estado de los objetos observer, pues el código que se ejecuta cuando ocurre el cambio de estado es parte de los observers. &lt;/p&gt;  &lt;p&gt;¿Cómo implementar ésto en C++? Para responder a ésto, antes debemos sentar algunas bases.&lt;/p&gt;  &lt;h2&gt;Punteros a función&lt;/h2&gt;  &lt;p&gt;En C/C++ una implementación parcial del patrón observer se consigue con punteros a función. Un puntero a función es una variable que almacena un puntero a la dirección de memoria donde empieza una función, de forma que al llamar a la variable con la sintaxis de una función, se ejecuta aquella a la que apunta &lt;/p&gt;  &lt;pre class="c++" name="code"&gt;//Punteros a función en C/C++. &lt;br /&gt;&lt;br /&gt;//Puntero a función que recibe un entero como argumento y retorna un std::string&lt;br /&gt;(std::string) (*MyFunctionPointer) ( int entero);&lt;br /&gt;&lt;br /&gt;//definimos un par de funciones que cumplen la firma anterior&lt;br /&gt;std::string Funcion1(int integer)&lt;br /&gt;{&lt;br /&gt;	return &amp;quot;null&amp;quot;;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;std::string Funcion2(int integer)&lt;br /&gt;{&lt;br /&gt;	std::ostringstream oss;&lt;br /&gt;	oss &amp;lt;&amp;lt; integer;&lt;br /&gt;	return oss.Str();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;//Declaramos una variable que almacenará el puntero a la función que queramos&lt;br /&gt;MyFunctionPointer variableQueAlmacenaUnPunteroAFuncion;&lt;br /&gt;&lt;br /&gt;//asignamos el valor de Function1 al puntero a función&lt;br /&gt;variableQueAlmacenaUnPunteroAFuncion = Funcion1;&lt;br /&gt;&lt;br /&gt;//prints &amp;quot;null&amp;quot;&lt;br /&gt;std::cout &amp;lt;&amp;lt; variableQueAlmacenaUnPunteroAFuncion (5) &amp;lt;&amp;lt; std::endl;&lt;br /&gt;&lt;br /&gt;//asignamos el valor de Function2 al puntero a función&lt;br /&gt;variableQueAlmacenaUnPunteroAFuncion = Funcion2;&lt;br /&gt;&lt;br /&gt;//prints &amp;quot;5&amp;quot;&lt;br /&gt;std::cout &amp;lt;&amp;lt; variableQueAlmacenaUnPunteroAFuncion (5) &amp;lt;&amp;lt; std::endl;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Con los punteros a función sólo podemos almacenar una única función. Si quisieramos almacenar un conjunto de funciones, tendríamos que crear una lista de punteros. &lt;/p&gt;&lt;br /&gt;&lt;h2&gt;Punteros a Método&lt;/h2&gt;&lt;br /&gt;&lt;p&gt;El problema es que los punteros a función sólo pueden almacenar, bien funciones tradicionales C, o bien métodos estáticos de una clase. Esto sucede porque un método de una clase siempre tiene un parámetro oculto, el puntero this. Por ello en C++ existen los punteros a métodos: &lt;/p&gt;&lt;br /&gt;&lt;pre class="c++" name="code"&gt;class MiClase&lt;br /&gt;{&lt;br /&gt;	public:&lt;br /&gt;		int MiMetodo(int entero1, int entero2){return entero1 + entero2;}&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;//Puntero a método de la clase MiClase&lt;br /&gt;typedef int (MiClase::*MiPunteroAMetodo) (int entero1, int entero2);&lt;/pre&gt;&lt;br /&gt;Sin embargo una importante limitación es que para invocar un puntero a método, se requiere una instancia de la clase para la cual se ha definido el puntero a método: &lt;br /&gt;&lt;br /&gt;&lt;pre class="c++" name="code"&gt;MiPunteroAMetodo variableQueAlmacenaUnPunteroAMetodo = &amp;amp;MiClase::MiMetodo;&lt;br /&gt;MiClase* miClase = new MiClase();&lt;br /&gt;(miClase-&amp;gt;*variableQueAlmacenaUnPunteroAMetodo)(5, 5);&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Es decir, que necesitarmos guardar tanto la función método, como una instancia del objeto a la hora de implementar eventos en C++&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Delegados y Eventos en C#&lt;/h2&gt;&lt;br /&gt;&lt;p&gt;En C# tenemos la figura del delegate (delegado) que básicamente es lo mismo que un puntero a función y un puntero a miembro, ya que admite funciones y metodos de clase. A su vez permite &amp;quot;de serie&amp;quot;, el registrar varias funciones al mismo delegate, de forma que cuando éste es llamado, se ejecutan todas las funciones registradas, y no sólo una como ocurre con los punteros a función o los punteros a método de C/C++ Un evento en C#, no es más que un delegado ya instanciado y con una sintaxis especial. Por ello los eventos en C# son una implementación de libro del patrón observer. &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Para la siguiente entrada veremos cual ha sido la aproximación seguida en el código de Nocturnal para implementar eventos en C++.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5754664854663769426-5674627388056971987?l=www.crazypointer.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/CrazyPointer?a=tKoDvCpC4w4:48yG9uW4PYA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CrazyPointer?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CrazyPointer?a=tKoDvCpC4w4:48yG9uW4PYA:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CrazyPointer?i=tKoDvCpC4w4:48yG9uW4PYA:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CrazyPointer/~4/tKoDvCpC4w4" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.crazypointer.com/feeds/5674627388056971987/comments/default" title="Enviar comentarios" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=5754664854663769426&amp;postID=5674627388056971987" title="2 comentarios" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5754664854663769426/posts/default/5674627388056971987?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5754664854663769426/posts/default/5674627388056971987?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CrazyPointer/~3/tKoDvCpC4w4/nocturnal-initiative-events-12.html" title="Nocturnal Initiative Events (1/2): Introducción" /><author><name>Ricky</name><uri>http://www.blogger.com/profile/18324470751965509112</uri><email>rickyah@gmail.com</email><gd:extendedProperty name="OpenSocialUserId" value="10817153364417160719" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total><feedburner:origLink>http://www.crazypointer.com/2009/07/nocturnal-initiative-events-12.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkINRHc9fSp7ImA9WxJQF0s.&quot;"><id>tag:blogger.com,1999:blog-5754664854663769426.post-5244754608603695652</id><published>2009-05-31T13:16:00.000+02:00</published><updated>2009-05-31T13:16:35.965+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-05-31T13:16:35.965+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Opinion" /><title>Contrato NDA simple y sencillo</title><content type="html">&lt;b&gt;Contrato NDA  (No Divulges Amigo)&lt;/b&gt;&lt;br /&gt;
El presente acuerdo se realiza en el día  __ de ___ de ____,  reunidos_____________ (en adelante "El Consejero") y _____________ (en adelante "El Artífice" o "Yo") sobre el trato de la información (en adelante "La Idea") que El Artífice ha decidido compartir con El Consejero.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Exposición&lt;/b&gt;&lt;br /&gt;
El Artífice tiene una gran idea que elige compartir a El Consejero, con el conocimiento mutuo de que El Consejero es amigo de El Artífice y no le va a joder.&lt;br /&gt;
Posibilidades de jodienda incluyen, sin limitarse a:&lt;br /&gt;
1. Adaptar parte o toda La Idea por parte de El Consejero para propósitos propios.&lt;br /&gt;
&lt;br /&gt;
2. El Consejero comparte parte o toda La Idea con otros que no están adheridos a este contrato.&lt;br /&gt;
3. El Consejero no ha intentado con todas tus fuerzas proteger La Idea&lt;br /&gt;
&lt;br /&gt;
Esto es un acuerdo de buen rollo, donde al pedir a El Consejero que se adhiera al mismo, se espera que El Artífice consiga dormir con algo de tranquilidad por las noches al introducir un poco más de formalidad a la hora de compartir La Idea. El Artífice cree solemnemente que La Idea sólo podrá mejorar por medio de las opiniones honestas y sinceras de El Consejero.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Alcance&lt;/b&gt;&lt;br /&gt;
Los términos de este acuerdo continuarán hasta que La Idea no sea considerada confidencial por El Artífice.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Ruptura de los términos&lt;/b&gt;&lt;br /&gt;
Este acuerdo no tiene un ápice de base legal. Sin embargo, en caso de cualquier ruptura o violación del acuerdo, El Artífice será libre de realizar todas o parte de las siguientes acciones, sin limitarse exclusivamente a ellas:&lt;br /&gt;
1. Maldecir a El Consejero y posiblemente mentar a la Madre que lo Parió, o cualquier otro familiar cercano.&lt;br /&gt;
&lt;br /&gt;
2. Contarle a todo el mundo la manera en que el Consejero le ha jodido.&lt;br /&gt;
3. Escribir al respecto de la traición de El Consejero en el blog de El Artífice, y con MAYÚSCULAS.&lt;br /&gt;
4. Dejar de considerar a El Consejero como una persona en la que se le puede confiar a la hora de compartir información.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Compartir&lt;/b&gt;&lt;br /&gt;
El Consejero podrá compartir parte o toda La Idea con terceros, siempre que El Artífice sea previamente notificado y que dichos terceros se adhieran a los términos y principios de este acuerdo NDA.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Cancelación&lt;/b&gt; &lt;br /&gt;
La cancelación de este contrato puede realizarse unilateralmente por cualquiera de sus participantes, pero El Artífice espera que El Consejero no se comporte como un capullo.&lt;br /&gt;
&lt;br /&gt;
Comprendes y aceptas los términos de este acuerdo al leerlo. Si encuentras parte de este acuerdo incómodo o confuso, tampoco te preocupes mucho. Podemos hablar de otro tema.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Traducción libre de &lt;a href="http://www.friendda.org/"&gt;http://www.friendda.org/&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5754664854663769426-5244754608603695652?l=www.crazypointer.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/CrazyPointer?a=TebfKkuMdkw:boaDvmidCBI:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CrazyPointer?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CrazyPointer?a=TebfKkuMdkw:boaDvmidCBI:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CrazyPointer?i=TebfKkuMdkw:boaDvmidCBI:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CrazyPointer/~4/TebfKkuMdkw" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.crazypointer.com/feeds/5244754608603695652/comments/default" title="Enviar comentarios" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=5754664854663769426&amp;postID=5244754608603695652" title="0 comentarios" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5754664854663769426/posts/default/5244754608603695652?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5754664854663769426/posts/default/5244754608603695652?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CrazyPointer/~3/TebfKkuMdkw/contrato-nda-simple-y-sencillo.html" title="Contrato NDA simple y sencillo" /><author><name>Ricky</name><uri>http://www.blogger.com/profile/18324470751965509112</uri><email>rickyah@gmail.com</email><gd:extendedProperty name="OpenSocialUserId" value="10817153364417160719" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://www.crazypointer.com/2009/05/contrato-nda-simple-y-sencillo.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEcGSXg4fip7ImA9WxJRE0k.&quot;"><id>tag:blogger.com,1999:blog-5754664854663769426.post-7078712971404295993</id><published>2009-05-15T01:00:00.001+02:00</published><updated>2009-05-15T01:00:28.636+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-05-15T01:00:28.636+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="OpenSource" /><category scheme="http://www.blogger.com/atom/ns#" term="ProgrammingChallenges" /><category scheme="http://www.blogger.com/atom/ns#" term="GameProgramming" /><category scheme="http://www.blogger.com/atom/ns#" term="VideoGames" /><title>Gamelab 2009 inscripción abierta</title><content type="html">&lt;p&gt;La Feria Internacional del Ocio Interactivo, es decir, el &lt;a href="http://www.gamelab.es/"&gt;Gamelab 2009&lt;/a&gt; ya admite inscripciones, y hacerlo es tan sencillo como &lt;a href="http://www.gamelab.es/registrate/"&gt;registrarse en un formulario&lt;/a&gt;. Entre otras novedades este año el acceso es gratuito, lo que es de agradecer. Además el evento cambia de lugar, celebrándose esta vez en la &lt;a href="http://www.laboralciudaddelacultura.com/es"&gt;Universidad Laboral de Gijón&lt;/a&gt;, los días 1, 2 y 3 de Julio.&lt;/p&gt;  &lt;p&gt;Este año, además de los “tradicionales” &lt;a href="http://www.gamelab.es/eventos/premios-gamelab/"&gt;Premios a la industria del videojuego&lt;/a&gt;, hay un evento muy interesante, el &lt;a href="http://www.gamelab.es/eventos/gamelab-challenge/"&gt;Gamelab Challenge&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;El Gamelab Challenge es una competición para que un equipo de máximo 4 personas cree un juego en &lt;strike&gt;48 horas&lt;/strike&gt; dos días.&lt;/p&gt;  &lt;p&gt;Es interesante que el código de los proyectos se publicará con licencia libre, aunque la propiedad intelectual seguirá perteneciendo a los participantes.&lt;/p&gt;  &lt;p&gt;Seguro que se verán cosas muy interesantes, talento no falta. Además, si te inscribes además te pagan el alojamiento. :)&lt;/p&gt;  &lt;p&gt;Podéis estar al tanto de las últimas novedades por medio del &lt;a href="http://twitter.com/gamelab"&gt;twitter del Gamelab&lt;/a&gt;, ver las fotos del evento que se &lt;a href="http://www.flickr.com/photos/gamelab"&gt;irán publicando en Flickr&lt;/a&gt;, así como asistir virtualmente a las conferencias por medio del &lt;a href="http://www.youtube.com/user/gamelabconference"&gt;canal de youtube&lt;/a&gt;.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5754664854663769426-7078712971404295993?l=www.crazypointer.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/CrazyPointer?a=fFAtrfJnukc:WwHXt1GZo-U:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CrazyPointer?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CrazyPointer?a=fFAtrfJnukc:WwHXt1GZo-U:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CrazyPointer?i=fFAtrfJnukc:WwHXt1GZo-U:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CrazyPointer/~4/fFAtrfJnukc" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.crazypointer.com/feeds/7078712971404295993/comments/default" title="Enviar comentarios" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=5754664854663769426&amp;postID=7078712971404295993" title="0 comentarios" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5754664854663769426/posts/default/7078712971404295993?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5754664854663769426/posts/default/7078712971404295993?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CrazyPointer/~3/fFAtrfJnukc/gamelab-2009-inscripcion-abierta.html" title="Gamelab 2009 inscripción abierta" /><author><name>Ricky</name><uri>http://www.blogger.com/profile/18324470751965509112</uri><email>rickyah@gmail.com</email><gd:extendedProperty name="OpenSocialUserId" value="10817153364417160719" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://www.crazypointer.com/2009/05/gamelab-2009-inscripcion-abierta.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DE8MSXo7fyp7ImA9WxJTGUg.&quot;"><id>tag:blogger.com,1999:blog-5754664854663769426.post-7354627678430847039</id><published>2009-04-29T00:14:00.000+02:00</published><updated>2009-04-29T00:14:48.407+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-04-29T00:14:48.407+02:00</app:edited><title>Nuevo dominio para el blog</title><content type="html">Una corta entrada para estrenar el nuevo dominio del blog: http://www.crazypointer.com aprovechando el alta en &lt;a href="http://www.google.com/a/help/intl/es/index.html"&gt;Google Apps&lt;/a&gt;&lt;br /&gt;
Ahora a sacarle partido e intentar meter más de una entrada al mes :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5754664854663769426-7354627678430847039?l=www.crazypointer.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/CrazyPointer?a=HE9jgCUYXY4:-pe3QMj6yjE:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CrazyPointer?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CrazyPointer?a=HE9jgCUYXY4:-pe3QMj6yjE:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CrazyPointer?i=HE9jgCUYXY4:-pe3QMj6yjE:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CrazyPointer/~4/HE9jgCUYXY4" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.crazypointer.com/feeds/7354627678430847039/comments/default" title="Enviar comentarios" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=5754664854663769426&amp;postID=7354627678430847039" title="4 comentarios" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5754664854663769426/posts/default/7354627678430847039?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5754664854663769426/posts/default/7354627678430847039?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CrazyPointer/~3/HE9jgCUYXY4/nuevo-dominio-para-el-blog.html" title="Nuevo dominio para el blog" /><author><name>Ricky</name><uri>http://www.blogger.com/profile/18324470751965509112</uri><email>rickyah@gmail.com</email><gd:extendedProperty name="OpenSocialUserId" value="10817153364417160719" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">4</thr:total><feedburner:origLink>http://www.crazypointer.com/2009/04/nuevo-dominio-para-el-blog.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEEDQXg8cSp7ImA9WxJTF0s.&quot;"><id>tag:blogger.com,1999:blog-5754664854663769426.post-7630295654110751372</id><published>2009-04-26T19:24:00.001+02:00</published><updated>2009-04-26T19:24:30.679+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-04-26T19:24:30.679+02:00</app:edited><title>Cómo usar el DNI electrónico (2/2)</title><content type="html">&lt;p&gt;Ya ha pasado casi un mes desde la &lt;a href="http://crazypointer.blogspot.com/2009/03/como-usar-el-dni-electronico-12.html"&gt;anterior entrada&lt;/a&gt;, así que creo que ya va siendo hora de finalizar con esta mini-serie y ponernos a instalar y configurar el hardware y software necesario para poder utilizar nuestro &lt;abbr title="DNI electrónico"&gt;DNI-e&lt;/abbr&gt;.&lt;/p&gt;  &lt;h2&gt;El lector&lt;/h2&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/_y5KbcXiMsPA/SfSYo20yM2I/AAAAAAAAAWA/qvIetAE4uIQ/s1600-h/Lector_LTC31%5B13%5D.jpg"&gt;&lt;img title="Lector LTC31" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; margin-left: 0px; margin-right: 0px; border-right-width: 0px" height="160" alt="Lector LTC31" src="http://lh4.ggpht.com/_y5KbcXiMsPA/SfSYpUG2KWI/AAAAAAAAAWE/r_98VKeEVF0/Lector_LTC31_thumb%5B11%5D.jpg?imgmax=800" width="240" align="right" border="0" /&gt;&lt;/a&gt;Lo primero que necesitamos es configurar el lector en nuestro sistema. Obviamente esto dependerá por un lado del sistema en cuestión y por el otro del modelo del lector escogido. En mi caso el lector tiene el aburrido nombre de &lt;a href="http://www.c3po.es/ltc31.html"&gt;LTC31&lt;/a&gt;, que contrata con el curioso nombre de su fabricante, una empresa española denominada &lt;a href="http://www.c3po.es"&gt;C3PO&lt;/a&gt; que no se cómo habrá pasado desapercibida a atenta mirada de George Lucas y sus abogados. La elección del mismo ha sido simple: bajo precio y disponibilidad en la tienda más cercana a mi casa.&lt;/p&gt;  &lt;p&gt;La configuración del lector no es complicada. En la página de soporte del fabricante instalamos los drivers para que el sistema lo reconozca, conectamos el lector a un puerto USB y localizará los drivers automáticamente. Me encontré con una sorpresa en el caso de Mac, donde el lector no necesita instalación de driver alguna, ya que el lector sigue el estándar USB CCID (la norma USB para lectores de smart-cards, que es lo que es en el fondo un lector de DNIe) y funciona perfectamente con los drivers del sistema sin instalar nada. Mola.&lt;/p&gt;  &lt;h2&gt;Módulos criptográficos &lt;/h2&gt;  &lt;p&gt;Ahora toca instalar este software de genérica denominación. Permitiéndome un poco de deformación profesional -y para reflejar que de verdad he mirado un poco este tema- comentar que un módulo criptográfico no es más que una norma que define un &lt;abbr title="Application Progarmming Interface"&gt;API&lt;/abbr&gt; que permita comunicarse con dispositivos criptográficos, que en nuestro caso es el lector. &lt;/p&gt;  &lt;p&gt;Hay dos implementaciones, una para windows, denominada &lt;a href="http://en.wikipedia.org/wiki/Cryptographic_Application_Programming_Interface"&gt;CAPI&lt;/a&gt;&lt;abbr title="Cryptographic Application Programming Interface"&gt; &lt;/abbr&gt;y otra para Mac y Linux, llamada &lt;a href="http://en.wikipedia.org/wiki/PKCS11"&gt;PKCS11&lt;/a&gt;. Ambas pueden obtenerse desde el portal oficial para el DNI-e, &lt;a href="http://www.dnielectronico.es/descargas/index.html"&gt;en la sección de descargas&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;Con esto ya está &lt;strong&gt;casi todo&lt;/strong&gt; preparado. Sin embargo hay un problema. Como explicamos en la primera entrada sobre el DNI-e, en el proceso de crear una comunicación segura entre ambos usuarios tenemos que poder identificar a ambas partes. Nosotros nos identificaremos usando el certificado de autenticación contenido en el DNI-e. El que nos presta un servicio necesitará validarse también usando un certificado que será contrastado con una Autoridad Validadora que será la encargada de verificar que los certificados de dicho servicio son válidos.&lt;/p&gt;  &lt;p&gt;Por esto hay que realizar un par de pasos. Lo primero informar al sistema qué Autoridades Validadoras tendremos que usar para comprobar que esos certificados son válidos. Lo segundo es obtener los certificados de los prestadores de servicios.&lt;/p&gt;  &lt;h2&gt;Instalar Autoridades Validadoras en eL sistema.&lt;/h2&gt;  &lt;p&gt;Esto también &lt;a href="http://www.dnielectronico.es/seccion_integradores/certs.html"&gt;está disponible en el portal del DNIe&lt;/a&gt;. Esa página nos muestra los tres principales servicios de validación, que serán la Fábrica nacional de moneda y timbre, el Ministerio de Administraciones Públicas, y el Ministerio de Industria Turismo y Comercio. Para cada uno de ellos tenemos disponible un link de descarga de su certificado (en ficheros .zip que contienen el fichero de certificado .cer)&lt;/p&gt;  &lt;p&gt;Debemos descargar los tres y guardarlos en alguna carpeta para instalarlos en el sistema y que sean reconocidos por nuestro navegador.&lt;/p&gt;  &lt;h5&gt;Internet Explorer&lt;/h5&gt;  &lt;p&gt;Instalar el certificado no puede ser más fácil. Doble clic en el fichero de certificado y aparecerá una ventana como la que muestro un poco más abajo. Pulsáis el botón “Instalar certificado” y a seguir el asistente. La única duda puede aparecer cuando pregunte por el almacén de certificados donde debería instalarse. Basta con dejar la opción por defecto, que le indica al sistema que lo seleccione automáticamente.&lt;a href="http://lh6.ggpht.com/_y5KbcXiMsPA/SfSYqVsobeI/AAAAAAAAAWI/a78W49qmoaM/s1600-h/instalar_certificado_ie%5B6%5D.png"&gt;&lt;img title="Instalación de fichero de certificado para una Autoridad Validadora" style="border-right: 0px; border-top: 0px; display: block; float: none; margin-left: auto; border-left: 0px; margin-right: auto; border-bottom: 0px" height="539" alt="Instalación de fichero de certificado para una Autoridad Validadora" src="http://lh3.ggpht.com/_y5KbcXiMsPA/SfSYrPDO0TI/AAAAAAAAAWM/Zy6Z1uK4KRI/instalar_certificado_ie_thumb%5B4%5D.png?imgmax=800" width="460" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Podremos comprobar que los certificados están correctamente instalados iniciando Internet Explorer, y pulsando en el menú &lt;em&gt;Herramientas / Opciones de internet&lt;/em&gt;, pestaña &lt;em&gt;Contenido&lt;/em&gt;, botón &lt;em&gt;Certificados&lt;/em&gt;.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;a href="http://lh6.ggpht.com/_y5KbcXiMsPA/SfSYr0bmJxI/AAAAAAAAAWQ/2hBZkqgD05A/s1600-h/vista_certificados_ie%5B5%5D.png"&gt;&lt;img title="Certificados instalados en IE" style="border-right: 0px; border-top: 0px; display: block; float: none; margin-left: auto; border-left: 0px; margin-right: auto; border-bottom: 0px" height="495" alt="Certificados instalados en IE" src="http://lh6.ggpht.com/_y5KbcXiMsPA/SfSYs7oyNwI/AAAAAAAAAWU/DYYftrtaZgA/vista_certificados_ie_thumb%5B3%5D.png?imgmax=800" width="539" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;h5&gt;Firefox&lt;/h5&gt;  &lt;p&gt;En firefox el proceso es un poco más largo, ya que no obtiene los certificados instalados en el sistema, y deberemos indicarle cuales usar. Sigue siendo muy sencillo en cualquier caso.&lt;/p&gt;  &lt;p&gt;Vamos al menú &lt;em&gt;Herramientas&lt;/em&gt; / &lt;em&gt;Opciones&lt;/em&gt;, y pulsamos en la pestaña &lt;em&gt;Avanzadas&lt;/em&gt; en la ventana que aparece, para obtener esto:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/_y5KbcXiMsPA/SfSYt9mHGOI/AAAAAAAAAWY/Ggk5w9zNx8Y/s1600-h/ff_opciones_avanzadas%5B10%5D.png"&gt;&lt;img title="ff_opciones_avanzadas" style="border-right: 0px; border-top: 0px; display: block; float: none; margin-left: auto; border-left: 0px; margin-right: auto; border-bottom: 0px" height="536" alt="ff_opciones_avanzadas" src="http://lh5.ggpht.com/_y5KbcXiMsPA/SfSYumKWdiI/AAAAAAAAAWc/3DEw31uyIE8/ff_opciones_avanzadas_thumb%5B8%5D.png?imgmax=800" width="601" border="0" /&gt;&lt;/a&gt; Pulsamos el botón &lt;em&gt;Ver certificados&lt;/em&gt;. En la ventana que aparece pulsamos la pestaña “Servidores”, y una vez seleccionada esta pulsaremos el botón &lt;em&gt;Importar&lt;/em&gt;. Ahora buscamos y seleccionamos los ficheros de certificado que hemos descargado del portal del DNIe (hay que hacerlo uno por uno) y pulsamos abrir. Con eso ya tendremos instalados los certificados, y deberíamos obtener algo parecido a esto:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/_y5KbcXiMsPA/SfSYvObKhyI/AAAAAAAAAWg/xxmoeOOE8EA/s1600-h/vista_certificados_ff%5B5%5D.png"&gt;&lt;img title="vista_certificados_ff" style="border-right: 0px; border-top: 0px; display: block; float: none; margin-left: auto; border-left: 0px; margin-right: auto; border-bottom: 0px" height="419" alt="vista_certificados_ff" src="http://lh4.ggpht.com/_y5KbcXiMsPA/SfSYv4rUiaI/AAAAAAAAAWk/_yDZ3Pf8HRQ/vista_certificados_ff_thumb%5B3%5D.png?imgmax=800" width="642" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;h2&gt;Comprobando que todo funciona&lt;/h2&gt;  &lt;p&gt;Ahora ya estamos listos para probar el DNIe desde la página de prueba que nos proporciona el portal del DNIe. Recuerda que antes de hacer click deberás tener el DNIe insertado en el lector. También al hacer clic el sistema nos pedirá el PIN del DNIe por medio de una de estas dos ventanas, dependiendo del navegador que uses:&lt;/p&gt;  &lt;p&gt;&lt;img title="solicitud_pin" style="border-right: 0px; border-top: 0px; display: block; float: none; margin-left: auto; border-left: 0px; margin-right: auto; border-bottom: 0px" height="180" alt="solicitud_pin" src="http://lh6.ggpht.com/_y5KbcXiMsPA/SfSYwRHQn8I/AAAAAAAAAWo/AJTo-5y8WYk/solicitud_pin_thumb%5B3%5D.png?imgmax=800" width="407" border="0" /&gt;&lt;a href="http://lh5.ggpht.com/_y5KbcXiMsPA/SfSYw1Ox8hI/AAAAAAAAAWs/ut9wAALjbv4/s1600-h/ff_password_dnie%5B12%5D.png"&gt;&lt;img title="ff_password_dnie" style="border-right: 0px; border-top: 0px; display: block; float: none; margin-left: auto; border-left: 0px; margin-right: auto; border-bottom: 0px" height="172" alt="ff_password_dnie" src="http://lh4.ggpht.com/_y5KbcXiMsPA/SfSYxSM2GqI/AAAAAAAAAWw/zjskKSRnDbc/ff_password_dnie_thumb%5B10%5D.png?imgmax=800" width="451" border="0" /&gt;&lt;/a&gt;&amp;#160; &lt;/p&gt;  &lt;p align="center"&gt;&lt;a href="https://av-dnie.cert.fnmt.es/compruebacert/compruebacert"&gt;&lt;font size="4"&gt;Clic para probar tu DNIe&lt;/font&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Si puedes ver tus datos es que tu DNIe funciona correctamente.&lt;/p&gt;  &lt;p&gt;No te olvides de probar también la firma en esa misma página. En el cuadro de texto pones cualquier palabra y pulsas el botón firmar. Te volverá a pedir tu PIN del DNIe, y si todo ha sido correcto debería crear una firma válida.&lt;/p&gt;  &lt;p&gt;Si todos los pasos han sido correctos ya podrás acceder a las ventajas del mismo desde las páginas oficiales del estado, a la falta de obtener los…&lt;/p&gt;  &lt;h2&gt;Certificados de prestadores de servicios&lt;/h2&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;Los prestadores de servicios utilizan certificados para identificarse, igual que nosotros con el DNIe, como hemos explicado. Sin embargo nosotros no hemos instalado esos certificados en el sistema. Lo que hemos instalado son unas herramientas que nos permitirán validar que esos certificados son correctos y que podemos confiar en ellos. Sin embargo podemos encontrarnos con certificados que no usan uno de esas tres Autoridades Validadoras para certificar su validez, pero dándose el caso de que nosotros confiemos en ellas igualmente. Eso nos puede hacer saltar una alerta de seguridad en el navegador, y es posible que nos pille con la guardia baja sin saber qué es lo que pasa o qué hacer. &lt;/p&gt;  &lt;p&gt;Hum, explicando esto me estoy haciendo un lío yo mismo, lo que es bastante triste, así que expliquémoslo de otra manera:&lt;/p&gt;  &lt;p&gt;Imaginemos que tenemos un amigo, Pepín, que es un fiera en esto del networking y tiene una base de datos que ríete tú de la &lt;a href="http://www.facebook.com/barackobama"&gt;lista de amigos de Obama en Facebook&lt;/a&gt;. El tío además tiene todos los datos posibles de sus contactos: nombre, apellidos, residencia, DNI, una foto, la huella dactilar, su firma manuscrita, sus datos bancarios, edad, altura, peso, el número que calza (de pie)… vamos todo lo que puedas averiguar de una persona, Pepín lo tiene. Sin embargo Pepín es una persona íntegra, que nunca da esos datos a terceros, por tanto se ha ganado la confianza de todos sus contactos y todo el mundo confía en su honradez y principios. Los servicios que ofrece Pepín se basan en esa confianza: tú le das los datos que una supuesta persona te ha dado y el te indica si esos datos son correctos, y además lo hace gratis porque es todo un filántropo. Pepín es por tanto nuestra Autoridad Certificadora.&lt;/p&gt;  &lt;p&gt;Supongamos que conocemos a una persona, Juan, que nos da unos datos personales de referencia para certificar su identidad. Como queremos hacer negocios con él y nos hemos llevado malas experiencias anteriores, nuestras alarmas saltan: hemos de asegurarnos de que Juan es realmente Juan, y no otra persona haciéndose pasar por él. Por ello enviamos esos datos a Pepín, y el nos contesta diciéndonos que son correctos. Como quiera que confiamos en Pepín, ahora tenemos la certeza de que Juan es quien dice ser. Juan hace lo mismo con los datos que nosotros le hemos proporcionado para probar nuestra identidad, y todos contentos.&lt;/p&gt;  &lt;p&gt;Sin embargo imaginemos que Juan es un tío asocial, que no está en la red de contactos de Pepín, pero que nosotros conocemos de toda la vida. Pues aunque Pepín no pueda certificar que Juan es quien dice ser, nosotros haremos una excepción al procedimiento y simplemente confiaremos en los datos que nos ha proporcionado.&lt;/p&gt;  &lt;p&gt;Pues algo parecido pasa cuando queremos acceder a los servicios y usamos nuestro DNIe. El DNIe contiene un certificado digital que nos identifica, y el prestador de servicios tiene el suyo. Ese certificado digital hemos de obtenerlo de alguna parte. Como esto es internet, el futuro y todo eso,la obtención del certificado es automática, y el prestador de servicios nos lo enviará automáticamente en el proceso de crear una conexión segura. Sin embargo si no fuera posible validar ese certificado con las Autoridades instaladas anteriormente, es posible que una alarma de seguridad nos aparezca dependiendo de nuestro nivel de seguridad del navegador,&amp;#160; ya que estamos obteniendo un certificado automáticamente que a priori no sabemos de quién es. Sin embargo puede que no nos importe porque confiamos en que esa página web es quien dice ser.&lt;/p&gt;  &lt;p&gt;Lo más probable es que nos salte en firefox antes que en IE (sorpresa!), y sea una ventana como esta:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/_y5KbcXiMsPA/SfSYyrTUvbI/AAAAAAAAAW0/Q2hUBzm71tM/s1600-h/certificado%5B7%5D.png"&gt;&lt;img title="certificado" style="border-right: 0px; border-top: 0px; display: block; float: none; margin-left: auto; border-left: 0px; margin-right: auto; border-bottom: 0px" height="205" alt="certificado" src="http://lh5.ggpht.com/_y5KbcXiMsPA/SfSYzZOzryI/AAAAAAAAAW4/zhrXxB1Tnvg/certificado_thumb%5B5%5D.png?imgmax=800" width="260" border="0" /&gt;&lt;/a&gt; Si sabemos que la página a la que accedemos es correcta en general podremos añadir la excepción de seguridad (que lo que hace es descargar el certificado y añadirlo a la lista de certificados seguros) sin problema.&lt;/p&gt;  &lt;p&gt;En este caso la página que hace saltar esa identificación es la del INEM.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;Y eso es todo, a partir de ahora podremos utilizar los servicios del DNIe, y con suerte evitarnos tiempo perdido haciendo cola en las administraciones públicas.&lt;/p&gt;  &lt;p&gt;No olvidéis visitar la página de vuestro ayuntamiento ya que muchas competencias relativos a estos servicios están descentralizadas y es responsabilidad de cada región proporcionarlas. Por ejemplo, datos de empadronamiento o catastro son datos que deben ser solicitados a tu ayuntamiento.&lt;/p&gt;  &lt;p&gt;Feliz uso del DNIe!&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5754664854663769426-7630295654110751372?l=www.crazypointer.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/CrazyPointer?a=ZUKgWBEILYw:F39MAmP71nY:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CrazyPointer?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CrazyPointer?a=ZUKgWBEILYw:F39MAmP71nY:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CrazyPointer?i=ZUKgWBEILYw:F39MAmP71nY:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CrazyPointer/~4/ZUKgWBEILYw" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.crazypointer.com/feeds/7630295654110751372/comments/default" title="Enviar comentarios" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=5754664854663769426&amp;postID=7630295654110751372" title="0 comentarios" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5754664854663769426/posts/default/7630295654110751372?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5754664854663769426/posts/default/7630295654110751372?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CrazyPointer/~3/ZUKgWBEILYw/como-usar-el-dni-electronico-22.html" title="Cómo usar el DNI electrónico (2/2)" /><author><name>Ricky</name><uri>http://www.blogger.com/profile/18324470751965509112</uri><email>rickyah@gmail.com</email><gd:extendedProperty name="OpenSocialUserId" value="10817153364417160719" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://www.crazypointer.com/2009/04/como-usar-el-dni-electronico-22.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Ak4AR3o5eip7ImA9WxJXEkU.&quot;"><id>tag:blogger.com,1999:blog-5754664854663769426.post-1573282019783388082</id><published>2009-03-28T02:00:00.006+01:00</published><updated>2009-06-06T13:49:06.422+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-06-06T13:49:06.422+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="DNIe" /><title>Cómo usar el DNI electrónico (1/2)</title><content type="html">&lt;p&gt;Aunque esto no tiene que ver totalmente con la temática del blog considero que es interesante igualmente, así que vamos a hablar del relativamente reciente &lt;abbr title="DNI Electrónico"&gt;DNIe&lt;/abbr&gt;, cómo prepararnos para usarlo y ver qué ventajas nos aporta. Lo dividiré en dos entradas para que no me ocupen mucho. Esta será teórica, para comprender grosso modo qué es el DNIe y cómo funciona. La segunda entrada cubre la instalación y configuración de un lector y los navegadores para poder usar el DNIe, y está disponible &lt;a href="http://www.crazypointer.com/2009/04/como-usar-el-dni-electronico-22.html"&gt;aquí&lt;/a&gt;. &lt;/p&gt;  &lt;br /&gt;  &lt;h2&gt;Introducción&lt;/h2&gt;  &lt;p&gt;El &lt;abbr title="DNI Electrónico"&gt;DNIe&lt;/abbr&gt; tiene la misma función que el DNI tradicional, servir como documento acreditativo de la identidad del titular. La novedad es que ahora lo podremos utilizar para acreditar nuestra identidad en el mundo digital, por medio de un &lt;a href="http://es.wikipedia.org/wiki/Certificado_digital"&gt;certificado digital&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;Esto nos permitirá, entre otras cosas, acceder a servicios o realizar trámites con la Administración pública desde casa, evitando desplazamientos y esperas, o la firma digital de documentos, emails, etc, que adquieren la misma validez legal que una firma manuscrita.&lt;/p&gt;  &lt;p&gt;Toda la información del &lt;abbr title="DNI Electrónico"&gt;DNIe&lt;/abbr&gt; está disponible en su &lt;a href="http://www.dnie.es/"&gt;portal oficial&lt;/a&gt;. &lt;/p&gt;  &lt;br /&gt;  &lt;h2&gt;Características del &lt;abbr title="DNI Electrónico"&gt;DNIe&lt;/abbr&gt;&lt;/h2&gt;  &lt;br /&gt;  &lt;p&gt;El nuevo DNI tiene el tamaño de cualquier tarjeta de crédito actual, y contiene los datos identificativos de siempre. La novedad es el nuevo chip que incorpora que contiene la siguiente información, copiada vilmente del portal oficial:&lt;/p&gt;  &lt;br /&gt;  &lt;ol&gt;   &lt;li&gt;Un certificado digital para autenticar la identidad del ciudadano. &lt;/li&gt;    &lt;li&gt;Un certificado digital para &lt;a href="http://es.wikipedia.org/wiki/Digitalizador_de_firmas"&gt;firmar digitalmente&lt;/a&gt;, con la misma validez jurídica que la firma manuscrita. &lt;/li&gt;    &lt;li&gt;Certificado de la Autoridad de Certificación emisora. &lt;/li&gt;    &lt;li&gt;Claves –pública y privada- para la firma digital. &lt;/li&gt;    &lt;li&gt;La plantilla biométrica de la impresión dactilar. &lt;/li&gt;    &lt;li&gt;La fotografía digitalizada del ciudadano. &lt;/li&gt;    &lt;li&gt;La imagen digitalizada de la firma manuscrita. &lt;/li&gt;    &lt;li&gt;Datos de la filiación del ciudadano, correspondientes con el contenido personalizado en la tarjeta. &lt;/li&gt; &lt;/ol&gt;  &lt;h2&gt;Funcionamiento del &lt;abbr title="DNI Electrónico"&gt;DNIe&lt;/abbr&gt;&lt;/h2&gt;  &lt;br /&gt;  &lt;p&gt;Para conocer mejor el funcionamiento del &lt;abbr title="DNI Electrónico"&gt;DNIe&lt;/abbr&gt;, hay que dejar claros algunos conceptos. (Los números en paréntesis referencian las características enumeradas anteriormente)&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;strong&gt;Autoridad Certificadora (AC) &lt;/strong&gt;&lt;/li&gt; &lt;/ul&gt;  &lt;blockquote&gt;   &lt;p&gt;Es la autoridad encargada de emitir certificados digitales.&lt;/p&gt; &lt;/blockquote&gt;  &lt;blockquote&gt;   &lt;p&gt;En el caso de los certificados de Autenticación(1) y Firma(2) incluidos en el &lt;abbr title="DNI Electrónico"&gt;DNIe&lt;/abbr&gt;, sólo la Dirección General de la Policía y la Guardia Civil tiene la potestad de emitirlos. Es decir, que son los únicos que pueden crear un &lt;abbr title="DNI Electrónico"&gt;DNIe&lt;/abbr&gt;.&lt;/p&gt; &lt;/blockquote&gt;  &lt;blockquote&gt;   &lt;p&gt;No hay que olvidar que existen otras entidades que también pueden emitir otros certificados al margen de los incluidos en el &lt;abbr title="DNI Electrónico"&gt;DNIe&lt;/abbr&gt; que también son válidos para trámites telemáticos en España, como la &lt;a href="http://www.fnmt.es/"&gt;Fábrica de Moneda y Timbre&lt;/a&gt;, por ejemplo.&lt;/p&gt; &lt;/blockquote&gt;  &lt;blockquote&gt;   &lt;p&gt;Los certificados son únicos para cada individuo y se generan en el momento en que te entregan el &lt;abbr title="DNI Electrónico"&gt;DNIe&lt;/abbr&gt;, un proceso largo por cierto. Si no te gustan los silencios incómodos, tus habilidades de hablar de temas triviales se pondrán al límite cuando estés enfrente del funcionario y tengas que esperar a que estos se creen...&lt;/p&gt; &lt;/blockquote&gt;  &lt;blockquote&gt;   &lt;p&gt;Los certificados se encuentran guardados en el chip del &lt;abbr title="DNI Electrónico"&gt;DNIe&lt;/abbr&gt; y sólo se puede acceder a ellos por medio de un &lt;abbr title="Personal Identification Number"&gt;PIN&lt;/abbr&gt; (que debería llamarse password) ya que no es un número sino una secuencia de caracteres. Éste se entrega junto al DNIe en un sobre cerrado y es necesario para realizar cualquier consulta de la información que contiene el &lt;abbr title="DNI Electrónico"&gt;DNIe&lt;/abbr&gt;, desde los personales (8), hasta los certificados. Dicho de otro modo, cada vez que quieras consultar los datos de tu DNIe o realizar algún tipo de operación con él, deberás introducir el &lt;abbr title="Personal Identification Number"&gt;PIN&lt;/abbr&gt;.&lt;/p&gt; &lt;/blockquote&gt;  &lt;blockquote&gt;   &lt;p&gt;Por cierto, si introduces tres veces consecutivas el &lt;abbr title="Personal Identification Number"&gt;PIN&lt;/abbr&gt;, el &lt;abbr title="DNI Electrónico"&gt;DNIe&lt;/abbr&gt; se bloquea, y deberás ir a un Punto de Actualización del DNIe&lt;strong&gt; &lt;/strong&gt;-que debería estar disponible donde te lo entregaron- para poder desbloquearlo usando la huella dactilar. Cabe destacar que la plantilla biométrica de la huella dactilar (8) no puede ser consultada, sino que es el propio &lt;abbr title="DNI Electrónico"&gt;DNIe&lt;/abbr&gt; el encargado de validar una plantilla que se le proporcione de forma externa (es decir, la plantilla leída desde el lector del puesto) con la que el propio &lt;abbr title="DNI Electrónico"&gt;DNIe&lt;/abbr&gt; guarda, y aceptarla como válida o no.&lt;/p&gt; &lt;/blockquote&gt;  &lt;br /&gt;  &lt;ul&gt;   &lt;li&gt;&lt;strong&gt;Autoridad Validadora (AV) &lt;/strong&gt;&lt;/li&gt; &lt;/ul&gt;  &lt;blockquote&gt;   &lt;p&gt;Estas entidades validan que un certificados emitido es vigente, por ejemplo, que realmente está generado por la Autoridad Certificadora indicada, o que bien este certificado no ha expirado.&lt;/p&gt; &lt;/blockquote&gt;  &lt;blockquote&gt;   &lt;p&gt;Para nuestro caso las autoridades validadoras más importantes serán la &lt;em&gt;Fábrica Nacional de Moneda y&lt;/em&gt; Timbre, que presta servicios de validación de forma universal (ciudadanos, empresas y Admon. Pública), el &lt;em&gt;Ministerio de Administraciones Públicas&lt;/em&gt;, que presta los servicios de validación a la Administración, y el Ministerio de Industria, Turismo y Comercio, que los presta a empresas, por ejemplo para generar &lt;a href="http://www.facturae.es/"&gt;facturas electrónicas firmadas digitalmente&lt;/a&gt;.&lt;/p&gt; &lt;/blockquote&gt;  &lt;br /&gt;  &lt;ul&gt;   &lt;li&gt;&lt;strong&gt;Firma electrónica&lt;/strong&gt;       &lt;br /&gt;&lt;/li&gt; &lt;/ul&gt;  &lt;blockquote&gt;   &lt;p&gt;La firma electrónica se realiza utilizando criptografía de &lt;a href="Public-key cryptography"&gt;clave asimétrica&lt;/a&gt;. Resumiendo mucho el procedimiento, esta técnica se basa en el uso de de dos claves relacionadas, de forma que están vinculadas entre si de forma única.&lt;/p&gt; &lt;/blockquote&gt;  &lt;ul&gt;   &lt;ul&gt;     &lt;li&gt;&lt;strong&gt;Clave privada&lt;/strong&gt;: como su nombre indica es personal e intransferible, Con ella efectuaremos la firma de un documento y en ese momento será como si hubiéramos firmado éste de forma manuscrita. Por eso es importante que esta clave privada permanezca en secreto, ya que si alguien más la tuviera podría firmar documentos con nuestra identidad.         &lt;br /&gt;&lt;/li&gt;      &lt;li&gt;&lt;strong&gt;Clave pública&lt;/strong&gt;: esta clave ha de distribuirse a los destinatarios de los documentos y servirá para comprobar que el documento pertenece realmente a la persona que lo firmó con su clave privada. Cada clave pública está vinculada a una, y sólo a una, clave privada.         &lt;br /&gt;&lt;/li&gt;   &lt;/ul&gt; &lt;/ul&gt;  &lt;blockquote&gt;   &lt;p&gt;Se puede establecer una analogía simple pensado en una caja fuerte con dos tipos de llaves. Una de ellas, la llave privada, permite a su usuario abrir la caja fuerte e introducir algo, y además tiene la particularidad de que sólo existe una copia. Por el contrario de la otra llave, la llave pública, tenemos un montón de copias que repartimos entre conocidos, pero ésta sólo permite recuperar lo que hay dentro de la caja, sin posibilidad de introducir algo -supongamos que la sofisticada caja fuerte simplemente expulsa el contenido como si fuera una máquina expendedora. Sí sólo existe una llave privada y nos pertenece, cualquier persona que tenga una llave pública tendrá la certeza de que lo que se encuentre dentro de ella sólo ha podido ser introducido por el propietario de la llave privada.&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;Una vez dejado claras estos términos, se puede explicar cómo funciona todo esto para poder asegurar nuestra identidad. Bien, supongamos que tenemos un cliente (nosotros), y una entidad que proporciona un servicio que necesitamos pero que para proporcionarlo es necesario estar completamente seguros de que la persona que lo solicita es quien dice ser (*). El procedimiento sería el siguiente:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Utilizando una conexión segura &lt;abbr title="Secure Socket Layer"&gt;SSL&lt;/abbr&gt; para conectarnos a la web de la entidad (la forma más fácil de identificarlo es porque la dirección de la página web comienza por https, en vez del habitual http) y solicitamos una conexión con autenticación.       &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;La entidad crea un mensaje autenticado por medio de un certificado y nos lo envía. Utilizando una Autoridad Validadora nos aseguramos de que el certificado es válido.      &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;El servicio nos envía un mensaje de inicio de sesión cifrado que procederemos a descifrar por medio de la clave pública incluida en el certificado.      &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;Una vez validado el mensaje de inicio de sesión en el paso anterior, utilizamos nuestra clave privada del &lt;abbr title="DNI Electrónico"&gt;DNIe&lt;/abbr&gt; para cifrar un mensaje de establecimiento de sesión, y enviarlo junto a nuestro certificado de autenticación. Como en este momento tenemos que acceder a los datos del &lt;abbr title="DNI Electrónico"&gt;DNIe&lt;/abbr&gt;, este debe estar insertado en el lector y nos pedirá el &lt;abbr title="Personal Identification Number"&gt;PIN&lt;/abbr&gt;.       &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;La entidad verifica que el mensaje de establecimiento de sesión es correcto desencriptándolo con la clave pública, y se asegura de que nuestro certificado de autenticación es válido.      &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;Como hemos verificado que ambos (cliente y entidad) somos quien decimos ser, se establece la conexión segura y autenticada. A partir de este momento podemos acceder a los servicios.      &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;&amp;#160;&lt;img alt="" src="http://www.zu14.cn/coolemotion/emotions/zz_3.gif" /&gt;       &lt;br /&gt;&lt;/li&gt; &lt;/ul&gt;  &lt;h2&gt;Servicios Disponibles con el &lt;abbr title="DNI Electrónico"&gt;DNIe&lt;/abbr&gt;&lt;/h2&gt;  &lt;p&gt;Aquí no me voy a complicar de forma exagerada y sólo comentaré algunos servicios que me han parecido interesantes. Para la lista completa (y larga) os remito al &lt;a href="http://www.dnie.es/servicios_disponibles/index.html"&gt;listado del portal oficial&lt;/a&gt;.&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;a href="http://www.inem.es/inem/OficinaVirtual/solicitud/index.html"&gt;Solicitar la prestación por desempleo&lt;/a&gt;, o &lt;a href="http://www.inem.es/inem/OficinaVirtual/consulte/index.html"&gt;consulta de la situación personal de prestación por desempleo.&lt;/a&gt;&lt;/p&gt;    &lt;p&gt;La &lt;a href="http://www.agenciatributaria.es"&gt;Agencia tributaria&lt;/a&gt; nos permite hacer la declaración de la renta o pagar nuestros impuestos sin esperar colas ni perder tiempo.&lt;/p&gt;    &lt;p&gt;Correos nos proporciona una &lt;a href="https://cep.correos.es/"&gt;dirección de correo electrónico segura&lt;/a&gt; de forma gratuita&lt;/p&gt;    &lt;p&gt;También hay una &lt;a href="http://www.dnie.es/servicios_disponibles/serv_disp_priv.html"&gt;lista de entidades privadas&lt;/a&gt; (bancos y una aseguradoras concretamente) que utilizan el DNIe para algunos trámites.&lt;/p&gt;    &lt;p&gt;Algunos ayuntamientos proporcionan servicios más concretos. En mi caso tengo suerte y el &lt;a href="http://www.agenciatributaria.es/"&gt;ayuntamiento de Gijón&lt;/a&gt; es uno de ellos. Aunque no he conseguido que funcione con el &lt;abbr title="DNI Electrónico"&gt;DNIe&lt;/abbr&gt; :(&lt;/p&gt;    &lt;p&gt;&amp;#160;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;En la próxima entrada veremos cómo instalar todo lo necesario para utilizar el &lt;abbr title="DNI Electrónico"&gt;DNIe&lt;/abbr&gt; en Windows y Mac con Firefox e Internet Explorer.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5754664854663769426-1573282019783388082?l=www.crazypointer.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/CrazyPointer?a=TucaRtp8KMM:MO4ZqHxZfpo:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CrazyPointer?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CrazyPointer?a=TucaRtp8KMM:MO4ZqHxZfpo:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CrazyPointer?i=TucaRtp8KMM:MO4ZqHxZfpo:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CrazyPointer/~4/TucaRtp8KMM" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.crazypointer.com/feeds/1573282019783388082/comments/default" title="Enviar comentarios" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=5754664854663769426&amp;postID=1573282019783388082" title="3 comentarios" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5754664854663769426/posts/default/1573282019783388082?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5754664854663769426/posts/default/1573282019783388082?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CrazyPointer/~3/TucaRtp8KMM/como-usar-el-dni-electronico-12.html" title="Cómo usar el DNI electrónico (1/2)" /><author><name>Ricky</name><uri>http://www.blogger.com/profile/18324470751965509112</uri><email>rickyah@gmail.com</email><gd:extendedProperty name="OpenSocialUserId" value="10817153364417160719" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">3</thr:total><feedburner:origLink>http://www.crazypointer.com/2009/03/como-usar-el-dni-electronico-12.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Ak8HSHY7eCp7ImA9WxVUGUo.&quot;"><id>tag:blogger.com,1999:blog-5754664854663769426.post-435717136283402912</id><published>2009-03-24T21:50:00.013+01:00</published><updated>2009-03-25T12:00:39.800+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-25T12:00:39.800+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Nocturnal" /><category scheme="http://www.blogger.com/atom/ns#" term="C++" /><title>Nocturnal Initiative: Smart Pointer (II)</title><content type="html">&lt;p&gt;Ya ha pasado mucho tiempo desde la última entrada, y ya no te quiero ni contar desde la &lt;a href="http://crazypointer.blogspot.com/2008/05/nocturnal-initiative-smart-pointer-i.html"&gt;entrada que precede a esta&lt;/a&gt;. Llevo sin escribir en el blog por mezcla de mi dejadez aderezado con ciertos cambios en mi vida laboral. Así que retomo la escritura para completar esta mini-serie iniciada ya hace casi un año, algo que no tiene excusa alguna porque lo que quedaba por explicar era muy sencillo.&lt;/p&gt;&lt;p&gt;Recapitulemos, en nocturnal teníamos un interface &lt;strong&gt;&lt;font color="#000000"&gt;IRefCount&lt;/font&gt;&lt;/strong&gt; que definía tres operaciones para contar las referencias a un objeto:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;em&gt;IncrRefCount&lt;/em&gt;() Incrementa en uno el contador de referencias. &lt;/li&gt;
&lt;li&gt;&lt;em&gt;DecrRefCount&lt;/em&gt;() Decrementa en uno el contador de referencias. &lt;/li&gt;
&lt;li&gt;&lt;em&gt;GetRefCount&lt;/em&gt;() Devuelve el número de referencias del objeto. &lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;A su vez teníamos disponible las clases &lt;strong&gt;RefCountBase&lt;/strong&gt; y &lt;strong&gt;RefCountAggregator&lt;/strong&gt;, que implementan dicho interface.&lt;/p&gt;&lt;p&gt;Pues ahora hablaremos de la clase &lt;strong&gt;SmartPtr&amp;lt;T&amp;gt;&lt;/strong&gt; una clase que tiene como fin comportarse exactamente igual que un puntero, pero gestionando automáticamente el ciclo de vida de un objeto según el número de referencias que tenga. Esto significa que, dada una instancia de un objeto en memoria, este se borrará automáticamente cuando ningún otro SmartPtr lo referencie.&lt;/p&gt;&lt;p&gt;Todo esto funciona siempre que T sea un tipo que implementa &lt;strong&gt;IRefCount&lt;/strong&gt;, por tanto utilizará los tres métodos definidos en dicho interface para gestionar las cuenta de las referencias. Si no es así el código ni compilará. Y aunque no es obligatorio para que el código compile, si que es necesario para que todo funcione que sólo utilizaremos un tipo de puntero SmartPtr para gestionar los objetos: si mezclamos punteros “tradicionales” con smart pointers armaremos un cisco épico con toda probabilidad.&lt;/p&gt;&lt;p&gt;Por supuesto que implemente &lt;strong&gt;IRefCount&lt;/strong&gt; es sólo parte del trabajo, ya que un interface por si sólo no incluye el código necesario para gestionar las referencias. Por ello, y suponiendo que no queremos reinventar la rueda, lo mejor será que cualquier objeto que pretendamos utilizar con un &lt;strong&gt;SmartPtr&lt;/strong&gt; derive de &lt;strong&gt;RefCountBase&lt;/strong&gt;, con lo que en la práctica se convertirá en la clase base de toda nuestra jerarquía de objetos.&lt;/p&gt;&lt;p&gt;Pero ¿cómo funciona SmartPtr internamente? Pues haciendo uso tanto de conversiones implícitas en los constructores como de sobrecarga de operadores para simular el comportamiento de un puntero a la par que actualizas la cuenta de referencias.&lt;/p&gt;&lt;p&gt;El contador de referencias se inicializa a 1 al asignar por primera vez un puntero &lt;u&gt;válido&lt;/u&gt; a un SmartPtr, y se va actualizando con cada operación de asignación –decrementando la referencia del SmartPtr sobreescrito e incrementando la del asignado, o cuando el objeto SmartPtr es destruido, momento en el que decrementamos en uno el contador de referencias.&lt;/p&gt;&lt;p&gt;Menudo lío, veamos algo de código:&lt;/p&gt;&lt;p&gt;Empezamos con una clase sencilla de prueba&lt;/p&gt;&lt;pre class="c++" name="code"&gt;//Clase simple que deriva de BaseRefCount para
//implementar el contador de referencias
class MyClass : BaseRefCount {};&lt;/pre&gt;&lt;br /&gt;
&lt;p&gt;Creamos un par de &lt;strong&gt;SmartPtr&lt;/strong&gt; que apuntan a instancias diferentes de MyClass&lt;/p&gt;&lt;pre class="c++" name="code"&gt;//ptr2MyClass1: Contador de referencia a 1
//apunta a la instancia 1 de MyClass
SmartPtr&lt; MyClass &gt; ptr2MyClass1 = new MyClass();
//ptr2MyClass2: Contador de referencia a 1
//apunta a la instancia 2 de MyClass
SmartPtr&lt; MyClass &gt; ptr2MyClass2 = new MyClass();&lt;/pre&gt;&lt;br /&gt;
&lt;p&gt;Ahora mismo ptr2MyClass1 != ptr2MyClass2 ya que apuntan a instancias de objetos distintas. &lt;/p&gt;&lt;br /&gt;
&lt;p&gt;Sin embargo con una &amp;quot;simple&amp;quot; asignación vamos a ver que ocurren varias cosas: &lt;/p&gt;&lt;pre class="c++" name="code"&gt;ptr2MyClass2 = ptr2MyClass1;&lt;/pre&gt;&lt;br /&gt;
&lt;p&gt;ptr2MyClass2 está siendo sobreescrito, con lo que decrementamos su contador de referencias. Como era 1, ahora pasa a ser 0, por tanto como ningún puntero referencia la instancia, hemos de borrar dicha instancia, y así lo hacemos, o mejor dicho, así se hace automáticamente. Por otro lado al asignarle el puntero ptr2MyClass1, lo que estamos estamos diciendo es que ptr2MyClass2 apunte a la misma instancia que ptr2MyClass1, que es la instancia 1 Eso implica que ahora tenemos DOS referencias a la misma instancia, por lo que incrementamos el contador de referencia que pasa a ser 2. &lt;/p&gt;&lt;p&gt;Ahora mismo ptr2MyClass1 == ptr2MyClass2: ambos apuntan a la misma instancia en memoria. Vamos a asignar un puntero nulo:&lt;/p&gt;&lt;pre class="c++" name="code"&gt;ptr2MyClass2 = 0;&lt;/pre&gt;&lt;br /&gt;
&lt;p&gt;Como estamos asignando una referencia nula, lo que haremos será decrementar el contador de referencias, con lo que pasa a ser 1.&lt;/p&gt;&lt;p&gt;Por último, imaginemos que ptr2MyClass1, que es el único &lt;strong&gt;SmartPtr&lt;/strong&gt; que apunta a la instancia 1 sale del ámbito actual en el que ha sido declarado, algo como esto:&lt;/p&gt;&lt;pre class="c++" name="code"&gt;{
    SmartPtr&lt; MyClass &gt; ptr2MyClass1 = new MyClass();
} 
//Aquí salimos de ámbito, por lo que llamamos al 
//destructor definido para ptr2MyClass1&lt;/pre&gt;&lt;p&gt;Pues bien, como al salir de ámbito su destructor es invocado el contador de referencias es decrementado de nuevo. Como éste era 1, pasa a ser 0, y por tanto la instancia es borrada automáticamente. &lt;/p&gt;&lt;br /&gt;
&lt;p&gt;Como vemos estamos trabajando con punteros sin necesidad de gestionar la memoria y sin crear fugas de memoria. &lt;/p&gt;&lt;br /&gt;
&lt;p&gt;Pero mucho ojo, ¡porque esto no es válido para semánticas de punteros como arrays!&lt;/p&gt;&lt;p&gt;Por ejemplo este código compila, pero genera fugas de memoria:&lt;/p&gt;&lt;pre class="c++" name="code"&gt;SmartPtr&lt; MyClass &gt;* myClassArray = new SmartPtr&lt; MyClass &gt; [2];
myClassArray[0] = new MyClass();
myClassArray[1] = new MyClass();&lt;/pre&gt;&lt;p&gt;Eso es debido a que al destruir el puntero myClassArray, no iteramos por cada uno de sus elementos para destruir los objetos que almacena. En estos casos lo más cómodo es utilizar la clase &lt;strong&gt;vector &lt;/strong&gt;de stl, que al destruir un vector si llama al destructor de cada uno de los elementos que almacena:&lt;/p&gt;&lt;pre class="c++" name="code"&gt;vector&lt; SmartPtr&lt;myclass&gt; &gt; myClassArray = vector&lt; SmartPtr&lt; MyClass &gt; &gt; (2);
myClassArray[0] = new MyClass();
myClassArray[1] = new MyClass();&lt;/pre&gt;&lt;p&gt;Y ya tenemos arrays que almacenan punteros sin fugas de memoria y auto-gestionados &lt;img alt="" src="http://www.zu14.cn/coolemotion/emotions/zz_3.gif" /&gt;&lt;/p&gt;&lt;p&gt;Como nota final, en la última versión del &lt;u&gt;&lt;a href="http://nocturnal.insomniacgames.com/"&gt;NocturnalFramework&lt;/a&gt;&lt;/u&gt;, que &lt;a href="http://crazypointer.blogspot.com/2008/08/nueva-versin-de-nocturnal-initiative.html"&gt;ya salió hace algún tiempo&lt;/a&gt; la clases necesarias para utilizar &lt;strong&gt;SmartPtr&lt;/strong&gt; se encuentran en el directorio &lt;em&gt;Common/Memory&lt;/em&gt;. Si queréis trastear con ella tened en cuenta que hay referencias a ficheros que se encuentran dentro del directorio &lt;em&gt;Common&lt;/em&gt;, por lo que lo más cómodo es copiar la carpeta &lt;em&gt;Common&lt;/em&gt; completa a vuestro proyecto.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5754664854663769426-435717136283402912?l=www.crazypointer.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/CrazyPointer?a=rtRWtVS0onw:5u1oP4jC4u8:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CrazyPointer?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CrazyPointer?a=rtRWtVS0onw:5u1oP4jC4u8:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CrazyPointer?i=rtRWtVS0onw:5u1oP4jC4u8:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CrazyPointer/~4/rtRWtVS0onw" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.crazypointer.com/feeds/435717136283402912/comments/default" title="Enviar comentarios" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=5754664854663769426&amp;postID=435717136283402912" title="0 comentarios" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5754664854663769426/posts/default/435717136283402912?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5754664854663769426/posts/default/435717136283402912?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CrazyPointer/~3/rtRWtVS0onw/nocturnal-initiative-smart-pointer-ii.html" title="Nocturnal Initiative: Smart Pointer (II)" /><author><name>Ricky</name><uri>http://www.blogger.com/profile/18324470751965509112</uri><email>rickyah@gmail.com</email><gd:extendedProperty name="OpenSocialUserId" value="10817153364417160719" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://www.crazypointer.com/2009/03/nocturnal-initiative-smart-pointer-ii.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEYNQHs7fSp7ImA9WxVRFUo.&quot;"><id>tag:blogger.com,1999:blog-5754664854663769426.post-5131298181086854312</id><published>2009-01-21T23:00:00.001+01:00</published><updated>2009-01-21T23:16:31.505+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-01-21T23:16:31.505+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="C#" /><category scheme="http://www.blogger.com/atom/ns#" term="Mono" /><title>Mono 2.2 released!</title><content type="html">&lt;p&gt;Hace una semana que se lanzó la versión 2.2 de &lt;a href="http://es.wikipedia.org/wiki/Proyecto_Mono"&gt;Mono&lt;/a&gt;, ¡y yo sin enterarme!. &lt;/p&gt; &lt;p&gt;Viene cargadita de novedades:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Nuevo &lt;a href="http://www.mono-project.com/Linear_IL"&gt;generador de código IL&lt;/a&gt;, más eficiente, que mejora el rendimiento y reduce la cantidad de código IL final.  &lt;li&gt;Reescritura de los &lt;a href="http://www.go-mono.com/docs/index.aspx?tlink=13@ecma%3a1798%23PerformanceCounter%2f"&gt;PerformanceCounters&lt;/a&gt;, que permiten monitorizar el propio runtime. (&lt;a href="http://www.go-mono.com/docs/index.aspx?tlink=13@ecma%3a1798%23PerformanceCounter%2f"&gt;link a la clase PerformanceCounter en MSDN&lt;/a&gt;) También incluye una nueva herramienta visual para este menester.  &lt;li&gt;&lt;a href="http://tirania.org/blog/archive/2008/Nov-03.html"&gt;Soporte SIMD&lt;/a&gt; ya incluido en la release (antes estaba disponible en el repositorio)  &lt;li&gt;Soporte para &lt;a href="http://www.mono-project.com/AOT"&gt;compilación Ahead of Time&lt;/a&gt;. Además se puede precompilar todo el código (e.g. para sistemas embebidos) o dejar al compilador que precompile de forma optimizada sólo las partes que te proporcionarán mayor beneficio.&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Y las novedades incorporadas específicamente al lenguaje C# son:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Compilador de C# como servicio. &lt;a href="http://crazypointer.blogspot.com/2008/12/pdc-2008-future-of-c-40-33.html"&gt;Adelantándose a C# 4.0&lt;/a&gt;, podrás ejecutar de forma dinámica scripts de C# en tu aplicación, o dicho de otro modo, podrás compilar código C#^desde tu programa ^_^  &lt;li&gt;Gracias al punto anterior, ahora hay disponibles shells interactivas para C#, al estilo de lenguajes como Python o Ruby&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Por lo demás son ligeras optimizaciones, corrección de bugs (casi 200 en Windows.Forms desde la versión 2.0) y cosas por el estilo.&lt;/p&gt; &lt;p&gt;Impresionante trabajo el de los chicos de Mono. &lt;a href="http://www.go-mono.com"&gt;Go Mono!&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5754664854663769426-5131298181086854312?l=www.crazypointer.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/CrazyPointer?a=HUbZps3E8Uk:iOmC0X7Yhc0:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CrazyPointer?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CrazyPointer?a=HUbZps3E8Uk:iOmC0X7Yhc0:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CrazyPointer?i=HUbZps3E8Uk:iOmC0X7Yhc0:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CrazyPointer/~4/HUbZps3E8Uk" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.crazypointer.com/feeds/5131298181086854312/comments/default" title="Enviar comentarios" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=5754664854663769426&amp;postID=5131298181086854312" title="0 comentarios" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5754664854663769426/posts/default/5131298181086854312?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5754664854663769426/posts/default/5131298181086854312?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CrazyPointer/~3/HUbZps3E8Uk/mono-22-released.html" title="Mono 2.2 released!" /><author><name>Ricky</name><uri>http://www.blogger.com/profile/18324470751965509112</uri><email>rickyah@gmail.com</email><gd:extendedProperty name="OpenSocialUserId" value="10817153364417160719" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://www.crazypointer.com/2009/01/mono-22-released.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUMFR304fyp7ImA9WxVRFUo.&quot;"><id>tag:blogger.com,1999:blog-5754664854663769426.post-5994900945931028905</id><published>2009-01-20T23:39:00.001+01:00</published><updated>2009-01-21T22:30:16.337+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-01-21T22:30:16.337+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="PersonalProjects" /><category scheme="http://www.blogger.com/atom/ns#" term="C#" /><category scheme="http://www.blogger.com/atom/ns#" term="Opinion" /><title>Automatizando el proceso de build de tu proyecto (2/n)</title><content type="html">&lt;h2&gt;Development tRee&lt;/h2&gt; &lt;p&gt;Seguimos con las series dedicadas a automatizar el proceso de build para nuestros proyectos.&lt;/p&gt; &lt;p&gt;En esta entrada definiremos un &lt;em&gt;development tree&lt;/em&gt; a utilizar en nuestro proyecto. Esto no es más que un nombre sofisticado para denominar una estructura de organización para todos los ficheros que forman nuestros proyectos, ya sean ficheros de código, recursos, scripts, etc.&lt;/p&gt; &lt;p&gt;Esta no sólo persigue la organización de los ficheros, sino que es básico que tengamos una estructura "estandar" para poder referenciar los diferentes elementos de cara a construir un script que podamos reutilizar. Entrecomillo estándar porque obviamente no hay unas reglas categóricas para estructurar nuestros proyectos: es algo que depende de nuestros gustos y necesidades.&lt;/p&gt; &lt;p&gt;La estructura de directorios (representados por \) y los ficheros (representados por -&amp;gt;) que tengo definida actualmente es la siguiente. &lt;/p&gt;&lt;pre class="xml" name="code"&gt;base&lt;br /&gt;	|- \tools&lt;br /&gt;	|&lt;br /&gt;	|- \builds&lt;br /&gt;	|	-&amp;gt; &amp;lt;MainProjectName&amp;gt;.&amp;lt;builddate&amp;gt;.zip&lt;br /&gt;	|				|-\output&lt;br /&gt;	|				|-\reports&lt;br /&gt;	|				|-\documentation&lt;br /&gt;	|	-&amp;gt; ...&lt;br /&gt;	|&lt;br /&gt;	|- \libs&lt;br /&gt;	|&lt;br /&gt;	|- \projects&lt;br /&gt;	|	|- \&amp;lt;VisualStudioProject1&amp;gt;&lt;br /&gt;	|	|	|- \Properties&lt;br /&gt;	|	|		-&amp;gt; guid.txt&lt;br /&gt;	|	|		-&amp;gt; version.txt&lt;br /&gt;	|	|		-&amp;gt; publickey.snk&lt;br /&gt;	|	|- \&amp;lt;VisualStudioProject2&amp;gt;&lt;br /&gt;	|	|	|- \Properties&lt;br /&gt;	|	|		-&amp;gt; guid.txt&lt;br /&gt;	|	|		-&amp;gt; version.txt&lt;br /&gt;	|	|		-&amp;gt; publickey.snk&lt;br /&gt;	|	|- ...&lt;br /&gt;	|	|&lt;br /&gt;	|	|- \&amp;lt;VisualStudioProjectN&amp;gt;&lt;br /&gt;	|	|	|- \Properties&lt;br /&gt;	|	|		-&amp;gt; guid.txt&lt;br /&gt;	|	|		-&amp;gt; version.txt&lt;br /&gt;	|	|		-&amp;gt; publickey.snk&lt;br /&gt;	|	|- \tests&lt;br /&gt;	|		|- \unit&lt;br /&gt;	|		|- \ui&lt;br /&gt;	|		|- \ ...&lt;br /&gt;	|&lt;br /&gt;	|- \resources&lt;br /&gt;		|- \icons&lt;br /&gt;		|- \images&lt;br /&gt;		|- \sounds&lt;br /&gt;		|- ...&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;La idea es que la estructura completa desde el directorio root va al repositorio de código, de forma que al hacer un checkout obtengamos todo lo necesario para generar el proyecto, aunque eso implique que tendremos datos repetidos entre diferentes proyectos.&lt;/p&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;&lt;strong&gt;root&lt;/strong&gt;: Aquí va el fichero de build para NAnt y algunos más que servirán para definir &lt;br /&gt;&lt;li&gt;&lt;strong&gt;tools&lt;/strong&gt;: En este directorio van los binarios necesarios para el proceso de build: NAnt, NUnit, etc. &lt;br /&gt;&lt;li&gt;&lt;strong&gt;builds&lt;/strong&gt;: Aquí se generará las última build del proyecto. Contendrá un fichero zip con el proyecto listo para ejecutar y opcionalmente unos informes con los resultados de las pruebas y la documentación. &lt;br /&gt;&lt;li&gt;&lt;strong&gt;libs&lt;/strong&gt;: Todas las librerías externas necesarias para generar el proyecto van aquí. Pueden organizarse también en subdirectorios si es necesario &lt;br /&gt;&lt;li&gt;&lt;strong&gt;projects&lt;/strong&gt;: Aquí van todos los ficheros de código necesarios para generar el proyecto. En mi caso sólo tengo en este directorio el fichero de solución de visual studio. El resto de proyectos va cada uno en un subcarpetas: &lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;&amp;lt;VisualStudioProjectN&amp;gt; Contiene el código y el fichero de proyecto de Visual studio para generar un assembly (librería o ejecutable). En la subcarpeta Properties tenemos además tres ficheros necesarios para generar siempre un assembly firmado: &lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;guid.txt: contiene un número Guid asociado al proyecto &lt;br /&gt;&lt;li&gt;publickey.snk: clave pública para fir &lt;br /&gt;&lt;li&gt;version.txt: contiene un número de versión para el ensamblado en formato Major.Minor.Build.Revision. &lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;li&gt;tests: Aquí van todos los proyectos de visual studio con los assemblies de tests que utilicemos en el proyecto, también organizados en subcarpetas si es necesario.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;li&gt;&lt;strong&gt;resources&lt;/strong&gt;: Resto de ficheros que pertenecen al proyecto: imágenes con logos, sonidos,&amp;nbsp; etc.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;p&gt;Por supuesto aquí hay bastante margen para añadir cosas: scripts para generar bases de datos, ficheros de localización, etc. La idea principal a transmitir es que una vez definida una estructura que nos sirva, podemos automatizar el proceso de generación en base a dicha estructura. Por ejemplo podemos crear un target para NAnt que compile todo fichero .csproj encontrado en projects/tests, y luego utilizando esos resultados, ejecutar nunit desde la consola de comandos para generar un informe que nos indique el estado de los tests.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;En mi proceso, además, he definido propiedades para cada uno de los directorios principales de la estructura, de forma que sea más cómodo utilizarlo en los scripts. Por ejemplo, para acceder al directorio root se define la propiedad ${dir.root}. Para acceder al directorio de proyectos, utilizo ${dir.projects}. Para ser consistente en realidad ésta última debería ser ${dir.root.projects}, pero hace que las propiedades aumenten su tamaño, y decidí optar por eliminarlo. Las propiedades se definirían:&lt;/p&gt;&lt;pre class="xml" name="code"&gt;&amp;lt;properties&amp;gt;&lt;br /&gt;	&amp;lt;!-- DO NOT DELETE ANY PROPERTY DEFINED IN THIS FILE --&amp;gt;	&lt;br /&gt;	&lt;br /&gt;	&amp;lt;property &lt;br /&gt;		name="dir.root" &lt;br /&gt;		value="${project::get-base-directory()}" /&amp;gt;&lt;br /&gt;	&lt;br /&gt;	&amp;lt;property &lt;br /&gt;		name="dir.tools" &lt;br /&gt;		value="${dir.root}/tools" /&amp;gt;&lt;br /&gt;	&lt;br /&gt;	&amp;lt;property &lt;br /&gt;		name="dir.resources"&lt;br /&gt;		value="${dir.root}/resources" /&amp;gt;&lt;br /&gt;&lt;br /&gt;	&amp;lt;property &lt;br /&gt;		name="dir.builds"&lt;br /&gt;		value="${dir.root}/builds" /&amp;gt;		&lt;br /&gt;				&lt;br /&gt;	&amp;lt;property &lt;br /&gt;		name="dir.libs"&lt;br /&gt;		value="${dir.root}/libs" /&amp;gt;&lt;br /&gt;				&lt;br /&gt;	&amp;lt;property &lt;br /&gt;		name="dir.projects" &lt;br /&gt;		value="${dir.root}/projects" /&amp;gt;		&lt;br /&gt;		&lt;br /&gt;	&amp;lt;property &lt;br /&gt;		name="dir.tests" &lt;br /&gt;		value="${dir.projects}/tests" /&amp;gt;		&lt;br /&gt;&lt;br /&gt;	&amp;lt;property &lt;br /&gt;		name="dir.tests.unit" &lt;br /&gt;		value="${dir.tests}/unit" /&amp;gt;	&lt;br /&gt;&lt;br /&gt;			&lt;br /&gt;	&amp;lt;property&lt;br /&gt;		name="dir.projects.temp"&lt;br /&gt;		value="${dir.projects}/tmp" /&amp;gt;	&lt;br /&gt;	&lt;br /&gt;	&amp;lt;property&lt;br /&gt;		name="dir.projects.temp.output"&lt;br /&gt;		value="${dir.projects.temp}/output" /&amp;gt;	&lt;br /&gt;&lt;br /&gt;	&amp;lt;property&lt;br /&gt;		name="dir.projects.temp.reports"&lt;br /&gt;		value="${dir.projects.temp}/reports" /&amp;gt;	&lt;br /&gt;&lt;br /&gt;	&amp;lt;property&lt;br /&gt;		name="dir.projects.temp.docs"&lt;br /&gt;		value="${dir.projects.temp}/docs" /&amp;gt;					&lt;br /&gt;&amp;lt;/properties&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;Y eso es todo por hoy! Cualquier comentario o sugerencia sobre la estructura elegida será -como siempre- bien recibida.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;a href="http://crazypointer.blogspot.com/2008/12/automatizando-el-proceso-de-build-de-tu.html"&gt;Automatizando el proceso de build de tu proyecto 1&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5754664854663769426-5994900945931028905?l=www.crazypointer.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/CrazyPointer?a=UOd253H2aHE:RSfTLfeAwJM:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CrazyPointer?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CrazyPointer?a=UOd253H2aHE:RSfTLfeAwJM:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CrazyPointer?i=UOd253H2aHE:RSfTLfeAwJM:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CrazyPointer/~4/UOd253H2aHE" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.crazypointer.com/feeds/5994900945931028905/comments/default" title="Enviar comentarios" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=5754664854663769426&amp;postID=5994900945931028905" title="0 comentarios" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5754664854663769426/posts/default/5994900945931028905?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5754664854663769426/posts/default/5994900945931028905?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CrazyPointer/~3/UOd253H2aHE/automatizando-el-proceso-de-build-de-tu.html" title="Automatizando el proceso de build de tu proyecto (2/n)" /><author><name>Ricky</name><uri>http://www.blogger.com/profile/18324470751965509112</uri><email>rickyah@gmail.com</email><gd:extendedProperty name="OpenSocialUserId" value="10817153364417160719" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://www.crazypointer.com/2009/01/automatizando-el-proceso-de-build-de-tu.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CE8BQXo_fSp7ImA9WxVTGUw.&quot;"><id>tag:blogger.com,1999:blog-5754664854663769426.post-5528794164364783578</id><published>2009-01-02T13:47:00.001+01:00</published><updated>2009-01-02T17:14:10.445+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-01-02T17:14:10.445+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="VideoGames" /><title>Post-mortem: Ratchet &amp; Clank</title><content type="html">&lt;p&gt;&lt;a href="http://www.gamasutra.com/view/feature/3889/postmortem_insomniacs_ratchet__.php"&gt;Aquí tenéis un link&lt;/a&gt; al interesante post-mortem del juego &lt;em&gt;Ratchet &amp;amp; Clank:Tools of Destruction&lt;/em&gt; (&lt;em&gt;Ratchet &amp;amp; Clank: Armados hasta los dientes&lt;/em&gt; en español) de Insomniac, proporcionado por &lt;a href="http://www.gamasutra.com"&gt;Gamasutra&lt;/a&gt;.&lt;br&gt;A destacar el sistema para el desarrollo de proyectos que usan, dos proyectos simultáneos en diferentes fases: mientras el grueso del equipo se encuentra inmerso en la producción del título actual, otro grupo más reducido ya está metido de lleno en la preproducción del siguiente, solapando ambas fases en el tiempo. &lt;/p&gt; &lt;p&gt;Durante la preproducción se crea un prototipo funcional del juego, lo que les permite descubrir los posibles problemas técnicos que tendrán que afrontar, así como los cambios necesarios del gameplay. Todo el conocimiento obtenido en esa fase se utiliza para establecer el diseño final del juego para finalmente pasar a producción.&lt;/p&gt; &lt;p&gt;También es de destacar su intento por seguir un sistema de &lt;a href="http://agilemanifesto.org/"&gt;desarrollo ágil&lt;/a&gt; de forma que intentan obtener versiones funcionales del juego, que mejoran en posteriores iteraciones, en contraposición a desarrollar diferentes partes del núcleo jugable perfectas, tal y como lo hacían anteriormente. De hecho, la agilidad era una de las cosas que ya destacaban en el post-mortem del Resistance:Fall of Men que apareció en la &lt;a href="http://www.gdmag.com/archive/feb07.htm"&gt;Game Developer Magazine de Febrero 2007&lt;/a&gt;.&lt;/p&gt; &lt;p align="center"&gt;&lt;a href="http://lh6.ggpht.com/_y5KbcXiMsPA/SV49Srw9zmI/AAAAAAAAARA/Tlgt4PwIhzI/s1600-h/754594362_03f10b7702_o%5B9%5D.jpg"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="380" alt="Ratchet &amp;amp; Clank Future" src="http://lh5.ggpht.com/_y5KbcXiMsPA/SV49T2GXoLI/AAAAAAAAARE/agO2xVQwqeU/754594362_03f10b7702_o_thumb%5B7%5D.jpg?imgmax=800" width="660" border="0"&gt;&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5754664854663769426-5528794164364783578?l=www.crazypointer.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/CrazyPointer?a=hBUtWlAJtI0:WPqsJT4lHIo:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CrazyPointer?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CrazyPointer?a=hBUtWlAJtI0:WPqsJT4lHIo:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CrazyPointer?i=hBUtWlAJtI0:WPqsJT4lHIo:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CrazyPointer/~4/hBUtWlAJtI0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.crazypointer.com/feeds/5528794164364783578/comments/default" title="Enviar comentarios" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=5754664854663769426&amp;postID=5528794164364783578" title="2 comentarios" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5754664854663769426/posts/default/5528794164364783578?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5754664854663769426/posts/default/5528794164364783578?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CrazyPointer/~3/hBUtWlAJtI0/postmortem-ratchet-clank.html" title="Post-mortem: Ratchet &amp;amp; Clank" /><author><name>Ricky</name><uri>http://www.blogger.com/profile/18324470751965509112</uri><email>rickyah@gmail.com</email><gd:extendedProperty name="OpenSocialUserId" value="10817153364417160719" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total><feedburner:origLink>http://www.crazypointer.com/2009/01/postmortem-ratchet-clank.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0cGSX46eCp7ImA9WxRaGEs.&quot;"><id>tag:blogger.com,1999:blog-5754664854663769426.post-4416980165686427238</id><published>2008-12-21T13:00:00.001+01:00</published><updated>2008-12-21T13:03:48.010+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-12-21T13:03:48.010+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="PersonalProjects" /><category scheme="http://www.blogger.com/atom/ns#" term="C#" /><category scheme="http://www.blogger.com/atom/ns#" term="Opinion" /><title>Automatizando el proceso de build de tu proyecto (1/n)</title><content type="html">&lt;p&gt;Al fin he terminado un pequeño proyecto personal que he estado realizando en mis ratos libres, que es la definición de un estándar personal para la organización y generación de mis proyectos en .NET. Suena muy rimbombante, pero no significa otra cosa que definir una estructura de directorios para organizar los diferentes ficheros que componen un proyecto (resources, ficheros de código), así como automatizar el proceso de build de un proyecto y los resultados generados (compilar, ejecutar tests y generar informes sobre el estado de la generación, etc). &lt;/p&gt; &lt;h1&gt;&lt;/h1&gt; &lt;h2&gt;Herramientas para automatización del proceso de build&lt;/h2&gt; &lt;p&gt;En mi caso, el &lt;abbr title="build process"&gt;proceso de build&lt;/abbr&gt; de un proyecto incluye:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Compilar todos los módulos que componen el proyecto a partir de la última versión del código fuente(obteniendo dicho código del servidor de control de código)  &lt;li&gt;Ejecutar los test-unitarios  &lt;li&gt;Generar informes, en mi caso sólo del resultado de la ejecución previa de los test unitarios  &lt;li&gt;Generar la documentación  &lt;li&gt;Preparar y empaquetar todo lo generado para distribuir la última versión de la build&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Al ser un proceso altamente repetitivo -y por tanto propenso a errores- es un gran candidato a una automatización. Para ello existen varias herramientas, siendo las más conocidas en el caso de .NET:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/MSBuild"&gt;MSBuild&lt;/a&gt; propiedad de y utilizado por Microsoft (de hecho los ficheros *.*proj de Visual Studio son ficheros de definición de &lt;a href="http://en.wikipedia.org/wiki/MSBuild"&gt;MSBuild&lt;/a&gt;).  &lt;li&gt;&lt;a href="http://nant.sourceforge.net/"&gt;NAnt&lt;/a&gt;, un port de la herramienta &lt;a href="http://en.wikipedia.org/wiki/Apache_Ant"&gt;Ant&lt;/a&gt; que se creo para projectos Java.&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;He decidido implementar la automatización utilizando &lt;a href="http://nant.sourceforge.net/"&gt;NAnt&lt;/a&gt;, simplemente por la posibilidad de aprovechar el conocimiento de cara a necesitar hacer algo con Ant para móviles, y porque me parecía subjetivamente más maduro: Microsoft lanzó &lt;a href="http://en.wikipedia.org/wiki/MSBuild"&gt;MSBuild&lt;/a&gt; al público de forma gratuita e indepente de Visual Studio hace relativamente poco, y &lt;a href="http://nant.sourceforge.net/"&gt;NAnt&lt;/a&gt; comenzó su andadura allá por el 2001. Además éste último es open source.&lt;/p&gt; &lt;p&gt;Ambas herramientas se basan en conceptos similares:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;&lt;em&gt;targets&lt;/em&gt;: Representa un resultado que queremos obtener en el proyecto. Típicos ejemplos de targets pueden ser 'clean', que elimina los ficheros binarios y temporales para dejar el código fuente preparado para compilar de nuevo, un target 'compile' para compilar el código y regenerar todo el proyecto, etc.  &lt;li&gt;&lt;em&gt;tasks&lt;/em&gt;: Las tareas son la base con las que realizamos las operaciones para llegar a un target. &lt;a href="http://nant.sourceforge.net/release/latest/help/tasks/"&gt;Están predefinidas&lt;/a&gt;, aunque podemos agregar tareas externas &lt;a href="http://nantcontrib.sourceforge.net/release/latest/help/tasks/"&gt;(NantContrib&lt;/a&gt;es un proyecto para agregar tareas útiles no incluidas en el proyecto NAnt), así como crear tareas personalizadas. Típicas tareas pueden ser operaciones sobre los ficheros (mover, copiar, borrar o generar nuevos ficheros o directorios), llamar al compilador con una lista de ficheros para que genere un ejecutable o una librería, etc.  &lt;li&gt;&lt;em&gt;properties&lt;/em&gt;: Las propiedades nos permiten definir pares clave-valor dentro de la configuración. Se puede pensar en ellas como variables. Por ejemplo la propiedad project.sourcedirectory, podría representar el path al directorio donde se encuentran los ficheros de código del proyecto&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Los ficheros de configuración de estas herramientas se construyen como ficheros XML con extensión .build, donde definimos los targets del proyecto y las tareas que lo componen, definimos las propiedades, etc. &lt;/p&gt; &lt;h2&gt;ejemplo de fichero básico de build para NAnt&lt;/h2&gt;&lt;pre class="xml" name="code"&gt;&amp;lt;project name="example nant-build"&amp;gt;&lt;br /&gt;	&amp;lt;property name="mySolutionPath" value="C:\dev\testproject\solution.sln" /&amp;gt;&lt;br /&gt;	&amp;lt;property name="myReferencesDir" value="C:\dev\testproject\references" /&amp;gt;&lt;br /&gt;&lt;br /&gt;	&amp;lt;target name="compile"&amp;gt;&lt;br /&gt;		&amp;lt;solution &lt;br /&gt;			configuration="Release"&lt;br /&gt;			solutionfile="${mySolutionPath}"&amp;gt;&lt;br /&gt;    			&amp;lt;projects&amp;gt;&lt;br /&gt;        			&amp;lt;include name="${mySolutionPath}\other.csproj" /&amp;gt;&lt;br /&gt;	    		&amp;lt;/projects&amp;gt;&lt;br /&gt;    			&amp;lt;excludeprojects&amp;gt;&lt;br /&gt;				&amp;lt;include name="${mySolutionPath}\toexclude.csproj" /&amp;gt;&lt;br /&gt;    			&amp;lt;/excludeprojects&amp;gt;&lt;br /&gt;    			&amp;lt;referenceprojects&amp;gt;&lt;br /&gt;        			&amp;lt;include name="${myReferencesDir}\*.dll" /&amp;gt;&lt;br /&gt;	    		&amp;lt;/referenceprojects&amp;gt;&lt;br /&gt;&lt;br /&gt;			&amp;lt;echo message="Solution generated sucessfully!" /&amp;gt;&lt;br /&gt;		&amp;lt;/solution&amp;gt;&lt;br /&gt;	&amp;lt;/target&amp;gt;&lt;br /&gt;&amp;lt;/project&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;El anterior fichero de configuración define dos propiedades: 'mySolutionPath y myReferencesDir', el valor de las cuales es el path al fichero de solución Visual Studio del proyecto, y el path a un directorio de referencias necesarias para el proyecto respectivamente. Estas propiedades se encuentran bajo la etiqueta 'proyect' así que son visibles para todo target definido dentro de este proyecto. Las propiedades se referenciarán más tarde en el fichero de configuración encerrándolas entre ${ &amp;lt;nombre_propiedad&amp;gt; }&lt;/p&gt;&lt;br /&gt;&lt;p&gt;A continuación se define un target llamado 'compile', el cual consta de una sóla tarea: 'solution'. Esta tarea simplemente compilará el proyecto usando un fichero de solución (.sln) de visual studio especificado, por lo que equivale a ejecutar el comando Build (Generar) en dicho &lt;abbr title="Integrated Development Environment"&gt;IDE&lt;/abbr&gt;. Por supuesto podemos tener tanto control como queramos a la hora de compilar el código, y podemos si así fuera necesario llamar directamente al compilador de C# con los argumentos apropiados y una lista de ficheros concretos, lo que puede ser muy útil en algunos casos (ahora mismo me viene a la cabeza que sería muy útil para generar http://en.wikipedia.org/wiki/.NET_assembly#Satellite_assemblies :)) &lt;/p&gt;&lt;br /&gt;&lt;p&gt;La tarea 'solution' a su vez contiene varios parámetros definidos tanto por medio de atributos XML como de etiquetas hijo:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Atributos XML: &lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;configuration: especifica la configuración a aplicar a la hora de generar el código (Release, Debug), de la misma manera que podemos hacer en Visual Studio &lt;br /&gt;&lt;li&gt;solutionfile: indica la ruta donde se encuentra el fichero de solución de Visual Studio. No es necesario que sea un path absoluto, puede ser relativo a la ruta donde se encuentra ubicado el fichero .build&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;li&gt;etiquetas hijo: &lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;projects: define una lista de ficheros de proyecto a generar. Por defecto la tarea 'solution' genera todos los proyectos definidos en el fichero de solucion, aunque podría ser necesario especificar que sólo genera un subconjunto de ellos. &lt;br /&gt;&lt;li&gt;excludeprojects: define una lista de ficheros de proyecto a excluir de la generación &lt;br /&gt;&lt;li&gt;referenceprojects: define una lista de ficheros que son necesarios referenciar para la generación de la solución &lt;br /&gt;&lt;li&gt;echo: muestra el texto especificado con el atributo 'message' en la consola&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Una vez terminado, sólo tendremos que ejecutar nant desde la línea de comandos especificando el target (si sólo hay un fichero de build en el directorio, nant lo usa automáticamente):&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;em&gt;nant compile&lt;/em&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Y automágicamente el proyecto se generará ;)&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Como veis esta "simple" tarea reemplaza al comando build de visual studio. Puede parecer una tontería teniendo ya disponible el comando en el editor, pero la idea es que podamos generar el proyecto entero sin necesitar que Visual Studio esté ejecutándose (aunque NAnt requiere que el SDK de .NET, MSBuild u otras herramientas estén instaladas en el sistema para ser capaz de ejecutar según qué tareas )&lt;/p&gt;&lt;br /&gt;&lt;p&gt;La idea es construir un fichero de build para NAnt que realice las tareas necesarias para nuestro proyecto. Por ejemplo, esto es lo que se muestra cuando ejecutamos el target tarea "Help" (que es la tarea por defecto) sobre mi fichero de configuración:&lt;/p&gt;&lt;pre&gt;Buildfile: file:///&lt;mybuildfilepath&gt;/ProjectGenerator/buildfile.build&lt;br /&gt;Target framework: Microsoft .NET Framework 3.5&lt;br /&gt;Target(s) specified: Help &lt;br /&gt;&lt;br /&gt;   [tstamp] lunes, 15 de diciembre de 2008 23:28:49.&lt;br /&gt;   [tstamp] build-process.date = 15-12-2008 23h 28m 49s.&lt;br /&gt;     [echo] [INFO] Including external files:&lt;br /&gt;     [echo]  -&amp;gt; development-tree.definition.buildinclude&lt;br /&gt;     [echo]  -&amp;gt; external-tool.paths.buildinclude&lt;br /&gt;     [echo]  -&amp;gt; project.properties.buildinclude&lt;br /&gt;     [echo] &lt;br /&gt;     [echo] [INFO] Performing checks... &lt;br /&gt;     [echo]  --&amp;gt; Checking development tree properties&lt;br /&gt;     [echo]  --&amp;gt; Checking project properties...&lt;br /&gt;     [echo] [OK] All checks passed&lt;br /&gt;     [echo] &lt;br /&gt;     [echo] [INFO] Using default solution file:&lt;br /&gt;     [echo]  -&amp;gt; AutomatedProjectGenerator.sln&lt;br /&gt;     [echo] &lt;br /&gt;     [echo] [INFO] Using default versioning file:&lt;br /&gt;     [echo]  -&amp;gt; version.number&lt;br /&gt;     [echo] &lt;br /&gt;     [echo] [INFO] Using default guid file:&lt;br /&gt;     [echo]  -&amp;gt; guid.number&lt;br /&gt;     [echo] &lt;br /&gt;     [echo] [INFO] Using default assemblyl file:&lt;br /&gt;     [echo]  -&amp;gt; CommonProjectAssembly.cs&lt;br /&gt;     [echo] &lt;br /&gt;     [echo] [INFO] Using tests reports file:&lt;br /&gt;     [echo]  -&amp;gt; UnitTestsReports&lt;br /&gt;     [echo] &lt;br /&gt;&lt;br /&gt;Help:&lt;br /&gt;&lt;br /&gt;     [echo] -----------------------------------------------------&lt;br /&gt;     [echo]  'AutomatedProjectGenerator' build file Targets   &lt;br /&gt;     [echo] -----------------------------------------------------&lt;br /&gt;     [echo] &lt;br /&gt;     [exec] &lt;br /&gt;     [exec] Skeleton file for the build process&lt;br /&gt;     [exec] &lt;br /&gt;     [exec] Default Target: &lt;br /&gt;     [exec] &lt;br /&gt;     [exec] Help                - Lists the available targets in the build file&lt;br /&gt;     [exec] &lt;br /&gt;     [exec] Main Targets: &lt;br /&gt;     [exec] &lt;br /&gt;     [exec] build               - Builds project and runs unit tests, placing the results in the publish directory&lt;br /&gt;     [exec] build-debug         - Like the build target, but using the debug configuration when building&lt;br /&gt;     [exec] clean               - Cleans up the build environment&lt;br /&gt;     [exec] CodeAnalisys        - Analyses the generated assemblies using FXCop&lt;br /&gt;     [exec] Compile             - Compiles the project&lt;br /&gt;     [exec] GenerateDoc         - Generate documentation files&lt;br /&gt;     [exec] GenerateGUID        - Generates a new GUID for the project&lt;br /&gt;     [exec] GenerateReports     - Generate unit tests and coverage reports&lt;br /&gt;     [exec] Get                 - Grabs the code from the repository&lt;br /&gt;     [exec] Help                - Lists the available targets in the build file&lt;br /&gt;     [exec] IncreaseBuildNumber - Updates project's version build number&lt;br /&gt;     [exec] IncreaseMajorNumber - Increases project's version major number&lt;br /&gt;     [exec] IncreaseMinorNumber - Increases project's version minor number&lt;br /&gt;     [exec] MoveToLastBuild     - Moves last generated build files to the publish directory&lt;br /&gt;     [exec] publish		- Zips all assets generated in the publish directory, getting it ready to be deployed&lt;br /&gt;     [exec] RepositoryCleanup   - Issues a 'cleanup' command to the repository&lt;br /&gt;     [exec] RunTests            - Run unit tests&lt;br /&gt;     [exec] UpdateDataAssembly  - Updates data assembly file and commits it to the repository&lt;br /&gt;     [exec] UpdateVersionFile   - Updates the versioning file and commits it to the repository&lt;br /&gt;     [exec] &lt;br /&gt;     [exec] Sub Targets: &lt;br /&gt;     [exec] &lt;br /&gt;     [exec] CloseLogs           &lt;br /&gt;     [exec] CommitDir           &lt;br /&gt;     [exec] ComputeIncludeList  &lt;br /&gt;     [exec] Failure             &lt;br /&gt;     [exec] StartLogs           &lt;br /&gt;     [exec] Success             &lt;br /&gt;     [exec] &lt;br /&gt;     [exec] &lt;br /&gt;     [echo] [INFO] Subtargets should not be called by the user&lt;br /&gt;&lt;br /&gt;CloseLogs:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Success:&lt;br /&gt;&lt;br /&gt;     [echo] [OK] BUILD SUCCEDED See build.lastbuild.log for details&lt;br /&gt;&lt;br /&gt;BUILD SUCCEEDED&lt;br /&gt;&lt;br /&gt;Total time: 1.1 seconds.&lt;/pre&gt;En posteriores entradas describiré un poco cómo he organizado la estructura de directorios para un proyecto y colgaré instrucciones y todo lo necesario para utilizar la configuración de nant que he creado, en caso de que a alguien le interese.  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5754664854663769426-4416980165686427238?l=www.crazypointer.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/CrazyPointer?a=5BoKRXDounQ:PMbIZpTwLGI:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CrazyPointer?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CrazyPointer?a=5BoKRXDounQ:PMbIZpTwLGI:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CrazyPointer?i=5BoKRXDounQ:PMbIZpTwLGI:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CrazyPointer/~4/5BoKRXDounQ" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.crazypointer.com/feeds/4416980165686427238/comments/default" title="Enviar comentarios" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=5754664854663769426&amp;postID=4416980165686427238" title="4 comentarios" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5754664854663769426/posts/default/4416980165686427238?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5754664854663769426/posts/default/4416980165686427238?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CrazyPointer/~3/5BoKRXDounQ/automatizando-el-proceso-de-build-de-tu.html" title="Automatizando el proceso de build de tu proyecto (1/n)" /><author><name>Ricky</name><uri>http://www.blogger.com/profile/18324470751965509112</uri><email>rickyah@gmail.com</email><gd:extendedProperty name="OpenSocialUserId" value="10817153364417160719" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">4</thr:total><feedburner:origLink>http://www.crazypointer.com/2008/12/automatizando-el-proceso-de-build-de-tu.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkMGRH84fSp7ImA9WxRaEkg.&quot;"><id>tag:blogger.com,1999:blog-5754664854663769426.post-169775798207165786</id><published>2008-12-14T13:40:00.001+01:00</published><updated>2008-12-14T13:40:25.135+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-12-14T13:40:25.135+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="VisualStudio" /><category scheme="http://www.blogger.com/atom/ns#" term="Python" /><title>IronPython &amp; IronPython Studio</title><content type="html">&lt;p&gt;El pasado 10 de diciembre se lanzó la &lt;a href="http://www.codeplex.com/IronPython/Release/ProjectReleases.aspx?ReleaseId=8365"&gt;versión 2.0&lt;/a&gt; de &lt;a href="http://www.codeplex.com/IronPython/"&gt;IronPython&lt;/a&gt;, la implementación del conocido lenguaje dinámico &lt;a href="http://www.python.org/"&gt;Python&lt;/a&gt; que corre bajo .NET. Esto permite, por ejemplo, que podamos acceder a todas las librerías que ofrece el framework.NET utilizando python, lo que unido a sus capacidades como lenguaje de script, puede ser una herramienta muy interesante de cara a desarrollar prototipos o aplicaciones simples. También para todo tipo de aplicaciones supongo, pero en mi caso no domino muy bien el lenguaje como para eso :)&lt;/p&gt; &lt;p&gt;Una de las novedades destacadas es que ahora utiliza el &lt;a href="http://www.codeplex.com/dlr"&gt;Dynamic Language Runtime&lt;/a&gt; lo que le da, por ejemplo, ventajas de cara a la interoperabilidad, &lt;a href="http://crazypointer.blogspot.com/2008/11/pdc-2008-future-of-c40-13.html"&gt;algo ya comentado cuando hablé de las mejoras que se esperan para c# 4.0&lt;/a&gt;, así como &lt;a href="http://www.codeplex.com/IronPython/Wiki/View.aspx?title=IronPython%20Performance"&gt;importantes mejoras de rendimiento&lt;/a&gt;. También como novedad, el código está disponible como código abierto bajo la &lt;a href="http://www.opensource.org/licenses/ms-pl.html"&gt;Microsoft Public License&lt;/a&gt;.&lt;/p&gt; &lt;p&gt;La versión 2.0 de IronPython es compatible con CPython 2.5, que no es la última versión existente del lenguaje, ya que &lt;a href="http://www.python.org/download/releases/3.0/"&gt;hace escasamente 10 días que salió la versión 3.0 de éste último&lt;/a&gt;. Sin embargo la versión 3.0 de Python no es compatible con las anteriores al incluir nueva funcionalidad y además reorganizar las librerías estándar del lenguaje, así que a día de hoy la versión 2.5 es la que más base de código tiene.&lt;/p&gt; &lt;p&gt;Relacionado con este proyecto tenemos &lt;a href="http://www.codeplex.com/IronPythonStudio"&gt;IronPython Studio&lt;/a&gt;, que utiliza Visual Studio 2008 para propocionar un &lt;abbr title="Integrated Development Environment"&gt;IDE&lt;/abbr&gt; para IronPython, incluyendo plantillas de proyecto iniciales, resaltado de sintaxis y autocompletado de código. Para la instalación podemos elegir entre integrarlo con una instalación ya existente de Visual Studio, o bien instalarlo como un componente independiente.&lt;/p&gt; &lt;p align="center"&gt;&lt;a href="http://lh3.ggpht.com/_y5KbcXiMsPA/SUT-s57L_cI/AAAAAAAAAPQ/ZGjFX9xFZf8/s1600-h/IronPythonIDE%5B4%5D.jpg"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="532" alt="IronPythonIDE" src="http://lh5.ggpht.com/_y5KbcXiMsPA/SUT-uKmQ-0I/AAAAAAAAAPU/yR7FjTrJhFw/IronPythonIDE_thumb%5B2%5D.jpg?imgmax=800" width="755" border="0"&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt; El único problemilla que tiene actualmente es que sigue basado en IronPython 1.0, así que habrá que esperar a que se actualice a la nueva versión.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5754664854663769426-169775798207165786?l=www.crazypointer.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/CrazyPointer?a=_54h1HLF3KQ:ttuOkpFmrnA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CrazyPointer?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CrazyPointer?a=_54h1HLF3KQ:ttuOkpFmrnA:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CrazyPointer?i=_54h1HLF3KQ:ttuOkpFmrnA:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CrazyPointer/~4/_54h1HLF3KQ" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.crazypointer.com/feeds/169775798207165786/comments/default" title="Enviar comentarios" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=5754664854663769426&amp;postID=169775798207165786" title="0 comentarios" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5754664854663769426/posts/default/169775798207165786?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5754664854663769426/posts/default/169775798207165786?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CrazyPointer/~3/_54h1HLF3KQ/ironpython-ironpython-studio.html" title="IronPython &amp;amp; IronPython Studio" /><author><name>Ricky</name><uri>http://www.blogger.com/profile/18324470751965509112</uri><email>rickyah@gmail.com</email><gd:extendedProperty name="OpenSocialUserId" value="10817153364417160719" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://www.crazypointer.com/2008/12/ironpython-ironpython-studio.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C08BRn08fyp7ImA9WxRbF0o.&quot;"><id>tag:blogger.com,1999:blog-5754664854663769426.post-8433276224279818026</id><published>2008-12-08T22:13:00.001+01:00</published><updated>2008-12-08T22:30:57.377+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-12-08T22:30:57.377+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="ParalellComputing" /><category scheme="http://www.blogger.com/atom/ns#" term="Mac" /><category scheme="http://www.blogger.com/atom/ns#" term="FAILinks" /><category scheme="http://www.blogger.com/atom/ns#" term="C#" /><title>Links de la sem... de cuando buenamente pueda</title><content type="html">&lt;p&gt;Bueno, pues más que links de la semana mejor lo empezaré a denominar F.A.I.L (Fun, Aperiodic and Interesting Links)&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Lo primero un interesante artículo de introducción sobre la codificación de caracteres por parte de Joel Spolsky: &lt;a href="http://www.joelonsoftware.com/articles/Unicode.html"&gt;The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)&lt;/a&gt;&lt;/li&gt; &lt;li&gt;Artículo sobre &lt;a href="http://www.moserware.com/2008/09/how-do-locks-lock.html"&gt;cómo funcionan los locks de acceso concurrente en .NET&lt;/a&gt;. Empieza a alto nivel y baja hasta la implementación en ensamblador. Blog muy recomendable el de Jeff Moser, que pasa a engrosar mi lista de blogs de desarrollo :)&lt;/li&gt; &lt;li&gt;Relacionado con el tema anterior (de hecho lo he descubierto por un link en el blog anterior, &lt;a href="http://blogs.msdn.com/vancem/archive/2006/03/28/563180.aspx "&gt;cómo implementar de un Reader-Writer lock&lt;/a&gt;, es decir, un lock que permite el acceso de múltiples hilos para lectura pero sólo uno para escritura.&lt;/li&gt; &lt;li&gt;Intesante &lt;a href="http://macdevelopertips.com/"&gt;página sobre desarrollo en Mac&lt;/a&gt;, con una &lt;a href="http://macdevelopertips.com/screencasts"&gt;sección de screencasts&lt;/a&gt;.&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;No hay muchos links porque me he dado cuenta que la lista de libros que estoy leyendo no ha variado un ápice desde que abrí el blog, así que en vez de mover la rueda del ratón para hacer scroll, me he puesto a pasar páginas&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5754664854663769426-8433276224279818026?l=www.crazypointer.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/CrazyPointer?a=kqGOVoXXm4Y:RygIDkOPJjA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CrazyPointer?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CrazyPointer?a=kqGOVoXXm4Y:RygIDkOPJjA:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CrazyPointer?i=kqGOVoXXm4Y:RygIDkOPJjA:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CrazyPointer/~4/kqGOVoXXm4Y" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.crazypointer.com/feeds/8433276224279818026/comments/default" title="Enviar comentarios" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=5754664854663769426&amp;postID=8433276224279818026" title="1 comentarios" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5754664854663769426/posts/default/8433276224279818026?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5754664854663769426/posts/default/8433276224279818026?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CrazyPointer/~3/kqGOVoXXm4Y/links-de-la-sem-de-cuando-buenamente.html" title="Links de la sem... de cuando buenamente pueda" /><author><name>Ricky</name><uri>http://www.blogger.com/profile/18324470751965509112</uri><email>rickyah@gmail.com</email><gd:extendedProperty name="OpenSocialUserId" value="10817153364417160719" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://www.crazypointer.com/2008/12/links-de-la-sem-de-cuando-buenamente.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0EFQX89eCp7ImA9WxRbF0o.&quot;"><id>tag:blogger.com,1999:blog-5754664854663769426.post-1293144795995007365</id><published>2008-12-01T00:04:00.001+01:00</published><updated>2008-12-08T22:26:50.160+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-12-08T22:26:50.160+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="NewThings" /><category scheme="http://www.blogger.com/atom/ns#" term="C#" /><title>PDC 2008: The Future of C# 4.0 (3/3)</title><content type="html">&lt;p&gt;Y llegamos a la tercera y última entrada de esta mini-serie, donde hablaremos de otra de las características &lt;a href="http://channel9.msdn.com/pdc2008/TL16/"&gt;presentadas para C# 4.0&lt;/a&gt;: covarianza y contravarianza en tipos genéricos.&lt;/p&gt; &lt;p&gt;Primero explicaremos brevemente lo que es la covarianza y la contravarianza, o al menos simplificar un poco la &lt;a href="http://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science)#C.2B.2B"&gt;reseña en la wikipedia&lt;/a&gt; ;)&lt;/p&gt; &lt;p&gt;En POO, una jerarquía de herencia puede verse como una &lt;a href="http://es.wikipedia.org/wiki/Teor%C3%ADa_del_orden"&gt;relación de órden&lt;/a&gt;. Si tenemos por ejemplo esta relación de clases:&lt;/p&gt; &lt;p align="center"&gt;&lt;a href="http://lh5.ggpht.com/_y5KbcXiMsPA/STMdkIUJ95I/AAAAAAAAAOw/Ws4cSICedn0/s1600-h/example%5B3%5D.png"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="190" alt="example" src="http://lh4.ggpht.com/_y5KbcXiMsPA/STMdkkRCLkI/AAAAAAAAAO0/nU-XGFXOmEY/example_thumb%5B1%5D.png?imgmax=800" width="207" border="0"&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;y si definimos la relación A ≤ B significando "B es un A" o que "B es más especializado que A", vemos que cumple una relación matemática de orden parcial (cumple las propiedades reflexiva, antisimétrica y transitiva). &lt;/p&gt; &lt;p&gt;Una vez dicho esto, los términos covarianza y contravarianza, se refieren al tipo de sustitución que podemos hacer, siendo B subtipo de A, y podemos entenderla así:&lt;/p&gt; &lt;table cellspacing="0" cellpadding="2" width="581"&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td valign="top" width="132"&gt;Covarianza&lt;/td&gt; &lt;td valign="top" width="50"&gt;A ≤ B&lt;/td&gt; &lt;td valign="top" width="397"&gt;Podemos sustituir un tipo A por otro más especializado B&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="136"&gt;Contravarianza&lt;/td&gt; &lt;td valign="top" width="53"&gt;A ≥ B&lt;/td&gt; &lt;td valign="top" width="392"&gt;Podemos sustituir un tipo A por otro más genérico B &lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt; &lt;p&gt;Esto lo veremos mejor con ejemplos: considerando la jerarquía anterior, sea un método definido:&lt;/p&gt;&lt;pre class="csharp" name="code"&gt;B MyMethod(B parameter);&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;Las llamadas a métodos son covariantes tanto en sus valores de retorno como en el paso de parámetros; es decir podemos retornar un tipo B, o cualquier subtipo suyo, y podemos pasar como parámetro un tipo B, o cualquier subtipo:&lt;/p&gt;&lt;pre class="csharp" name="code"&gt;void MyMethod(B parameter) { return new D(); }&lt;br /&gt;...&lt;br /&gt;MyMethod( new D() );&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;Sin embargo en los delegados tenemos contravarianza en el paso de parámetro, es decir dado este delegado la asignación es legal &lt;pre class="csharp" name="code"&gt;delegate void MyDelegate(D parameter);&lt;br /&gt;MyDelegate myDelegate; //delegate instance&lt;br /&gt;myDelegate += MyMethod;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;La segunda asignación es válida porque en realidad el delegado está especificando que acepta uno de los (potencialmente muchos) subtipos que acepta el método, con lo que estamos aplicando una restricción mas fuerte. Por tanto estamos asignando MyMethod, que recibe un parámetro de tipo B, a un delegado que espera un tipo D, es decir, sustituimos un tipo concreto por otro más genérico.&lt;/p&gt;&lt;br /&gt;&lt;p&gt; El problema es que todo esto no se aplicaba con herencia cuando usamos tipos genéricos, es decir estos eran invariantes. No podíamos hacer esto:&lt;/p&gt;&lt;pre class="csharp" name="code"&gt;public interface IMyInterface&amp;lt;TYPE&amp;gt; { ... } &lt;/pre&gt;&lt;pre class="csharp" name="code"&gt;public static class Tmp&lt;br /&gt;{&lt;br /&gt;	public static IMyInterface&amp;lt;B&amp;gt; GetData() &lt;br /&gt;	{ &lt;br /&gt;		return new B[] {new B(), new B()}; &lt;br /&gt;	}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;IMyInterface&amp;lt;B&amp;gt; e1 = Tmp.GetData();&lt;br&gt;IMyInterface&amp;lt;A&amp;gt; e2 = e1; // ERROR&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;Esto es a priori perfectamente válido, ya que A es más genérico que B, sin embargo no es una asignación válida en C# al carecer de covarianza en valores de retorno para tipos genéricos. Cuando tengamos disponible C# 4.0, podremos indicar que un tipo genérico concreto admitirá covarianza en valores de retorno por medio de la palabra clave &lt;strong&gt;&lt;font color="#0000ff"&gt;out&lt;/font&gt;&lt;/strong&gt; y declarando el tipo genérico :&lt;/p&gt;&lt;pre class="csharp" name="code"&gt;public interface IMyInterface&amp;lt;out TYPE&amp;gt; { ... }&lt;/pre&gt;Para utilizar contravarianza con genéricos usaremos la palabra clave &lt;strong&gt;&lt;font color="#0000ff"&gt;in&lt;/font&gt;&lt;/strong&gt;. Nueva fusilada de la presentación: &lt;pre class="csharp" name="code"&gt;public interface IComparer&amp;gt;in T&amp;lt;&lt;br /&gt;{&lt;br /&gt;   int Compare(T x, T y);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;IComparerobjComp = GetComparer(); //Returns an IComparer &lt;br /&gt;IComparer&lt;string&gt; strComp = objComp; //Ilegal before 4.0 &lt;br /&gt;&lt;/pre&gt;Queda un punto muy interesante por tratar de la presentación, la novedad de presentar el compilador de C# como un servicio, es decir, podremos llamar al compilador de C# en tiempo de ejecución para compilar el código que queramos y que esté accesible en ese momento. Sin embargo esta característica es similar a una presentada en &lt;a href="http://www.mono-project.com"&gt;Mono&lt;/a&gt;, y la trataré en una entrada posterior :)  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5754664854663769426-1293144795995007365?l=www.crazypointer.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/CrazyPointer?a=Nx0CdQtb4wE:PKSCzBFvcQs:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CrazyPointer?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CrazyPointer?a=Nx0CdQtb4wE:PKSCzBFvcQs:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CrazyPointer?i=Nx0CdQtb4wE:PKSCzBFvcQs:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CrazyPointer/~4/Nx0CdQtb4wE" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.crazypointer.com/feeds/1293144795995007365/comments/default" title="Enviar comentarios" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=5754664854663769426&amp;postID=1293144795995007365" title="0 comentarios" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5754664854663769426/posts/default/1293144795995007365?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5754664854663769426/posts/default/1293144795995007365?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CrazyPointer/~3/Nx0CdQtb4wE/pdc-2008-future-of-c-40-33.html" title="PDC 2008: The Future of C# 4.0 (3/3)" /><author><name>Ricky</name><uri>http://www.blogger.com/profile/18324470751965509112</uri><email>rickyah@gmail.com</email><gd:extendedProperty name="OpenSocialUserId" value="10817153364417160719" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://www.crazypointer.com/2008/12/pdc-2008-future-of-c-40-33.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0EFQX89eSp7ImA9WxRbF0o.&quot;"><id>tag:blogger.com,1999:blog-5754664854663769426.post-7632758931540235424</id><published>2008-11-25T20:54:00.001+01:00</published><updated>2008-12-08T22:26:50.161+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-12-08T22:26:50.161+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="NewThings" /><category scheme="http://www.blogger.com/atom/ns#" term="C#" /><title>PDC 2008: The Future of C# 4.0 (2/3)</title><content type="html">&lt;p&gt;Seguimos comentando la presentación de &lt;a href="http://en.wikipedia.org/wiki/Anders_Hejlsberg"&gt;Anders Hejlsberg&lt;/a&gt; sobre el futuro de C# y las novedades que nos aguardan para la próxima versión.&lt;/p&gt; &lt;p&gt;Ahora le toca el turno a una característica que los usuarios de VB.NET disfrutan también desde siempre y que personalmente no entiendo cómo ha tardado tanto en aparecer en C#: Llamadas a métodos con valores por defecto para los parámetros.&lt;/p&gt; &lt;p&gt;Si has tocado C++ seguramente has echado de menos escribir algo como:&lt;/p&gt;&lt;pre class="csharp" name="code"&gt;void SomeMethod(string connectionString, int timeout = 1000) {...};&lt;br /&gt;...&lt;br /&gt;SomeMethod("myConnectionString"); //1000ms timeout&lt;br /&gt;SomeMethod("otherConnectionString", 3000);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;Esta limitación se puede solventar fácilmente, simplemente escribiendo varias sobrecargas para el método:&lt;/p&gt;&lt;pre class="csharp" name="code"&gt;void SomeMethod(string connectionString , int timeout = 1000) {...};&lt;br /&gt;void SomeMethod(string connectionString):this (connectionString, 1000) {...}&lt;br /&gt;&lt;br /&gt;SomeMethod("myConnectionString"); //1000ms timeout&lt;br /&gt;SomeMethod("otherConnectionString", 3000);&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;Pero escribir más sobrecargas implica... escribir más código. Eso es algo que el propio compilador podría hacer y que de hecho ya hacía en otros lenguajes, por lo que realmente era una carencia ... curiosa.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Quizá para implorar el perdón de las hordas, además de prometer que a partir de ahora se intentaría que ambos lenguajes (VB.NET y C#) evolucionen de forma paralela para mantener en ambos funcionalidad similar, se añadirá la posibilidad de utilizar parámetros con nombre dentro de métodos con parámetros por defecto. Eso implica que ahora podremos elegir qué parametros por defecto utilizar, y no estaremos limitados a utilizarlos en el orden declarado. &lt;strike&gt;Por ejemplo&lt;/strike&gt;Fusilando de nuevo, si tenemos &lt;/p&gt;&lt;pre class="csharp" name="code"&gt;public StreamReader OpenTextFile(&lt;br /&gt;    string path,&lt;br /&gt;    Encoding encoding = null,&lt;br /&gt;    bool detectEncoding = true,&lt;br /&gt;    int bufferSize = 1024);&lt;/pre&gt;Podríamos llamarlo así: &lt;pre class="csharp" name="code"&gt;OpenTextFile("C:\mypath");&lt;br /&gt;OpenTextFile("C:\mypath",Encoding.ASCII);&lt;br /&gt;OpenTextFile("C:\mypath",Encoding.ASCII, false);&lt;br /&gt;OpenTextFile("C:\mypath",Encoding.ASCII, false, 2048);&lt;/pre&gt;Pero &lt;strong&gt;no&lt;/strong&gt; podríamos llamar a dicho método así: &lt;pre class="csharp" name="code"&gt;OpenTextFile(2048);&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;Es decir, el orden de uso de los parámetros depende de su declaración. De hecho todos los parámetros por defecto deben ser los últimos que se declaren (los que estén "más a la derecha" en la firma del método) &lt;/p&gt;&lt;br /&gt;&lt;p&gt;Sin embargo con parámetros por nombre podremos definir el nombre del parámetro que queremos establecer y el compilador utilizará los valores por defecto para el resto si procede. Así, ahora podríamos hacer:&lt;/p&gt;&lt;pre class="csharp" name="code"&gt;OpenTextFile(bufferSize : 2048, path :"C:\MyPath");&lt;/pre&gt;Siendo esta llamada equivalente a &lt;pre class="csharp" name="code"&gt;OpenTextFile("C:\MyPath", null, true, 2048);&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;Por supuesto los parámetros que no tienen un valor por defecto DEBEN aparecer en la llamada. Además los parámetros con nombre se evaluarán en el orden en que aparezcan en la llamada, y no en el orden en el que estén definidos. &lt;/p&gt;&lt;br /&gt;&lt;p&gt;Para la próxima entrada comentaremos la última novedad, algo por lo que también hubiera &lt;strike&gt;matado&lt;/strike&gt; pagado: covarianza y contra-varianza con generics.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5754664854663769426-7632758931540235424?l=www.crazypointer.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/CrazyPointer?a=4IiSGiYsRJc:Izf4fy9u47k:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CrazyPointer?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CrazyPointer?a=4IiSGiYsRJc:Izf4fy9u47k:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CrazyPointer?i=4IiSGiYsRJc:Izf4fy9u47k:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CrazyPointer/~4/4IiSGiYsRJc" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.crazypointer.com/feeds/7632758931540235424/comments/default" title="Enviar comentarios" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=5754664854663769426&amp;postID=7632758931540235424" title="2 comentarios" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5754664854663769426/posts/default/7632758931540235424?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5754664854663769426/posts/default/7632758931540235424?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CrazyPointer/~3/4IiSGiYsRJc/pdc-2008-future-of-c-40-23.html" title="PDC 2008: The Future of C# 4.0 (2/3)" /><author><name>Ricky</name><uri>http://www.blogger.com/profile/18324470751965509112</uri><email>rickyah@gmail.com</email><gd:extendedProperty name="OpenSocialUserId" value="10817153364417160719" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total><feedburner:origLink>http://www.crazypointer.com/2008/11/pdc-2008-future-of-c-40-23.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0EFQX89eip7ImA9WxRbF0o.&quot;"><id>tag:blogger.com,1999:blog-5754664854663769426.post-2854494085305157394</id><published>2008-11-23T19:55:00.007+01:00</published><updated>2008-12-08T22:26:50.162+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-12-08T22:26:50.162+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="NewThings" /><category scheme="http://www.blogger.com/atom/ns#" term="C#" /><title>PDC 2008: The Future of C#4.0 (1/3)</title><content type="html">&lt;p&gt;Hace aproximadamente un mes se celebró la &lt;a href="https://sessions.microsoftpdc.com/public/timeline.aspx"&gt;Professional Developers Conference 2008&lt;/a&gt;, conferencias dedicadas principalmente a desarrolladores Windows. En esta edición se han presentado múltiples novedades, como el &lt;a href="http://channel9.msdn.com/pdc2008/PC17/"&gt;SDK de Microsoft Surface&lt;/a&gt; (la pena es que me parece que para conseguirlo hay que comprarse también el &lt;a href="http://www.microsoft.com/SURFACE/index.html"&gt;aparatito&lt;/a&gt;, que no es precisamente barato), han presentado novedades sobre &lt;a href="http://en.wikipedia.org/wiki/Windows_7"&gt;Windows 7&lt;/a&gt;, y muchas otra cosas más. Podéis &lt;a href="https://sessions.microsoftpdc.com/public/timeline.aspx"&gt;hacer una búsqueda&lt;/a&gt; para intentar encontrar una conferencia que contenga un tema que os interese. Las vídeos de las conferencias pueden verse por streaming -siempre que tengas instalado &lt;a href="http://silverlight.net/"&gt;Silverlight&lt;/a&gt;- pero también están disponibles para descarga en múltiples formatos; y lo mismo se aplica a las presentaciones utilizadas.&lt;/p&gt; &lt;p&gt;Después del párrafo patrocinado por Microsoft :) vamos a realizar una pequeña serie de posts comentando la presentación que da título a esta entrada y que hasta hoy mismo no he podido mirar: &lt;a href="http://channel9.msdn.com/pdc2008/TL16/"&gt;The future of C#&lt;/a&gt;, presentada por &lt;a href="http://en.wikipedia.org/wiki/Anders_Hejlsberg"&gt;Anders Hejlsberg&lt;/a&gt;, arquitecto jefe del desarrollo del lenguaje C#.&lt;/p&gt; &lt;p&gt;Anders comienza reseñando que las nuevas "tendencias" en programación apuntan a lenguajes de programación declarativos, dinámicos y con soporte para concurrencia, indicando que C# se mueve hacia dichas tendencias:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;&lt;strong&gt;Programación declarativa&lt;/strong&gt;: &lt;a href="http://en.wikipedia.org/wiki/Language_Integrated_Query"&gt;LINQ&lt;/a&gt; nos permite especificar los datos que queremos y cómo los queremos, pero la forma última de acceder a ellos y tratarlos no es de nuestra competencia. La ventaja que esto puede tener es que el compilador JIT podría realizar optimizaciones según el tipo de dato al que accedemos.&lt;br&gt; &lt;li&gt;&lt;strong&gt;Lenguajes dinámicos&lt;/strong&gt;: aunque defensor de los lenguajes y del tipado estático, reconoce muchas virtudes de utilizar un lenguaje dinámico en muchas situaciones. Además, una de las ventajas que tienen los lenguajes dinámicos es la capacidad de metaprogramación. Estos dos aspectos se intentarán mejorar en el lenguaje mediante la palabra clave &lt;strong&gt;&lt;font color="#0000ff"&gt;dynamic&lt;/font&gt;&lt;/strong&gt; y la presentación del compilador de C# como servicio (en próximas entradas :) .&lt;br&gt; &lt;li&gt;&lt;strong&gt;Concurrencia&lt;/strong&gt;: Aquí ya no hay otro truco que el diseñar la aplicación como un grupo de trabajos independientes y paralelizables. Sin embargo hay ya una extensión al lenguaje llamada &lt;a href="http://blogs.msdn.com/somasegar/archive/2008/06/02/june-2008-ctp-parallel-extensions-to-the-net-fx.aspx"&gt;.NET Parallel Extensions&lt;/a&gt; de la que ya &lt;a href="http://msdn.microsoft.com/es-es/concurrency/default(en-us).aspx"&gt;hay disponible una &lt;abbr title="Community Technology Preview "&gt;CPT&lt;/abbr&gt; para su descarga&lt;/a&gt;.&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Pasemos entonces a comentar el primero los añadidos más interesantes de C# presentados:&lt;/p&gt; &lt;h2&gt;Programación dinámica: palabra clave &lt;strong&gt;&lt;font color="#8080ff"&gt;dynamic&lt;/font&gt;&lt;/strong&gt;&lt;/h2&gt; &lt;p&gt;La ejecución de código dinámico no es algo nuevo en .NET, ya hay un esfuerzo para definir un entorno de ejecución dinámico común en todo .NET: el &lt;a href="http://en.wikipedia.org/wiki/Dynamic_Language_Runtime"&gt;&lt;abbr title="Dynamic Language Runtime"&gt;DLR&lt;/abbr&gt;&lt;/a&gt;, que estandariza el sistema de tipos, de enlace dinámico y de generación dinámica de código, de forma que sea accesible para cualquier lenguaje y además permita que las diferentes implementaciones interactúen entre sí de forma más cómoda. Por ejemplo, tanto &lt;a href="http://en.wikipedia.org/wiki/IronRuby"&gt;IronRuby&lt;/a&gt; como &lt;a href="http://en.wikipedia.org/wiki/IronPython"&gt;IronPython&lt;/a&gt;, utilizan el &lt;abbr title="Dinamic Language Runtime"&gt;DLR&lt;/abbr&gt;. Vamos, que es algo así como el &lt;abbr title="Common Lenguage Runtime"&gt;CLR&lt;/abbr&gt; pero en dinámico.&lt;/p&gt; &lt;p align="center"&gt;&lt;a href="http://lh6.ggpht.com/_y5KbcXiMsPA/SSmnFb0LPoI/AAAAAAAAAOo/rr8n7SgKk2E/s1600-h/DLR%5B4%5D.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="447" alt="DLR" src="http://lh3.ggpht.com/_y5KbcXiMsPA/SSmnHl_DkeI/AAAAAAAAAOs/fINVpYpq6zA/DLR_thumb%5B2%5D.png?imgmax=800" width="704" border="0"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;El propósito de la palabra clave &lt;strong&gt;&lt;font color="#0000ff"&gt;dynamic&lt;/font&gt;&lt;/strong&gt; es "comunicarse con cosas que no son una clase .net con tipado estático". Esto se realiza por medio de binders a dichos lenguajes, y&amp;nbsp; como se ve en la figura, entre esas &lt;em&gt;cosas&lt;/em&gt; se incluyen propio código .NET enlazado dinámicamente, java script, Python, Ruby, o bien objetos COM. De hecho esta palabra clave está llamada a dejar obsoleta mi librería &lt;a onmouseover="ddrivetip('Library which simplifies Late Binding calls with C#')" onmouseout="hideddrivetip()" href="http://code.google.com/p/latebindinghelper/" target="_new"&gt;LateBindingHelper&lt;/a&gt;. &lt;strike&gt;Por ejemplo&lt;/strike&gt; Fusilando este código de la presentación, supongamos un objeto Calculator que permite realizar operaciones aritméticas: &lt;/p&gt;&lt;pre class="csharp" name="code"&gt;Calculator calc = GetCalculator();&lt;br&gt;int sum = calc.Add(10, 20);&lt;/pre&gt;Si queremos utilizarlo usando LateBinding: &lt;pre class="csharp" name="code"&gt;object calc = GetCalculator();&lt;br&gt;Type calcType = calc.GetType();&lt;br&gt;object res = calcType.InvokeMember("Add",BindingFlags.InvokeMethod, null,new object[] { 10, 20 });&lt;br&gt;int sum = Convert.ToInt32(res);&lt;/pre&gt;Aprovechando para hacer publicidad ^_^ con librería LateBindingHelper se simplificaría a &lt;pre class="csharp" name="code"&gt;IOperationInvoker calc = BindingFactory.CreateObjectBinding(GetCalculator());&lt;br&gt;int sum = calc.Method("Add").AddParameter(10).AddParameter(20).Invoke&amp;lt;int&amp;gt;();&lt;/pre&gt;Sin embargo utilizando la palabra clave dynamic, todo quedaría: &lt;pre class="csharp" name="code"&gt;dynamic calc = GetCalculator();&lt;br&gt;int sum = calc.Add(10, 20);&lt;/pre&gt;Sin embargo, si cogemos este pequeño código vemos que se están realizando muchas cosas. En la primera línea, la palabra dynamic define una variable con un tipado fuerte. Es decir, una variable declarada con dinamic es de tipo dinámico, que viene a ser una especie de object al poder asignarle cualquier valor. Sin embargo no podemos hacer castings implícitos: &lt;pre class="csharp" name="code"&gt;dynamic x = 1;&lt;br&gt;int i = x; //NO!&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;En la segunda estamos invocando el método &lt;em&gt;Add&lt;/em&gt; de forma dinámica, esto es: el enlace al método se realiza en tiempo de ejecución, y esto ocurre para cualquier operación en la que esté involucrada una variable dynamic. Además, el resultado de la operación se convierte también de forma dinámica al tipo que asignamos, int en este caso.&lt;/p&gt;Es indudable que la nueva keyword &lt;strong&gt;&lt;font color="#0000ff"&gt;dynamic&lt;/font&gt;&lt;/strong&gt; muy útil en muchos casos. Aunque en algunos sitios &lt;a href="http://www.dev102.com/2008/11/03/c-40-dynamic-lookup-are-you-kidding-me/"&gt;ya ponen el grito en el cielo&lt;/a&gt; diciendo que podría sobreutilizarse y derivar en diseños pobres. Yo digo que 'como todo'. Prácticamente cualquier cosa de un lenguaje la puedes utilizar de una manera incorrecta manera y acabar creando un diseño pobre.  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5754664854663769426-2854494085305157394?l=www.crazypointer.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/CrazyPointer?a=RpVvbqmYE_c:ZaUeYhuhCa8:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CrazyPointer?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CrazyPointer?a=RpVvbqmYE_c:ZaUeYhuhCa8:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CrazyPointer?i=RpVvbqmYE_c:ZaUeYhuhCa8:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CrazyPointer/~4/RpVvbqmYE_c" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.crazypointer.com/feeds/2854494085305157394/comments/default" title="Enviar comentarios" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=5754664854663769426&amp;postID=2854494085305157394" title="0 comentarios" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5754664854663769426/posts/default/2854494085305157394?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5754664854663769426/posts/default/2854494085305157394?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CrazyPointer/~3/RpVvbqmYE_c/pdc-2008-future-of-c40-13.html" title="PDC 2008: The Future of C#4.0 (1/3)" /><author><name>Ricky</name><uri>http://www.blogger.com/profile/18324470751965509112</uri><email>rickyah@gmail.com</email><gd:extendedProperty name="OpenSocialUserId" value="10817153364417160719" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://www.crazypointer.com/2008/11/pdc-2008-future-of-c40-13.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0IBRn09eip7ImA9WxRbF0o.&quot;"><id>tag:blogger.com,1999:blog-5754664854663769426.post-1274835840865837404</id><published>2008-11-16T17:36:00.001+01:00</published><updated>2008-12-08T22:25:57.362+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-12-08T22:25:57.362+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="PersonalProjects" /><category scheme="http://www.blogger.com/atom/ns#" term="Design" /><category scheme="http://www.blogger.com/atom/ns#" term="Opinion" /><title>Fluent Interfaces</title><content type="html">&lt;p&gt;Navegando un poco e investigando sobre ideas y tecnología a usar en mi &lt;abbr title="Proyecto Fin Carrera"&gt;PFC&lt;/abbr&gt; llegué a uno de los muchos artículos de &lt;a href="http://martinfowler.com/"&gt;Martin Fowler&lt;/a&gt; donde se discute una forma de generar una &lt;abbr title="Application Programming Interface"&gt;API&lt;/abbr&gt;, que aunque ya conocía en esencia, no sabía que tenía un nombre: &lt;a href="http://www.martinfowler.com/bliki/FluentInterface.html"&gt;Fluent Interfaces&lt;/a&gt;&lt;/p&gt;Básicamente cuando se crea un "interface fluido" se pretende que las operaciones que puedes realizar en un objeto dependan del contexto generado por la operación previa. Con un ejemplo es mucho más sencillo, y corto y pego el que aparece en la &lt;a href="http://en.wikipedia.org/wiki/Fluent_interface"&gt;wikipedia&lt;/a&gt;: &lt;pre class="c++" name="code"&gt;GlutApp app(argc, argv);&lt;br /&gt;app.setDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_ALPHA|GLUT_DEPTH); // Set framebuffer params&lt;br /&gt;app.setWindowSize(500, 500); // Set window params&lt;br /&gt;app.setWindowPosition(200, 200);&lt;br /&gt;app.setTitle("My OpenGL/GLUT App");&lt;br /&gt;app.create();&lt;/pre&gt;El código de arriba crea una ventana de visualización OpenGL usando GLUT. Bien, pues el mismo código utilizando el tipo de interface que discutimos sería: &lt;pre class="c++" name="code"&gt;FluentGlutApp app(argc, argv)&lt;br /&gt;     .withDouble().withRGBA().withAlpha().withDepth()&lt;br /&gt;     .at(200, 200).across(500, 500)&lt;br /&gt;     .named("My OpenGL/GLUT App");&lt;br /&gt;app.create();&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;Personalmente creo que el último ejemplo expresa de forma más clara las operaciones a realizar (inicialización), y sobre todo a qué objeto están dirigidas. Al respecto, y como curiosidad, si habéis utilizado &lt;a href="http://ayende.com/projects/rhino-mocks.aspx"&gt;Rhino Mocks&lt;/a&gt; como librería de Mocks para vuestros casos de prueba, comprobaréis que &lt;a href="http://ayende.com/Wiki/Comparison+of+different+Rhino+Mocks+syntaxes.ashx"&gt;a partir de la versión 3.2 añade una sintaxis fluida&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Dándole vueltas al asunto, me di cuenta que tenía un proyecto previo que podría beneficiarse -y mucho- de este tipo de interfaces: &lt;a onmouseover="ddrivetip('Library which simplifies Late Binding calls with C#')" onmouseout="hideddrivetip()" href="http://code.google.com/p/latebindinghelper/" target="_new"&gt;mi librería para simplificar llamadas utilizando Late Binding en C#&lt;/a&gt;, de la que hablé en una &lt;a href="http://crazypointer.blogspot.com/2008/09/c-late-binding-helper-library.html"&gt;entrada anterior&lt;/a&gt;. Así que dejando aparcado el PFC un tiempo y dedicándole un par de días, he creado la versión &lt;strike&gt;2.0&lt;/strike&gt; 2.1 de la librería, cuyo código está subido ya al repositorio.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Una de las mejoras que provoca el nuevo interface es la llamada de métodos con múltiples parámetros. Por ejemplo, supongamos una operación que recibe 2 parámetros, uno de ellos por referencia:&lt;/p&gt;&lt;pre class="csharp" name="code"&gt;void MyClass.MyOperation(string command, ref int result);&lt;/pre&gt;Con la versión 1.* tendríamos que hacer : &lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;pre class="csharp" name="code"&gt;ILateBindingFacade lb = LateBindingFactory.CreateObject(typeof(MyClass) );&lt;br /&gt;string cmd = "myCommand";&lt;br /&gt;int result;&lt;br /&gt;object[] args = Args.Build(cmd, result);&lt;br /&gt;lb.Call("MyOperation", Args.ByRefIndexs(1), args);&lt;br /&gt;result = args[1];&lt;/pre&gt;Con la nueva versión sin embargo el código queda así: &lt;pre class="csharp" name="code"&gt;IInvoker invoker = LateBindingFactory.CreateObject(typeof(MyClass) );&lt;br /&gt;object result;&lt;br /&gt;invoker.Method("MyOperation")&lt;br /&gt;	.AddArgument("myCommand")&lt;br /&gt;	.AddRefArgument(result)&lt;br /&gt;	.Invoke();&lt;br /&gt;&lt;br /&gt;result = invoker.LastCallArguments[1];&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;Vale que es "mi" librería y que los niños de uno nunca son feos, pero a mi me parece muchísimo más elegante y simple que la primera versión, y no sólo se queda en elegancia, sino que las operaciones permitidas dependen del contexto como había hablado anteriormente. Por ejemplo, si en un objeto IInvoker llamamos a la operación &lt;em&gt;Method&lt;/em&gt; para especificar el nombre de la operación a invocar sobre él, los únicas operaciones que pueden ejecutarse son &lt;em&gt;AddParameter&lt;/em&gt;, &lt;em&gt;AddRefParameter&lt;/em&gt; e &lt;em&gt;Invoke, que son las únicas que tienen sentido&lt;/em&gt;.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;La legibilidad aumenta según más complejo es el uso. Esto se puede ver si retomamos el código para controlar Microsoft Word que tenía en la versión 1.3 de la librería, y lo comparamos con la nueva versión:&lt;/p&gt;&lt;pre class="csharp" name="code"&gt;ILateBindingFacade word = LateBindingFactory.CrateAutomationBinding("Word.Application");&lt;br /&gt;            &lt;br /&gt;//Get Word object &lt;br /&gt;ILateBindingFacade wordDoc = word.Get&amp;lt;ILateBindingFacade&amp;gt;("Documents").Call&amp;lt;ILateBindingFacade&amp;gt;("Add");&lt;br /&gt;ILateBindingFacade selection = word.Get&amp;lt;ILateBindingFacade&amp;gt;("Selection");&lt;br /&gt;&lt;br /&gt;string str = "Hello World!";&lt;br /&gt;&lt;br /&gt;word.Set("Visible", true);&lt;br /&gt;&lt;br /&gt;selection.Call("BoldRun");&lt;br /&gt;&lt;br /&gt;foreach (char c in str)&lt;br /&gt;{&lt;br /&gt;	selection.Call("TypeText", Args.Build(c.ToString()));&lt;br /&gt;        System.Threading.Thread.Sleep(200);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;word.Call("Quit", Args.Build(0) );&lt;/pre&gt;&lt;br /&gt;Y la nueva versión 2.1 que lava más blanco:&lt;br /&gt;&lt;pre class="csharp" name="code"&gt;IInvoker wordApp = BindingFactory.CreateAutomationBinding("Word.Application");&lt;br /&gt;//Get Word object &lt;br /&gt;IInvoker document = wordApp.Property("Documents").Get&amp;lt;IIinvoker&amp;gt;();&lt;br /&gt;            &lt;br /&gt;document&lt;br /&gt;    .Method("Add")&lt;br /&gt;    .Invoke();&lt;br /&gt;&lt;br /&gt;IInvoker selection = wordApp&lt;br /&gt;			.Property("Selection")&lt;br /&gt;			.Get&amp;lt;IInvoker&amp;gt;();&lt;br /&gt;&lt;br /&gt;string str = "Hello World!";&lt;br /&gt;&lt;br /&gt;//Make workd visible&lt;br /&gt;wordApp&lt;br /&gt;    .Property("Visible")&lt;br /&gt;    .Set(true);&lt;br /&gt;&lt;br /&gt;//Activate bold&lt;br /&gt;selection&lt;br /&gt;    .Method("BoldRun")&lt;br /&gt;    .Invoke();&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;foreach (char c in str)&lt;br /&gt;{&lt;br /&gt;	selection&lt;br /&gt;		.Method("TypeText")&lt;br /&gt;		.AddParameter(c.ToString())&lt;br /&gt;		.Invoke();&lt;br /&gt;&lt;br /&gt;        System.Threading.Thread.Sleep(200);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;//Quit&lt;br /&gt;wordApp&lt;br /&gt;    .Method("Quit")&lt;br /&gt;    .AddParameter(0)&lt;br /&gt;    .Invoke();&lt;br /&gt;&lt;/pre&gt;Sólo queda hacer la pregunta de rigor, ¿qué interface creeis que sería más cómodo de utilizar?  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5754664854663769426-1274835840865837404?l=www.crazypointer.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/CrazyPointer?a=OPA3FKAOSc0:eJwEp-8GHZc:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CrazyPointer?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CrazyPointer?a=OPA3FKAOSc0:eJwEp-8GHZc:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CrazyPointer?i=OPA3FKAOSc0:eJwEp-8GHZc:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CrazyPointer/~4/OPA3FKAOSc0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.crazypointer.com/feeds/1274835840865837404/comments/default" title="Enviar comentarios" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=5754664854663769426&amp;postID=1274835840865837404" title="2 comentarios" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5754664854663769426/posts/default/1274835840865837404?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5754664854663769426/posts/default/1274835840865837404?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CrazyPointer/~3/OPA3FKAOSc0/fluent-interfaces.html" title="Fluent Interfaces" /><author><name>Ricky</name><uri>http://www.blogger.com/profile/18324470751965509112</uri><email>rickyah@gmail.com</email><gd:extendedProperty name="OpenSocialUserId" value="10817153364417160719" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total><feedburner:origLink>http://www.crazypointer.com/2008/11/fluent-interfaces.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0EAQnsyeip7ImA9WxRVEE0.&quot;"><id>tag:blogger.com,1999:blog-5754664854663769426.post-6613909426414654185</id><published>2008-10-25T16:29:00.004+02:00</published><updated>2008-11-06T22:07:23.592+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-11-06T22:07:23.592+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="CodeSnippet" /><category scheme="http://www.blogger.com/atom/ns#" term="C#" /><title>[CSharp]Fun with Windows Handlers (3/3)</title><content type="html">&lt;p&gt;Y por fin la tercera y última entrada, donde -por fin- utilizaremos todo lo que hemos aprendido anteriormente para realmente hacer algo útil :)&lt;/p&gt;&lt;p&gt;Ya vimos anteriormente los &lt;a href="http://crazypointer.blogspot.com/2008/10/csharpfun-with-windows-handlers-22.html";
onMouseout="hideddrivetip()"&gt;conceptos de parent y owner&lt;/a&gt; de un control, ahora vamos a ver cómo podemos forzar esos comportamientos en una aplicación por medio de los Handlers de la ventana y de llamadas a la API Win32.&lt;/p&gt;&lt;p&gt;Al final de la entrada se puede descargar el proyecto de visual studio 2005 utilizado para las capturas de pantalla de este post. La aplicación crea tres formularios simples: un reloj con un par de botones que simplemente muestran un aviso al ser pulsados, un formulario para guardar una imagen, y un formulario con diferentes botones de control para activar y desactivar las operaciones entre los anteriores formularios.&lt;/p&gt;&lt;p align="center"&gt;&lt;a href="http://lh6.ggpht.com/rickyAH/SQNcDpN4JyI/AAAAAAAAAN4/coUzmTAfaYc/s1600-h/FunWithWinHdl17.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="383" alt="Formularios creados por la aplicaci&amp;oacute;n de ejemplo" src="http://lh6.ggpht.com/rickyAH/SQNcERiV1uI/AAAAAAAAAN8/b6Q65hkXtPQ/FunWithWinHdl1_thumb3.png?imgmax=800" width="572" border="0"&gt;&lt;/a&gt;&amp;nbsp; &lt;/p&gt;&lt;h2&gt;Botón 'Make Owner'&lt;/h2&gt;&lt;p&gt;Al pulsar este botón provocará que el formulario 'ClockWindow' se convierta en el Owner del formulario 'PictureBox'. Por tanto éste último siempre será dibujado por encima del primero:&lt;/p&gt;&lt;p align="center"&gt;&lt;a href="http://lh3.ggpht.com/rickyAH/SQNcFbJO7HI/AAAAAAAAAOA/0JRT4mSjrpU/s1600-h/FunWithWinHdl33.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="367" alt="N&amp;oacute;tese que la ventana activa es 'ClockWindow' y a&amp;uacute;n as&amp;iacute; 'PictureWindow' permanece por encima" src="http://lh4.ggpht.com/rickyAH/SQNcGCbUL1I/AAAAAAAAAOE/GUHwrwZM1J0/FunWithWinHdl3_thumb1.png?imgmax=800" width="359" border="0"&gt;&lt;/a&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;Para conseguir este efecto, usaremos la función &lt;a href="http://msdn.microsoft.com/en-us/library/ms644898(VS.85).aspx"&gt;SetWindowLongPtr()&lt;/a&gt;, que sirve para cambiar los atributos de una ventana. Si firma en P/Invoke es:&lt;/p&gt;&lt;pre class="csharp" name="code"&gt;public static IntPtr SetWindowLongPtr(IntPtr hWnd, int nIndex, IntPtr dwNewLong)&lt;/pre&gt;&lt;br /&gt;
&lt;p&gt;Donde hWnd es el handle de la ventana a la que queremos cambiar un atributo, nIndex es una constante que define el atributo a cambiar, y dwNewLong sirve para establecer el nuevo valor.&lt;/p&gt;&lt;br /&gt;
&lt;p&gt;En este caso para cambiar el owner de la ventana, tenemos que usar una constante con un desafortunado nombre: GWL_HWNDPARENT. Ésta constante está definida en winapi.h, y tiene el valor -8. Su nombre es desafortunado porque realmente no tiene nada que ver con establecer la clase padre (parent) y puede llevar a equívocos.&lt;/p&gt;&lt;br /&gt;
&lt;p&gt;Para establecer, por ejemplo, que el formulario 'ClockWindow' sea el propietario de 'PictureBox' llamaremos a la función de la siguiente manera:&lt;/p&gt;&lt;pre class="csharp" code="name"&gt;WinAPIDeclarations.SetWindowLongPtr(
pictureWindowForm.Handle,
-8,
clockWindowForm.Handle);&lt;/pre&gt;&lt;br /&gt;
&lt;p&gt;Y para volver a dejar todo como estaba, lo que haremos será establecer el Handler del owner de 'PictureBox' como IntPtr.Zero, lo que equivale a establecer el escritorio como propietario:&lt;/p&gt;&lt;pre class="csharp" code="name"&gt;WinAPIDeclarations.SetWindowLongPtr(
pictureWindowForm.Handle,
-8,
IntPtr.Zero); &lt;/pre&gt;&lt;br /&gt;
&lt;h2&gt;Botón 'Make Parent' y 'Make Parent to Button'&lt;/h2&gt;&lt;br /&gt;
&lt;p&gt;Seguimos con la función &lt;a href="http://msdn.microsoft.com/en-us/library/ms633541.aspx"&gt;SetParent()&lt;/a&gt;, cuya firma para P/Invoke se define:&lt;pre&gt;[DllImport("user32.dll")]
public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);&lt;/pre&gt;&lt;br /&gt;
&lt;p&gt;Con esta función podemos forzar que un control cualquiera se convierta en el padre del otro, y por tanto provocará que el hijo se dibuje dentro del rectángulo de cliente del control padre, ya sea un formulario u otro control:&lt;/p&gt;&lt;br /&gt;
&lt;p align="center"&gt;&lt;a href="http://lh6.ggpht.com/rickyAH/SQNcGpeIR4I/AAAAAAAAAOI/J9-yoC1O3NU/s1600-h/FunWithWinHdl2%5B7%5D.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="308" alt="PictureWindow es ahora hija de ClockWindow" src="http://lh5.ggpht.com/rickyAH/SQNcHb3wI0I/AAAAAAAAAOM/CrGZRRyZdAc/FunWithWinHdl2_thumb%5B3%5D.png?imgmax=800" width="290" border="0"&gt;&lt;/a&gt;&amp;nbsp; &lt;a href="http://lh5.ggpht.com/rickyAH/SQNcH-PqAfI/AAAAAAAAAOQ/fuCiJMiq1e8/s1600-h/FunWithWinHdl5%5B10%5D.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="307" alt="PictureWindow es ahora hija de un bot&amp;oacute;n en ClockWindow" src="http://lh4.ggpht.com/rickyAH/SQNcIb1LiAI/AAAAAAAAAOU/GvpYqzkk8P0/FunWithWinHdl5_thumb%5B8%5D.png?imgmax=800" width="348" border="0"&gt;&lt;/a&gt;&amp;nbsp; &lt;/p&gt;&lt;br /&gt;
&lt;p&gt;Hay que destacar que tanto esta operación como la anterior funcionan para &lt;u&gt;cualquier&lt;/u&gt; ventana de la que podamos obtener el handle. Por tanto podemos conseguir cosas como esta:&lt;/p&gt;&lt;br /&gt;
&lt;p align="center"&gt;&lt;a href="http://lh6.ggpht.com/rickyAH/SQNcLkxYjrI/AAAAAAAAAOY/1ou14UJ_xXM/s1600-h/FunWithWinHdl4%5B3%5D.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="459" alt="Windows Live Writter es ahora el padre de PictureWindow. No es Potosof :)" src="http://lh3.ggpht.com/rickyAH/SQNcNDFDHMI/AAAAAAAAAOc/kOJfknIfPzI/FunWithWinHdl4_thumb%5B1%5D.png?imgmax=800" width="664" border="0"&gt;&lt;/a&gt;&amp;nbsp; &lt;/p&gt;&lt;br /&gt;
&lt;h2&gt;Botón 'Disable refresh'&lt;/h2&gt;&lt;br /&gt;
&lt;p&gt;Esta operación permite activar o desactivar el repintado de una ventana. Utilizaremos la función &lt;a href="http://msdn.microsoft.com/en-us/library/ms644950(VS.85).aspx"&gt;SendMessage()&lt;/a&gt; para ello y el mensaje &lt;a href="http://msdn.microsoft.com/en-us/library/ms534853(VS.85).aspx"&gt;WM_SETREDRAW&lt;/a&gt;. La firma P/Invoke de la función y el valor del mensaje es:&lt;/p&gt;&lt;pre class="csharp" name="code"&gt;[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);&lt;/pre&gt;&lt;pre class="csharp" name="code"&gt;public static readonly uint WM_SETREDRAW = 0x000B; &lt;/pre&gt;&lt;br /&gt;
&lt;p&gt;Para desactivar el repintado de una ventana haremos: &lt;/p&gt;&lt;br /&gt;
&lt;pre class="csharp" name="code"&gt;IntPtr result = WinAPIDeclarations.SendMessage(
clockWindowForm.Handle,
WinAPIDeclarations.WM_SETREDRAW,
(IntPtr)0,
IntPtr.Zero);&lt;/pre&gt;Y para volver a activarlo: &lt;br /&gt;
&lt;pre class="csharp" name="code"&gt;IntPtr result = WinAPIDeclarations.SendMessage(
clockWindowForm.Handle,
WinAPIDeclarations.WM_SETREDRAW,
(IntPtr)1,
IntPtr.Zero);&lt;/pre&gt;&lt;br /&gt;
&lt;h2&gt;Botón 'Disable Input'&lt;/h2&gt;&lt;br /&gt;
&lt;p&gt;Esta operación permite activar o desactivar el procesado de input para una ventana, es decir, podemos hacer que la ventana no responda a ningún tipo de entrada de datos (con ratón o teclado) de forma que en la práctica no se puede interactuar con ella. Para ello disponemos de otra función con un nombre no muy descriptivo: &lt;a href="http://msdn.microsoft.com/en-us/library/ms646291.aspx"&gt;EnableWindow()&lt;/a&gt;, que tiene la firma:&lt;/p&gt;&lt;pre class="csharp" name="code"&gt;[DllImport("user32.dll")]
public static extern bool EnableWindow(IntPtr hWnd, bool bEnable);&lt;/pre&gt;Viendo los argumentos es bastante fácil de usar si eres capaz de intuir por el nombre lo que hace; para desactivar la entrada de input haremos: &lt;pre class="csharp" name="code"&gt;EnableWindow(clockWindowForm.Handle, false);&lt;/pre&gt;y para desactivarla: &lt;pre class="csharp" name="code"&gt;EnableWindow(clockWindowForm.Handle, true);&lt;/pre&gt;&lt;br /&gt;
&lt;p&gt;De nuevo, estas dos últimas operaciones pueden aplicarse a cualquier ventana sabiendo su handle, así que podemos desactivar el repintado o la entrada de datos de una ventana externa. Esto puede ser útil en ciertos casos pero hay que tener mucho cuidado: si olvidamos restablecer el estado anterior o nuestra aplicación se cierra inesperadamente podríamos dejar una aplicación externa sin respuesta, por lo que el usuario tendría que matar el proceso y recargarla, potencialmente perdiendo datos. Hay que ser muy cuidadoso al utilizar estas operaciones.&lt;/p&gt;&lt;br /&gt;
&lt;p&gt;También hay que avisar a posibles usuarios de &lt;a href="http://www.mono-project.com/"&gt;Mono&lt;/a&gt; de que al estar haciendo llamadas específicas a la API de Windows, este código no es portable.&lt;/p&gt;&lt;br /&gt;
&lt;p&gt;&lt;a href="http://rickyah.googlepages.com/PlayingWithWindowsCrazyPointer.rar"&gt;Descargar ejemplo para VisualStudio 2005&lt;/a&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5754664854663769426-6613909426414654185?l=www.crazypointer.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/CrazyPointer?a=ufWkrcn3aOo:8dDLV_4bR3w:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CrazyPointer?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CrazyPointer?a=ufWkrcn3aOo:8dDLV_4bR3w:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CrazyPointer?i=ufWkrcn3aOo:8dDLV_4bR3w:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CrazyPointer/~4/ufWkrcn3aOo" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.crazypointer.com/feeds/6613909426414654185/comments/default" title="Enviar comentarios" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=5754664854663769426&amp;postID=6613909426414654185" title="0 comentarios" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5754664854663769426/posts/default/6613909426414654185?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5754664854663769426/posts/default/6613909426414654185?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CrazyPointer/~3/ufWkrcn3aOo/csharpfun-with-windows-handlers-33.html" title="[CSharp]Fun with Windows Handlers (3/3)" /><author><name>Ricky</name><uri>http://www.blogger.com/profile/18324470751965509112</uri><email>rickyah@gmail.com</email><gd:extendedProperty name="OpenSocialUserId" value="10817153364417160719" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://www.crazypointer.com/2008/10/csharpfun-with-windows-handlers-33.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0cDSHoyfyp7ImA9WxRXGUg.&quot;"><id>tag:blogger.com,1999:blog-5754664854663769426.post-9090078148608320486</id><published>2008-10-18T20:46:00.008+02:00</published><updated>2008-10-25T19:17:59.497+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-10-25T19:17:59.497+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="CodeSnippet" /><category scheme="http://www.blogger.com/atom/ns#" term="C#" /><title>[CSharp]Fun with Windows Handlers (2/3)</title><content type="html">&lt;p&gt;Siguiendo con la &lt;a href="http://crazypointer.blogspot.com/2008/10/csharpfun-with-windows-handlers-12.html"&gt;entrada anterior&lt;/a&gt;, veremos ahora una pequeña muestra de alguna cosa divertida conociendo el Handler de una ventana.&lt;/p&gt; &lt;p&gt;Si la ventana pertenece a nuestra aplicación, y sólo en ese caso, podemos obtener a partir del handle, la instancia de la clase Form al que está asociado:&lt;/p&gt;&lt;pre class="csharp" name="code"&gt;Form formApp = (Form)Form.FromHandle( myAppWindowHandle );&lt;/pre&gt;Si el handle no pertenece a una ventana creada dentro de nuestra propia aplicación, Form.FromHandle retorna null, imagino que será por cuestiones de seguridad. El caso es que usando funciones de Win32 API por medio de P/Invoke podemos saltarnos en algunos casos esta seguridad.&lt;br&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;br&gt;&lt;br /&gt;&lt;p&gt;Antes de mostrar lo que podemos hacer, tendremos que presentar dos conceptos que se aplican en las ventanas de Windows. Si, es un momento teórico, pero necesario.&lt;/p&gt;&lt;br&gt;&lt;br /&gt;&lt;h2&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ms632599%28VS.85%29.aspx#child"&gt;Parent Window&lt;/a&gt;&lt;/h2&gt;&lt;br&gt;&lt;br /&gt;&lt;p&gt;En Windows, todo elemento visual (widgets), desde el formulario principal a los botones se consideran... windows (buen nombre para no confundir a la gente ¿eh? ) Una mejor manera de denominar a los widgets es usar la nomenclatura usada en .NET: Todo es un &lt;a href="http://msdn.microsoft.com/en-us/library/system.windows.forms.control.aspx"&gt;Control&lt;/a&gt;.&lt;/p&gt;&lt;br&gt;&lt;br /&gt;&lt;p&gt;Una aplicación de Windows consiste en una jerarquía de controles: cada control puede a su vez &lt;strike&gt;contener a otros&lt;/strike&gt;, ser padre de otros, creando una jerarquía en forma árbol. En Visual Studio podemos ver esa jerarquía por medio del menú View/Other Windows/Outline Document.&lt;/p&gt;&lt;br&gt;&lt;br /&gt;&lt;p&gt;Por ejemplo, si tuviéramos el siguiente formulario la jerarquía sería la mostrada por la imagen a su derecha:&lt;/p&gt;&lt;br&gt;&lt;br /&gt;&lt;p align="center"&gt;&lt;a href="http://lh5.ggpht.com/rickyAH/SPowwS3R_dI/AAAAAAAAAM4/P_PkroxZXHo/s1600-h/parentWindow1%5B2%5D.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="228" alt="parentWindow1" src="http://lh4.ggpht.com/rickyAH/SPou4Oe1FUI/AAAAAAAAAM8/_OsIs4Erjv8/parentWindow1_thumb.png?imgmax=800" width="322" border="0"&gt;&lt;/a&gt; &lt;a href="http://lh6.ggpht.com/rickyAH/SPoww3LIVhI/AAAAAAAAANA/kRAosh8LR2g/s1600-h/parentWindowTree1%5B2%5D.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="174" alt="parentWindowTree1" src="http://lh4.ggpht.com/rickyAH/SPou40KqvsI/AAAAAAAAANE/k0nEA0MGiWQ/parentWindowTree1_thumb.png?imgmax=800" width="288" border="0"&gt;&lt;/a&gt; &lt;/p&gt;&lt;br&gt;&lt;br /&gt;&lt;p&gt;Sin embargo si ahora añadimos un GroupBox e introducimos el botón en él, tendríamos la siguiente ventana y jerarquía:&lt;/p&gt;&lt;br&gt;&lt;br /&gt;&lt;p align="center"&gt;&lt;a href="http://lh6.ggpht.com/rickyAH/SPou5N8f4DI/AAAAAAAAAMY/tIzC2PgRRQw/s1600-h/parentWindow24.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="227" alt="parentWindow2" src="http://lh4.ggpht.com/rickyAH/SPou5sUXmAI/AAAAAAAAAMc/aIo91lO7GnA/parentWindow2_thumb2.png?imgmax=800" width="320" border="0"&gt;&lt;/a&gt; &lt;a href="http://lh3.ggpht.com/rickyAH/SPou51rJDRI/AAAAAAAAAMg/ETEdBCWRsv0/s1600-h/parentWindowTree24.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="179" alt="parentWindowTree2" src="http://lh6.ggpht.com/rickyAH/SPou6adOdlI/AAAAAAAAAMk/zj_fbAV8g2Y/parentWindowTree2_thumb2.png?imgmax=800" width="287" border="0"&gt;&lt;/a&gt; &lt;/p&gt;&lt;br&gt;&lt;br /&gt;&lt;p&gt;Una vez dicho esto, creo que queda claro de forma intuitiva lo que es una ventana padre o una ventana hija dentro de la jerarquía. Lo que tenemos que tener en cuenta que una ventana hija se posiciona en coordenadas relativas a la ventana padre, y que siempre se mantiene dentro de los límites del área de cliente de una ventana.&lt;/p&gt;&lt;br&gt;&lt;br /&gt;&lt;p align="center"&gt;&lt;a href="http://lh6.ggpht.com/rickyAH/SPou6pE1M3I/AAAAAAAAAMo/ZQhCO-YqG2g/s1600-h/WindowParts4.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="292" alt="WindowParts" src="http://lh4.ggpht.com/rickyAH/SPou7JTxxzI/AAAAAAAAAMs/DVeoaIBS94w/WindowParts_thumb2.png?imgmax=800" width="396" border="0"&gt;&lt;/a&gt; &lt;/p&gt;&lt;br&gt;&lt;br /&gt;&lt;p align="left"&gt;&lt;/p&gt;&lt;br&gt;&lt;br /&gt;&lt;h2&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ms632599%28VS.85%29.aspx#owned_windows"&gt;Owner Window&lt;/a&gt;&lt;/h2&gt;&lt;br&gt;&lt;br /&gt;&lt;p&gt;Esta es más sencilla: una ventana se considera propietaria de otra cuando se considera parte fundamental de la ventana propietaria. Pro ejemplo, si desde nuestra aplicación creamos un MessageBox, o mostramos un diálogo de selección de fichero, nuestra aplicación es la propietaria de éstas ventanas: nuestra aplicación las crea y las gestiona, pero no dependen de una jerarquía de controles dentro de la ventana principal. Esas ventanas no tienen por qué se modales, por ejemplo, las típicas ventanas flotantes de una aplicación de retoque fotográfico tienen como propietaria a la ventana de la aplicación principal:&lt;/p&gt;&lt;br&gt;&lt;br /&gt;&lt;p align="center"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="736" alt="La ventana principal es propietaria de las sombreadas en rojo" src="http://lh3.ggpht.com/rickyAH/SPou85zpV3I/AAAAAAAAANI/W2NR8c4bj2I/OwnerWindow%5B1%5D.png?imgmax=800" width="821" border="0"&gt; &lt;/p&gt;&lt;br&gt;&lt;br /&gt;&lt;p&gt;Las ventanas que son propiedad de otra tienen la particularidad de que se pueden dibujar en cualquier parte del escritorio, pero siempre se muestran por encima de la ventana propietaria.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;UPDATE: Otro &lt;u&gt;comportamiento muy importante&lt;/u&gt; de una ventana que tiene como propietaria a otra es que si cerramos la ventana principal, todas las ventanas de las que la ventana principal sea propietaria también se ocultarán.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Y por fin, veremos cómo hacer alguna cosa interesante con un handler en la tercera y última entrada de esta mini-serie.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5754664854663769426-9090078148608320486?l=www.crazypointer.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/CrazyPointer?a=xjiOJSLaUnU:SitwvNJe4Hg:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CrazyPointer?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CrazyPointer?a=xjiOJSLaUnU:SitwvNJe4Hg:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CrazyPointer?i=xjiOJSLaUnU:SitwvNJe4Hg:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CrazyPointer/~4/xjiOJSLaUnU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.crazypointer.com/feeds/9090078148608320486/comments/default" title="Enviar comentarios" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=5754664854663769426&amp;postID=9090078148608320486" title="0 comentarios" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5754664854663769426/posts/default/9090078148608320486?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5754664854663769426/posts/default/9090078148608320486?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CrazyPointer/~3/xjiOJSLaUnU/csharpfun-with-windows-handlers-22.html" title="[CSharp]Fun with Windows Handlers (2/3)" /><author><name>Ricky</name><uri>http://www.blogger.com/profile/18324470751965509112</uri><email>rickyah@gmail.com</email><gd:extendedProperty name="OpenSocialUserId" value="10817153364417160719" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://www.crazypointer.com/2008/10/csharpfun-with-windows-handlers-22.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkQGQ3c_fSp7ImA9WxRXGU4.&quot;"><id>tag:blogger.com,1999:blog-5754664854663769426.post-9144504292882550938</id><published>2008-10-17T01:39:00.012+02:00</published><updated>2008-10-25T13:32:02.945+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-10-25T13:32:02.945+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="CodeSnippet" /><category scheme="http://www.blogger.com/atom/ns#" term="C#" /><title>[CSharp]Fun with Windows Handlers (1/3)</title><content type="html">&lt;p align="left"&gt;Hay una cosa segura: .Net tiene sus limitaciones. Al menos, si lo comparamos con las operaciones que teníamos disponibles con la &lt;a href="http://msdn.microsoft.com/en-us/library/aa383749%28VS.85%29.aspx"&gt;API Win32&lt;/a&gt;, veremos que no podemos hacer absolutamente todo lo que hacíamos con ésta última. Para solucionar este eventual problema tenemos &lt;a href="http://msdn.microsoft.com/en-us/library/aa288468.aspx"&gt;Platform Invocation Services&lt;/a&gt;, más conocido como PInvoke (o P/Invoke), que nos permite hacer llamadas a código nativo implementadas en una DLL desde código administrado.&lt;/p&gt; &lt;p&gt;Debido a que las estructuras de datos utilizadas en código nativo son distintas a las de código administrado, debemos realizar un proceso conocido como &lt;a href="http://en.csharp-online.net/Glossary:Definition_-_Marshaling"&gt;Marshaling&lt;/a&gt;, que grosso modo viene a significar &lt;em&gt;transportar datos entre diferentes contextos&lt;/em&gt;. Muy genérico ¿verdad?. &lt;/p&gt; &lt;p&gt;Este proceso de adecuación de los datos es prácticamente automático. Lo único que tenemos que hacer es indicarle al framework .net la función de la Dll que queremos utilizar, y decirle cómo debe traducir las estructuras de datos. Y ni siquiera tenemos que perder el tiempo en ello, ya que gracias &lt;strike&gt;a la página&lt;/strike&gt; al wiki &lt;a href="http://www.pinvoke.net/"&gt;PInvoke.net&lt;/a&gt;, tenemos acceso a un motor de búsqueda donde sólo debemos introducir el nombre de la función que buscamos y obtendremos el código necesario para usarla, listo para cortar y pegar. Aún así daremos una pequeña explicación:&lt;/p&gt; &lt;p&gt;Para usar una función que exporta una Dll tenemos que seguir los siguientes pasos:&lt;/p&gt; &lt;p&gt;Crear una función estática y con el keyword &lt;strong&gt;&lt;span style="color: #0000ff"&gt;extern&lt;/span&gt;&lt;/strong&gt;. &lt;/p&gt; &lt;p&gt;Marcamos la función con el atributo &lt;a href="http://msdn.microsoft.com/es-es/library/system.runtime.interopservices.dllimportattribute%28VS.80%29.aspx"&gt;DllImport&lt;/a&gt;, al cual pasamos como parámetro el nombre de la Dll que contiene al método.&lt;/p&gt; &lt;p&gt;La función por supuesto debe tener los parámetros adecuados a lo tipos de .NET.&lt;/p&gt; &lt;p&gt;Por ejemplo, la función Win32 API &lt;em&gt;&lt;a href="http://msdn.microsoft.com/es-es/library/system.runtime.interopservices.dllimportattribute%28VS.80%29.aspx"&gt;FindWindow&lt;/a&gt;&lt;/em&gt; tiene esta definición:&lt;/p&gt;&lt;pre class="cpp" name="code"&gt;HWND FindWindow( LPCTSTR lpClassName, LPCTSTR lpWindowName );&lt;/pre&gt;Esta función recibe un puntero a una cadena con la nombre de la clase con la que se registró la ventana (ojo esto no tiene que ver con clases de POO, sino con &lt;a href="http://msdn.microsoft.com/en-us/library/ms633586%28VS.85%29.aspx"&gt;otro tipo de clase&lt;/a&gt;), y otro puntero a una cadena con el nombre de la ventana (lo que sería el título o caption), retornando el HANDLE de la ventana si la encuentra. Bien, esto se traduce en .NET con el siguiente método de clase (en .NET no existen las funciones por separado, todo tiene que ser parte de un objeto) &lt;pre class="csharp" name="code"&gt;public static class Win32API{    [DllImport("user32.dll")]public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);}&lt;/pre&gt;&lt;br&gt;&lt;br&gt;&lt;br /&gt;&lt;p&gt;Vemos que el Handler de la ventana se traduce por una estructura &lt;a href="http://msdn.microsoft.com/es-es/library/system.intptr%28VS.80%29.aspx"&gt;System.IntPtr&lt;/a&gt;, y los punteros a cadenas por strings. Ahora podremos llamar a la función, por ejemplo:&lt;/p&gt;&lt;pre class="csharp" name="code"&gt;IntPtr hwn = FindWindow(null, "título de la ventana");&lt;/pre&gt;&lt;br&gt;&lt;br&gt;&lt;br /&gt;&lt;p&gt;Y buscaría la ventana con dicho título ignorando su clase de ventana, retornando el handler a la ventana (o IntPtr.Zero si no se encuentra una ventana con ese título)&lt;/p&gt;&lt;br&gt;&lt;br&gt;&lt;br /&gt;&lt;p&gt;Teniendo el Handler de una ventana podemos controlar prácticamente todo si sabemos lo que hacemos. Y esta función nos permite buscar y obtener el handler de cualquier ventana. Aunque no sea de nuestra aplicación. Aunque ni siquiera haya sido generada por código .NET...&lt;/p&gt;&lt;br&gt;&lt;br&gt;&lt;br /&gt;&lt;p&gt;Veremos algunos conceptos más en la siguiente entrada.&lt;/p&gt;&lt;br&gt;&lt;br&gt;&lt;br /&gt;&lt;p&gt;PS: Como nota curiosa, podemos llamar a nuestro método estático como queramos, siempre que en el atributo [DllImport] le indiquemos el nombre real de la función de la Dll que pretendemos importar:&lt;/p&gt;&lt;pre class="csharp" name="code"&gt;&lt;br&gt;[DllImport("user32.dll", EntryPoint="FindWindow")]&lt;br&gt;public static extern IntPtr BuscaHandlerDeVentana(string lpClassName, string lpWindowName);&lt;/pre&gt;&lt;br&gt;&lt;br&gt;&lt;br /&gt;&lt;p&gt;Como vemos si el parámetro &lt;em&gt;EntryPoint&lt;/em&gt; no está disponible, se toma como el mismo el nombre del método estático.&lt;/p&gt;&lt;br&gt;&lt;br&gt;&lt;br /&gt;&lt;p&gt;PPS: Existen otras maneras de obtener un handle de la ventana. Si tenemos un objeto System.Windows.Forms.Control (lo que incluye un System.Windows.Forms.Form), éste expone la propiedad &lt;a href="http://msdn.microsoft.com/en-us/library/system.windows.forms.control.handle.aspx"&gt;Handle&lt;/a&gt;, que nos devuelve el Handler de la ventana.&lt;/p&gt;&lt;br&gt;&lt;br&gt;&lt;br /&gt;&lt;p&gt;Del mismo modo la clase System.Diagnostics.Process, expone el método estático GetProcesses(), que nos devuelve una lista con todos los Procesos en ejecución (podemos buscar por PID, nombre, etc). A su vez una instancia de la clase System.Diagnostics.Process expone el método Handle, con el Handler del proceso (que &lt;u&gt;suele&lt;/u&gt; coincidir con el de la ventana principal).&lt;/p&gt;&lt;br /&gt;&lt;p&gt;UPDATE: La clase Process expone una propiedad denominada &lt;a href="http://msdn.microsoft.com/en-us/library/system.diagnostics.process.mainwindowhandle.aspx"&gt;MainWindowHandle&lt;/a&gt;, que SI devuelve el handle de la ventana principal del proceso :)&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5754664854663769426-9144504292882550938?l=www.crazypointer.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/CrazyPointer?a=VfTssY1RDT0:gAU6HkvKF_k:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CrazyPointer?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CrazyPointer?a=VfTssY1RDT0:gAU6HkvKF_k:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CrazyPointer?i=VfTssY1RDT0:gAU6HkvKF_k:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CrazyPointer/~4/VfTssY1RDT0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.crazypointer.com/feeds/9144504292882550938/comments/default" title="Enviar comentarios" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=5754664854663769426&amp;postID=9144504292882550938" title="0 comentarios" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5754664854663769426/posts/default/9144504292882550938?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5754664854663769426/posts/default/9144504292882550938?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CrazyPointer/~3/VfTssY1RDT0/csharpfun-with-windows-handlers-12.html" title="[CSharp]Fun with Windows Handlers (1/3)" /><author><name>Ricky</name><uri>http://www.blogger.com/profile/18324470751965509112</uri><email>rickyah@gmail.com</email><gd:extendedProperty name="OpenSocialUserId" value="10817153364417160719" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://www.crazypointer.com/2008/10/csharpfun-with-windows-handlers-12.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0ADSXc4eSp7ImA9WxRbF0o.&quot;"><id>tag:blogger.com,1999:blog-5754664854663769426.post-5315183523791321810</id><published>2008-10-01T18:44:00.005+02:00</published><updated>2008-12-08T22:29:38.931+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-12-08T22:29:38.931+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="J2ME" /><category scheme="http://www.blogger.com/atom/ns#" term="VideoGames" /><category scheme="http://www.blogger.com/atom/ns#" term="FAILinks" /><category scheme="http://www.blogger.com/atom/ns#" term="C#" /><category scheme="http://www.blogger.com/atom/ns#" term="VisualStudio" /><category scheme="http://www.blogger.com/atom/ns#" term="TDD" /><title>Links de la semana</title><content type="html">&lt;p&gt;Algo retrasados, pero aquí están los links de la "semana"agrupados un poco...&lt;/p&gt;&lt;p&gt;&lt;span style="font-size:130%;"&gt;&lt;strong&gt;Test Driven Development&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Google nos ofrece &lt;a href="http://code.google.com/p/moq/"&gt;Moq&lt;/a&gt;, una librería de &lt;a href="http://en.wikipedia.org/wiki/Mock_object"&gt;Mocks&lt;/a&gt;, simple de utilizar y aprovechando las características del framework .NET 3.5.  La verdad es que sin haberla probado pero viendo los pequeños snippets de código de la web tiene una pinta &lt;strong&gt;muy&lt;/strong&gt; interesante. Yo he estado usando &lt;a href="http://ayende.com/projects/rhino-mocks.aspx"&gt;Rhino Mocks&lt;/a&gt;, y aunque es muy potente, es un &lt;span style="text-decoration: line-through;"&gt;lío que te cagas&lt;/span&gt; algo compleja al principio.&lt;/li&gt;&lt;li&gt;Y más Mocks, pero esta vez para J2ME. &lt;a href="http://mockme.sourceforge.net/"&gt;MockME&lt;/a&gt; es un mock completo de las librerías que conforman la especificación J2ME. De esta forma podemos escribir casos de prueba para nuestra aplicación J2ME, pero sin necesidad de ejecutarlos en el móvil.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;p&gt;&lt;span style="font-size:130%;"&gt;&lt;strong&gt;Visual Studio&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.codeplex.com/SnippetDesigner"&gt;Snippet Designer&lt;/a&gt; te permite crear &lt;a href="http://crazypointer.blogspot.com/2008/05/snippet-para-crear-un-singleton-en.html"&gt;snippets de código&lt;/a&gt; para Visual Studio de forma visual, lo que es más intuitivo y cómodo.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;p&gt;&lt;span style="font-size:130%;"&gt;&lt;strong&gt;Miscelánea&lt;/strong&gt;:&lt;/span&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Si eres el poseedor de una &lt;a href="http://es.playstation.com/ps3/hardware/accessories/detail/item78899/PLAYSTATION%C2%AEEye/"&gt;PlayStation Eye&lt;/a&gt;, y además usas Windows, aquí tienes &lt;a href="http://nuigroup.com/forums/viewthread/2921/"&gt;a un campeón que se ha currado un driver para la misma.&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://googlemac.blogspot.com/"&gt;Blog oficial de google sobre Mac&lt;/a&gt;, con novedades y utilidades centradas en lo relacionado con Apple.&lt;/li&gt;&lt;li&gt;&lt;a href="http://bookletcreator.com/"&gt;Booklet Creator&lt;/a&gt; es una página web a la que le puedes subir cualquier PDF y te lo transforma para que puedas imprimirlo a dos caras como un libro. Muy útil si el driver de tu impresora no te permite hacerlo de serie, o quieres llevar a imprimir el PDF directamente a una copistería.&lt;/li&gt;&lt;li&gt;&lt;a href="http://openpandora.org/"&gt;OpenPandora&lt;/a&gt;. Una consola open source, al estilo de la &lt;a href="http://es.wikipedia.org/wiki/GP2X"&gt;GP2X&lt;/a&gt; o su antecesora la &lt;a href="http://es.wikipedia.org/wiki/GP32"&gt;GP32&lt;/a&gt;, que por fin está a punto de ser lanzada. Destacan sus especificaciones técnicas:&lt;/li&gt;&lt;/ul&gt;&lt;blockquote&gt;&lt;blockquote&gt;&lt;p&gt; * ARM® Cortex™-A8 &lt;strong&gt;600Mhz+ CPU&lt;/strong&gt; running &lt;strong&gt;Linux&lt;/strong&gt;&lt;br /&gt;* 430-MHz TMS320C64x+™ DSP Core&lt;br /&gt;* PowerVR SGX &lt;strong&gt;OpenGL 2.0 ES compliant 3D hardware&lt;/strong&gt;&lt;br /&gt;* &lt;strong&gt;800x480 4.3&lt;/strong&gt;" 16.7 million colours &lt;strong&gt;touchscreen&lt;/strong&gt; LCD&lt;br /&gt;* &lt;strong&gt;Wifi 802.11b/g, Bluetooth&lt;/strong&gt; &amp;amp; High Speed USB 2.0 &lt;strong&gt;Host&lt;/strong&gt;&lt;br /&gt;* &lt;strong&gt;Dual SDHC&lt;/strong&gt; card slots &amp;amp; &lt;strong&gt;SVideo TV output&lt;/strong&gt;&lt;br /&gt;* &lt;strong&gt;Dual Analogue&lt;/strong&gt; and Digital gaming controls&lt;br /&gt;* 43 button QWERTY and numeric keypad&lt;br /&gt;* Around &lt;strong&gt;10+ Hours battery life&lt;/strong&gt;&lt;/p&gt;Vale, lo de la batería no me lo trago hasta que no lo vea, y aunque guapa lo que se dice guapa, la consola no es, tampoco es un adefesio. Pero sus specs son impresionantes, y el hecho de que sea abierta es su principal virtud. Su precio es de 250€, que tal y como está el mercado es bastante competitivo. Eso si, si estás interesado más te vale reservar ya porque sólo van a lanzar 3000 en lo que queda de año.&lt;br /&gt;&lt;p align="center"&gt;&lt;img style="margin: 5px;" alt="" src="http://openpandora.org/storetop.jpg" /&gt;&lt;/p&gt;&lt;br /&gt;Y la próxima "semana", más ;)&lt;br /&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5754664854663769426-5315183523791321810?l=www.crazypointer.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/CrazyPointer?a=IpmeKp6cAJs:fILstesCm9Y:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CrazyPointer?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CrazyPointer?a=IpmeKp6cAJs:fILstesCm9Y:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CrazyPointer?i=IpmeKp6cAJs:fILstesCm9Y:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CrazyPointer/~4/IpmeKp6cAJs" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.crazypointer.com/feeds/5315183523791321810/comments/default" title="Enviar comentarios" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=5754664854663769426&amp;postID=5315183523791321810" title="9 comentarios" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5754664854663769426/posts/default/5315183523791321810?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5754664854663769426/posts/default/5315183523791321810?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CrazyPointer/~3/IpmeKp6cAJs/links-de-la-semana.html" title="Links de la semana" /><author><name>Ricky</name><uri>http://www.blogger.com/profile/18324470751965509112</uri><email>rickyah@gmail.com</email><gd:extendedProperty name="OpenSocialUserId" value="10817153364417160719" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">9</thr:total><feedburner:origLink>http://www.crazypointer.com/2008/10/links-de-la-semana.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0IGSHwzfip7ImA9WxRbF0o.&quot;"><id>tag:blogger.com,1999:blog-5754664854663769426.post-463840225892867784</id><published>2008-09-22T23:57:00.006+02:00</published><updated>2008-12-08T22:25:29.286+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-12-08T22:25:29.286+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="PersonalProjects" /><category scheme="http://www.blogger.com/atom/ns#" term="C#" /><title>[C#] Late binding helper library</title><content type="html">Bueno, pues cuelgo un nuevo y sencillo proyectillo de librería para facilitar las llamadas usando &lt;a href="http://code.google.com/p/latebindinghelper/"&gt;Late Binding en C#&lt;/a&gt;. La verdad es que es un poco pesado usar Late Binding en C#, y como contraste en VB lo simplifican en mi opinión sobremanera: &lt;pre class="vb"&gt;Dim lateBindingObject As Object&lt;br /&gt;lateBindingObject = CreateObject("Word.Application")&lt;br /&gt;lateBindingObject.Visible = True&lt;br /&gt;lateBindingObject.Quit(0)&lt;/pre&gt;Esto &lt;strike&gt;es lo que hay que hacer en C#&lt;/strike&gt; lo que hace realmente el compilador de Visual Basic sin que te enteres (tx to &lt;a href="http://www.red-gate.com/products/reflector/"&gt;Reflector&lt;/a&gt;): &lt;pre class="csharp"&gt;object lateBindingObject = RuntimeHelpers.GetObjectValue(Interaction.CreateObject("Word.Application", ""));&lt;br /&gt;NewLateBinding.LateSet(lateBindingObject, null, "Visible", new object[] { true }, null, null);&lt;br /&gt;NewLateBinding.LateCall(lateBindingObject, null, "Quit", new object[] { 0 }, null, null, null, true);&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;Usando mi librería esto se transforma en: &lt;pre class="csharp"&gt;ILateBindingFacade word = LateBindingFactory.CreateAutomationLateBinding("Word.Application");&lt;br /&gt;word.Set("Visible", true);&lt;br /&gt;word.Call("Quit", Args.Build(0));&lt;/pre&gt;Que simplifica un poco las cosas, o al menos eso espero. Y aprovechando el tema he escrito &lt;a href="http://www.codeproject.com/KB/cs/LateBindingHelper.aspx"&gt;un artículo en CodeProject&lt;/a&gt; explicando un poco el funcionamiento, aunque eso si en inglés.  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5754664854663769426-463840225892867784?l=www.crazypointer.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/CrazyPointer?a=njpvPkE4UyY:PZUZVnfjG8U:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CrazyPointer?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CrazyPointer?a=njpvPkE4UyY:PZUZVnfjG8U:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CrazyPointer?i=njpvPkE4UyY:PZUZVnfjG8U:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CrazyPointer/~4/njpvPkE4UyY" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.crazypointer.com/feeds/463840225892867784/comments/default" title="Enviar comentarios" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=5754664854663769426&amp;postID=463840225892867784" title="0 comentarios" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5754664854663769426/posts/default/463840225892867784?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5754664854663769426/posts/default/463840225892867784?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CrazyPointer/~3/njpvPkE4UyY/c-late-binding-helper-library.html" title="[C#] Late binding helper library" /><author><name>Ricky</name><uri>http://www.blogger.com/profile/18324470751965509112</uri><email>rickyah@gmail.com</email><gd:extendedProperty name="OpenSocialUserId" value="10817153364417160719" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://www.crazypointer.com/2008/09/c-late-binding-helper-library.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEQMQHw9fyp7ImA9WxRREEQ.&quot;"><id>tag:blogger.com,1999:blog-5754664854663769426.post-158968802515718085</id><published>2008-09-22T17:13:00.000+02:00</published><updated>2008-09-22T17:13:01.267+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-09-22T17:13:01.267+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="C#" /><category scheme="http://www.blogger.com/atom/ns#" term="VisualStudio" /><title>Tip visual studio: Watch genérico para la excepción en curso</title><content type="html">&lt;div xmlns='http://www.w3.org/1999/xhtml'&gt;Leo en el &lt;a href='http://blogs.msdn.com/saraford/default.aspx'&gt;blog de Sara Ford&lt;/a&gt;, en el que cada día se añade un 'tip of the day' sobre visual studio, una forma sencilla de &lt;a href='http://blogs.msdn.com/saraford/archive/2008/09/22/did-you-know-you-can-add-exception-to-the-watch-window-to-see-the-caught-exception-318.aspx'&gt;añadir un watch para que muestre la excepción que estamos tratando dentro de un bloque catch&lt;/a&gt;.&lt;br/&gt;&lt;br/&gt;Basta con añadir &lt;i&gt;$exception&lt;/i&gt;:&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;&lt;div align='center'&gt;&lt;img src='http://blogs.msdn.com/blogfiles/saraford/WindowsLiveWriter/Did.YoucanaddexceptiontotheWatchwindowto_1393A/image_thumb.png'/&gt;&lt;br/&gt;&lt;div align='left'&gt;&lt;br/&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5754664854663769426-158968802515718085?l=www.crazypointer.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/CrazyPointer?a=U_kEMbzbhuY:LJhdAu2hVew:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CrazyPointer?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CrazyPointer?a=U_kEMbzbhuY:LJhdAu2hVew:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CrazyPointer?i=U_kEMbzbhuY:LJhdAu2hVew:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CrazyPointer/~4/U_kEMbzbhuY" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.crazypointer.com/feeds/158968802515718085/comments/default" title="Enviar comentarios" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=5754664854663769426&amp;postID=158968802515718085" title="0 comentarios" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5754664854663769426/posts/default/158968802515718085?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5754664854663769426/posts/default/158968802515718085?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CrazyPointer/~3/U_kEMbzbhuY/tip-visual-studio-watch-genrico-para-la_22.html" title="Tip visual studio: Watch genérico para la excepción en curso" /><author><name>Ricky</name><uri>http://www.blogger.com/profile/18324470751965509112</uri><email>rickyah@gmail.com</email><gd:extendedProperty name="OpenSocialUserId" value="10817153364417160719" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://www.crazypointer.com/2008/09/tip-visual-studio-watch-genrico-para-la_22.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0ADSXc4eyp7ImA9WxRbF0o.&quot;"><id>tag:blogger.com,1999:blog-5754664854663769426.post-386534334338025424</id><published>2008-09-20T20:40:00.001+02:00</published><updated>2008-12-08T22:29:38.933+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-12-08T22:29:38.933+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Webs" /><category scheme="http://www.blogger.com/atom/ns#" term="GTD" /><category scheme="http://www.blogger.com/atom/ns#" term="GameProgramming" /><category scheme="http://www.blogger.com/atom/ns#" term="NewThings" /><category scheme="http://www.blogger.com/atom/ns#" term="FAILinks" /><category scheme="http://www.blogger.com/atom/ns#" term="C#" /><title>Comentarios de la semana y estreno</title><content type="html">&lt;p&gt;Bueno, lo primero es lo primero:&lt;/p&gt; &lt;p align="center"&gt;&lt;abbr title=".CPP"&gt;&lt;font face="System" size="5"&gt;&lt;strong&gt;&lt;font color="#0080c0"&gt;CrazyPointer Proudly&lt;/font&gt; &lt;font color="#0080c0"&gt;Presents&lt;/font&gt;&lt;/strong&gt;&lt;/font&gt;&lt;/abbr&gt;&lt;/p&gt; &lt;p align="center"&gt;&lt;strong&gt;&lt;font face="Tempus Sans ITC" color="#004080" size="7"&gt;&lt;/font&gt;&lt;/strong&gt;&amp;nbsp;&lt;/p&gt; &lt;p align="center"&gt;&lt;strong&gt;&lt;font face="Tempus Sans ITC" color="#004080" size="7"&gt;The aiCon&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt; &lt;p align="center"&gt;&lt;a href="http://lh6.ggpht.com/rickyAH/SNVDh8z5fVI/AAAAAAAAALI/MGnEAu0y638/s1600-h/Icono_iPhone3.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="179" alt="Nuevo Icono de pantalla de inicio para el iPhone / iPod Touch" src="http://lh6.ggpht.com/rickyAH/SNVDirMqi9I/AAAAAAAAALM/tmfZaJ4XbEo/Icono_iPhone_thumb1.png?imgmax=800" width="159" border="0"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;Si desde tu iPhone (aifón) o tu iTouch (aipó tach) decides crear un acceso a la pantalla de inicio, este será el icono que te encontrarás. Si ya habías creado el acceso, además de llevarte +20 &lt;a href="http://en.wikipedia.org/wiki/Kudos"&gt;kudos&lt;/a&gt; por tu buen gusto, tendrás que borrarlo y volverlo a crear si quieres &lt;strike&gt;disfrutar de esta obra de arte&lt;/strike&gt; tener un icono más elaborado que el que se crea por defecto.&lt;/p&gt; &lt;p&gt;Y ya de paso para asegurarme de que al menos actualiza esto cada 7 días, pues qué mejor momento que el fin de semana para recopilar un poco todas esas noticias y artículos interesantes que te vas encontrando a lo largo de la semana en el trabajo&lt;font size="1"&gt;(*)&lt;/font&gt; en casa, o las nuevas aplicaciones o utilidades descubiertas. Así de paso el blog me sirve de sistema de referencia :)&lt;/p&gt; &lt;p&gt;Si, lo se, &lt;a href="http://www.google.es/search?&amp;amp;q=links+del+viernes"&gt;es una idea tan original que no entiendo cómo se me ha ocurrido a mi solo&lt;/a&gt;. Pero bueno, a lo que íbamos:&lt;/p&gt; &lt;p&gt;Enlaces de interés sobre programación&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Lista de &lt;a href="http://stackoverflow.com/questions/24692/where-can-you-find-funeducational-programming-challenges"&gt;websites con retos de programación&lt;/a&gt;, obtenido de &lt;a href="http://www.stackoverflow.com"&gt;StackOverflow&lt;/a&gt;.  &lt;li&gt;&lt;a href="http://sqlite.phxsoftware.com/"&gt;Provider de ADO.NET para SQLite&lt;/a&gt;, junto con un &lt;a href="https://addons.mozilla.org/en-US/firefox/addon/5817"&gt;gestor de SQLite en forma de extensión para firefox&lt;/a&gt;.  &lt;li&gt;eBook gratuito sobre &lt;a href="http://submain.com/?nav=products.guidelines"&gt;Coding Guidelines para .NET&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Páginas web:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;&lt;a href="http://www.stackoverflow.com"&gt;www.stackoverflow.com&lt;/a&gt; Esta ya la describí en una &lt;a href="http://crazypointer.blogspot.com/2008/09/stack-overflow-en-beta-pblica.html"&gt;entrada anterior&lt;/a&gt;. Nada más que añadir. &lt;li&gt;&lt;a href="http://www.gamedevkicks.com"&gt;www.gamedevkicks.com&lt;/a&gt; Pagina web con kicks sobre programación de videojuegos.&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Un par de aplicaciones web interesantes:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;&lt;a href="http://www.evernote.com/"&gt;Evernote&lt;/a&gt;.&lt;/li&gt;&lt;/ul&gt; &lt;blockquote&gt; &lt;p&gt;Sirve para gestionar todo tipo de notas y apuntes, y formar una pequeña base de datos. Las notas se organizan en notebooks, y además permite aplicarle etiquetas a las mismas. Permite también hacer búsquedas en ellas, incluso guardando esas búsquedas como accesos directos. Sin embargo la característica más importante es que en Evernote puedes hacer búsquedas por el contenido de las notas, incluso si estas son imágenes, ya que aplica &lt;abbr title="Optical Character Recognition (Reconocimiento &amp;Oacute;ptico de Caracteres)"&gt;OCR &lt;/abbr&gt;a la mismas. &lt;/p&gt; &lt;p&gt;También permite enviar directamente notas utilizando una dirección de correo electrónico, o especificar que los notebooks que quieras sean accesibles públicamente &lt;a href="http://www.evernote.com/pub/rickyah/reference"&gt;via Web&lt;/a&gt;&lt;/p&gt; &lt;p&gt;Y por si fuera poco, además tiene disponibles &lt;a href="http://www.evernote.com/about/download/"&gt;clientes de escritorio&lt;/a&gt; para Windows y Mac que se sincronizan con la web para un acceso offline. También tiene un cliente para SmartPhones y para iPhone / iTouch pero al menos en éste último no almacena las notas para su visionado offline, con lo que pierde toda la utilidad a no ser que estés contactado 24/7 con algún plan de datos, o tengas una WiFi cerca. &lt;/p&gt; &lt;p&gt;Puedes añadir notas manualmente ya sean texto o dibujos (el cliente de escritorio permite dibujar las notas) o bien de forma automática realizando capturas de pantalla (totales o parciales). Por último dispone de una &lt;a href="http://www.evernote.com/about/download/"&gt;extensión de firefox&lt;/a&gt; para capturar con un sólo clic la página actual, asignarla a un notebook y aplicarle etiquetas.&lt;/p&gt; &lt;p&gt;Y por último, es gratuito. Tienes un límite de datos de notas que puedes subir al mes, y si necesitas más entonces puedes solicitar una cuenta premium, que cuenta con un límite mucho mayor.&lt;/p&gt;&lt;/blockquote&gt; &lt;ul&gt; &lt;li&gt;&lt;a href="http://www.toodledo.com/"&gt;ToodLedo&lt;/a&gt; (&lt;a href="http://www.toodledo.com/slim"&gt;versión iPhone&lt;/a&gt;)&lt;/li&gt;&lt;/ul&gt; &lt;blockquote&gt; &lt;p&gt;Es un gestor de tareas online. Es gratuito con opciones de pago, pero la versión básica es muy, muy completa. De lo mejor es que permite importar y exportar a prácticamente todo: Outlook, iCal, Google Calendar, Palm OS, ficheros de texto, CSV, XML, y la mejor, &lt;a href="http://www.toodledo.com/info/help_email.php"&gt;añadir tareas enviando un e-mail&lt;/a&gt;.&lt;/p&gt; &lt;p&gt;Dispone también de &lt;a href="http://www.toodledo.com/widget/index.php"&gt;servicios&lt;/a&gt; para integrarse con otras páginas web como Netvibes o iGoogle y Google Calendar, añadir un Gadget para MacOS, una extensión para firefox que permite acceder a las listas de tareas como una barra lateral o añadir tareas desde el propio navegador incluso dispone de una guía para &lt;abbr title="Getting Things Done"&gt;&lt;a href="http://www.toodledo.com/info/gtd.php"&gt;utilizar Toodledo para seguir la metodología GTD&lt;/a&gt;&lt;/abbr&gt;,.&lt;/p&gt; &lt;p&gt;Una característica curiosa es el booklet, que no es más que la posibilidad de exportar los datos a un PDF que puedes imprimir y recortar para que te quede accesible en papel:&lt;/p&gt; &lt;p align="center"&gt;&lt;img src="http://www.toodledo.com/images/pdfsteps.gif"&gt; &lt;/p&gt; &lt;p align="left"&gt;El único problema que se le puede achacar es que no dispone de clientes de escritorio para acceso offline, pero tampoco es algo muy grave, ya que dispone de una &lt;a href="http://www.toodledo.com/info/api_doc.php"&gt;API pública&lt;/a&gt;, en forma de &lt;a href="http://en.wikipedia.org/wiki/Representational_State_Transfer"&gt;web-services REST&lt;/a&gt;.&lt;/p&gt; &lt;p align="left"&gt;La versión de pago añade un organizador al que le indicas el tiempo que tienes disponible y te genera una lista de tareas de acuerdo a dicho tiempo, personalización del booklet, acceso a estadísticas, subtareas, permitir que otros puedan modificar tu lista de tareas, o conexión segura con &lt;abbr title="Secure Sockets Layer"&gt;SSL&lt;/abbr&gt;.&lt;/p&gt; &lt;p align="left"&gt;Y pim pum pas, la próxima semana más &lt;/p&gt; &lt;p&gt;(*) A la hora del café por supuesto&lt;img alt="coffee" src="http://spaces.live.com/rte/emoticons/coffee.gif"&gt;&lt;/p&gt;&lt;/blockquote&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5754664854663769426-386534334338025424?l=www.crazypointer.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/CrazyPointer?a=jYQVnsdY0jw:keISZPz2FsY:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CrazyPointer?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CrazyPointer?a=jYQVnsdY0jw:keISZPz2FsY:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CrazyPointer?i=jYQVnsdY0jw:keISZPz2FsY:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CrazyPointer/~4/jYQVnsdY0jw" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.crazypointer.com/feeds/386534334338025424/comments/default" title="Enviar comentarios" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=5754664854663769426&amp;postID=386534334338025424" title="0 comentarios" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5754664854663769426/posts/default/386534334338025424?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5754664854663769426/posts/default/386534334338025424?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CrazyPointer/~3/jYQVnsdY0jw/comentarios-de-la-semana-y-estreno.html" title="Comentarios de la semana y estreno" /><author><name>Ricky</name><uri>http://www.blogger.com/profile/18324470751965509112</uri><email>rickyah@gmail.com</email><gd:extendedProperty name="OpenSocialUserId" value="10817153364417160719" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://www.crazypointer.com/2008/09/comentarios-de-la-semana-y-estreno.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0MGSXszfip7ImA9WxRbF0o.&quot;"><id>tag:blogger.com,1999:blog-5754664854663769426.post-7756013066489958964</id><published>2008-09-17T09:39:00.001+02:00</published><updated>2008-12-08T22:23:48.586+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-12-08T22:23:48.586+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="XNA" /><category scheme="http://www.blogger.com/atom/ns#" term="GameProgramming" /><category scheme="http://www.blogger.com/atom/ns#" term="C#" /><title>XNA GameStudio beta 3.0</title><content type="html">Pues al parecer &lt;a href="http://creators.xna.com/en-us/3.0beta_mainpage"&gt;ya ha salido la beta de XNA GameStudio 3.0&lt;/a&gt;. &lt;br /&gt;Entre otras novedades permite usar la versión 3.0 de C#, programar para el &lt;a href="http://www.zune.net/"&gt;Zune&lt;/a&gt;, y crear proyectos para la Xbox360 (aunque me parece que la beta aún no permite probar el código en la consola)&lt;br /&gt;&lt;br /&gt;Habrá que echarle un vistazo :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5754664854663769426-7756013066489958964?l=www.crazypointer.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/CrazyPointer?a=1Xzzl-rHtPU:I5zQhtioxy8:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CrazyPointer?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CrazyPointer?a=1Xzzl-rHtPU:I5zQhtioxy8:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CrazyPointer?i=1Xzzl-rHtPU:I5zQhtioxy8:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CrazyPointer/~4/1Xzzl-rHtPU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.crazypointer.com/feeds/7756013066489958964/comments/default" title="Enviar comentarios" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=5754664854663769426&amp;postID=7756013066489958964" title="0 comentarios" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5754664854663769426/posts/default/7756013066489958964?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5754664854663769426/posts/default/7756013066489958964?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CrazyPointer/~3/1Xzzl-rHtPU/xna-gamestudio-beta-30.html" title="XNA GameStudio beta 3.0" /><author><name>Ricky</name><uri>http://www.blogger.com/profile/18324470751965509112</uri><email>rickyah@gmail.com</email><gd:extendedProperty name="OpenSocialUserId" value="10817153364417160719" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://www.crazypointer.com/2008/09/xna-gamestudio-beta-30.html</feedburner:origLink></entry></feed>
