Articulo tomado de mi blog
Como aumentar el tiempo de carga de nuestras web – los iframe
-------------------------
El tiempo de carga de nuestros sitios web es un tema complejo, abordarlo completamente fácilmente podría ser tema de un solo blog… y no hablemos de las diferencias entre hacerlo con plataformas .Net o LAMP o lo que sea. Es un tema largo.
Así que siempre hay que abordarlo desde lo más grande hasta lo más pequeño. En la web moderna es frecuente encontrarse con iframes puesto que la integración con diversos servicios como redes sociales, mapas y demas gadgets suele hacerse por medio del tag <iframe> , lo cual en resumen es un marco que despliega contenidos alojados en otra web.
El problema con los iframes es que funcionan de manera síncrina, es decir nuestra web esta cargando normalmente, encuentra un iframe y comienza a cargarlo, solo cuando el iframe es cargado por completo continua la carga de los demas elementos de nuestra web.
Lo ideal entonces es hacer que la carga de éstos iframe sea asincónica o bien dilatarla para que inicien su carga solo cuando todo nuestro sitio haya sido desplegado, esto lo podemos hacer manipulando alguno de los eventos de carga de la pagina y luego escribiendo los tag del iframe dinámicamente.
Este es un código de prueba de un iframe
Para cargarlo dinamicamente lo primero que haremos es envolverlo dentro de un nuevo div al cual llamaremos “#map-container”
|
1
2
3
|
<div id="map-container">
</div>
|
Ahora haremos la parte del evento de carga de la página, a mi me gusta hacerlo con JQuery, pero ya sabes que puedes hacerlo con lo que desees. Colocamos el código dentro del evento ready de JQuery. El código es como sigue:
|
1
2
3
4
5
6
|
$(window).load(
function()
{
$("#map-container").html();
}
);
|
Así que ahora tomamos todo el contenido del tag <iframe> y lo enviamos como parámetro:
|
1
2
3
4
5
6
7
|
$(window).load(
function()
{
var iframeString ='<iframe id="Iframe2" name="gmap" width="100%" height="400" src="http://www.otraweb.com"></iframe>';
$("#map-container").html(iframeString);
}
);
|
Y eso es todo, en adelante el tiempo de carga de tu página es independiente del tiempo de carga de los iframe
.
Artículo tomado de mi blog
http://juank.black-byte.com/csharp-richeditbox-rtf-metro-formato/
------------------
Algunas veces cuando cargamos documentos RTF en un RichEditBox nos llevamos la no muy grata sorpresa de que aunque se muestra el texto correctamente los formatos aplicados a este, como color, negrita, itálica, etc. no son tenidos en cuenta.
Podemos abrir los RTF en editores comoWordpad y allí se muestran correctamente. Este problema se debe a que el controlRichEditBox no esta preparado en todo momento para aplicar dichos formatos, razón por la cual no es recomendable asignar el texto del documento hasta no estar 100% seguro de que el control ha cargado en su totalidad, por ende se debe evitar cargar texto en este control en el constructor de su clase contenedora, y en su lugar hacerlo en el evento Loaded, ejemplo:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
<common:LayoutAwarePage
x:Name="pageRoot"
x:Class="Test.GroupDetailPage"
xmlns:local="using:Test"
xmlns:data="using:Test.Data"
xmlns:common="using:Test.Common"
mc:Ignorable="d">
<RichEditBox x:Name="Richtest" Loaded="LoadedEventHandler"/>
</common:LayoutAwarePage>
|
Este es el code Behind
|
1
2
3
4
5
6
|
private void LoadedEventHandler(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
var cadena = @"{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\colortbl;\red255\green0\blue0;}{\cf1 Hello World }{\b nice text}{\par}}";
rich.Document.SetText(TextSetOptions.FormatRtf, cadena);
}
|
artículo tomado de mi blog
http://juank.black-byte.com/csharp-metro-mostrar-colores-rtf-richeditbox/
-----------------
Cuando cargamos documentos RTF en un RichEditBox esperamos que el formato siempre sea el adecuado, sin embargo en ocasiones, especialmente cuando nos entregan los RTF extraidos en una base de datos o en otros formatos diferentes de RTF, nos encontramos con que los textos coloreados no son procesados
EL color dentro de un archivo RTF se encuentra demarcado por medio de los ‘tag’ {\cf# donde # es un numero de color. De esta forma si buscamos dentro de un texto coloreado con RTF podemos encontrar un código como el que se ve a continuación:
|
1
|
{\cf1 Hola Mundo} \b nice text\b0
|
Donde cf1 hace referencia a un color determinado. Retomando el planteamiento inicial es posible en algunos escenarios que el texto sea mkjostrado sin el formato de color, esto se debe a que RTF requiere que se establezca previamente una paleta de colores que indique, por ejemplo, a que color equivale cf1.
Para ello, justo al inicio del documento establecemos la ‘etiqueta’ \colortbl la cual contiene una lista de entradas, donde cada una de estas entradas representa un color, la siguiente muestra una lista de 2 colores definidos, el azul y el rojo.
|
1
2
3
|
{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033
{\colortbl ;\red0\green0\blue255;\red255\green0\blue0;}
}
|
Este color creado en nuestra ‘paleta de colores’ puede ser referido en cualquier parte del documento como cf1, de tal forma si deseamos escribir “Hola Mundo” en color azul y rojo basta con hacer lo siguiente:
|
1
2
3
4
|
{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033
{\colortbl ;\red0\green0\blue255;\red255\green0\blue0;}
{\cf1 Hola}{\cf2 Mundo}
}
|
Si envias el documento (o sea la cadena de texto con la información) dentro de estos tag entonces al cargar la información dentro del RichEditBox debes asegurarte de indicarle el formato que debe aplicar, ejemplo:
|
1
2
3
4
5
|
string cadena = @"{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033
{\colortbl ;\red0\green0\blue255;\red255\green0\blue0;}
{\cf1 Hola}{\cf2 Mundo}
}";
MyRichEditBox.Document.SetText(TextSetOptions.FormatRtf, cadena);
|
De esta forma los documentos RTF cargados mostraran sus colores adecuadamente en un RichEditBox.
Tomado de mi blog:
http://juank.black-byte.com/csharp-richeditbox-rtf-metro/
-------------------
En algunas ocasiones necesitamos cargar documentos RTF en un RichEditBox no direcamente desde archivo sino de otras fuentes, en estas ocasiones es común encontrarnos conque nuestro RTF se muestra de la siguiente manera
|
1
|
{\cf1 Hola Mundo} \b nice text\b0
|
Es decir nuestro RTF muestra el código pero el RichEditBox no es capaz de interpretarlo, este error se debe principalmente a que no se ha indicado el encabezado estandard de un documento RTF. Todo documento RTF debe estar contenido dentro de los siguintes tag omo mínimo:
Sin embargo es recomendable incluir información relacionada con la versión del documento, quedando de esta manera:
|
1
|
{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033 CONTENIDO }
|
Si envias el documento (o sea la cadena de texto con la información) dentro de estos tag entonces al cargar la información dentro del RichEditBox debes asegurarte de indicarle el formato que debe aplicar, ejemplo:
|
1
2
|
string cadena = @"{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033 Hello World\par}";
MyRichEditBox.Document.SetText(TextSetOptions.FormatRtf, cadena);
|
De esta forma ya no apreceran carácteres ‘basura’ el cargar tus datos RTF en un RichEditBox
Articulo tomado de mi blog:
http://juank.black-byte.com/csharp-archivo-configuracion-limpio/
-----------------
o Como reducir el archivo de configuración usando múltiples archivos .config
Como programadores siempre tenemos que lidiar con archivos de configuración, en mi opinión una hermosa forma de deshacernos de complejidad innecesaria en el código y desde luego una manera muy cool de crear aplicaciones fléxibles.
Sin embargo en aplicaciones de tipo empresarial comenzamos a tener detestables problemas con estos archivos. El notable aumento de complejidad en su estructura se convierte en una bomba de tiempo para el mantenimiento de las aplicaciones, es común encontrase con archivos de configuración que se miden en cientos de lineas y a veces en miles.
Cómo tener un archivo de configuración más limpio?
Por fortuna existe un mecanismo muy útil, a continuación les muestro un archivo de configuración que si bien no es uno precisamente enorme, ya comienza a mostrar problemasde legibilidad, en esta ocasión generados por la configuración de Unity Application Block , hablaremos de el en otro momento.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 | <?xml version="1.0"?>
<configuration>
<configSections>
<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration" />
</configSections>
<typeAliases>
<typeAlias alias="singleton"
type="Microsoft.Practices.Unity.ContainerControlledLifetimeManager,
Microsoft.Practices.Unity" />
<typeAlias alias="external"
type="Microsoft.Practices.Unity.ExternallyControlledLifetimeManager,
Microsoft.Practices.Unity" />
<typeAlias alias="web_session"
type="Traversal.Utilities.Web.WebSessionLifetimeManager,
Traversal" />
<typeAlias alias="IDataContextWrapper" type="Domain.Core.Data.IDataContextWrapper`1, Domain.Core" />
<typeAlias alias="IParameterManager" type="Domain.Core.Repositories.IParameterManager, Domain.Core" />
<typeAlias alias="ILocalizationManager" type="Domain.Core.Repositories.ILocalizationManager, Domain.Core" />
<typeAlias alias="ContextWrapperSTE" type="Domain.Core.Data.ContextWrapperSTE`1, Domain.Core" />
<typeAlias alias="ContextWrapperEF" type="Domain.Core.Data.ContextWrapperEF`1, Domain.Core" />
<typeAlias alias="ParameterManager" type="Domain.Core.Repositories.ParameterManager, Domain.Core" />
<typeAlias alias="LocalizationManager" type="Domain.Core.Repositories.LocalizationManager, Domain.Core" />
<typeAlias alias="IEnteManager" type="Domain.wsldckm.Repositories.IEnteManager, Domain.oplkjsdfkpwe" />
<typeAlias alias="IEquipoManager" type="Domain.wsldckm.Repositories.IEquipoManager, Domain.oplkjsdfkpwe" />
<typeAlias alias="IEstadioManager" type="Domain.wsldckm.Repositories.IEstadioManager, Domain.oplkjsdfkpwe" />
<typeAlias alias="IEventoManager" type="Domain.wsldckm.Repositories.IEventoManager, Domain.oplkjsdfkpwe" />
<typeAlias alias="IPartidoManager" type="Domain.wsldckm.Repositories.IPartidoManager, Domain.oplkjsdfkpwe" />
<typeAlias alias="ITagManager" type="Domain.wsldckm.Repositories.ITagManager, Domain.oplkjsdfkpwe" />
<typeAlias alias="ITipoFormacionManager" type="Domain.wsldckm.Repositories.ITipoFormacionManager, Domain.oplkjsdfkpwe" />
<typeAlias alias="ITorneoEtapaManager" type="Domain.wsldckm.Repositories.ITorneoEtapaManager, Domain.oplkjsdfkpwe" />
<typeAlias alias="ITorneoNominaManager" type="Domain.wsldckm.Repositories.ITorneoNominaManager, Domain.oplkjsdfkpwe" />
<typeAlias alias="ITorneoManager" type="Domain.wsldckm.Repositories.ITorneoManager, Domain.oplkjsdfkpwe" />
<typeAlias alias="EnteManager" type="Domain.wsldckm.Repositories.EnteManager, Domain.oplkjsdfkpwe" />
<typeAlias alias="EquipoManager" type="Domain.wsldckm.Repositories.EquipoManager, Domain.oplkjsdfkpwe" />
<typeAlias alias="EstadioManager" type="Domain.wsldckm.Repositories.EstadioManager, Domain.oplkjsdfkpwe" />
<typeAlias alias="EventoManager" type="Domain.wsldckm.Repositories.EventoManager, Domain.oplkjsdfkpwe" />
<typeAlias alias="PartidoManager" type="Domain.wsldckm.Repositories.PartidoManager, Domain.oplkjsdfkpwe" />
<typeAlias alias="TagManager" type="Domain.wsldckm.Repositories.TagManager, Domain.oplkjsdfkpwe" />
<typeAlias alias="TipoFormacionManager" type="Domain.wsldckm.Repositories.TipoFormacionManager, Domain.oplkjsdfkpwe" />
<typeAlias alias="TorneoEtapaManager" type="Domain.wsldckm.Repositories.TorneoEtapaManager, Domain.oplkjsdfkpwe" />
<typeAlias alias="TorneoNominaManager" type="Domain.wsldckm.Repositories.TorneoNominaManager, Domain.oplkjsdfkpwe" />
<typeAlias alias="TorneoManager" type="Domain.wsldckm.Repositories.TorneoManager, Domain.oplkjsdfkpwe" />
</typeAliases>
<containers>
<container name="WebContainer">
<types>
<type type="IParameterManager" mapTo="ParameterManager" />
<type type="ILocalizationManager" mapTo="LocalizationManager" />
<type type="IDataContextWrapper" mapTo="ContextWrapperEF">
<lifetime type="web_session" />
</type>
<type type="IEnteManager" mapTo="EnteManager" />
<type type="IEquipoManager" mapTo="EquipoManager" />
<type type="IEstadioManager" mapTo="EstadioManager" />
<type type="IEventoManager" mapTo="EventoManager" />
<type type="IPartidoManager" mapTo="PartidoManager" />
<type type="ITagManager" mapTo="TagManager" />
<type type="ITipoFormacionManager" mapTo="TipoFormacionManager"/>
<type type="ITorneoEtapaManager" mapTo="TorneoEtapaManager" />
<type type="ITorneoNominaManager" mapTo="TorneoNominaManager" />
<type type="ITorneoManager" mapTo="TorneoManager" />
</types>
</container>
<container name="StandAloneContainer">
<types>
<type type="IParameterManager" mapTo="ParameterManager" />
<type type="ILocalizationManager" mapTo="LocalizationManager" />
<type type="IDataContextWrapper" mapTo="ContextWrapperEF" >
<lifetime type="singleton" />
</type>
</types>
</container>
</containers>
</unity>
<appSettings>
<add key="UnitySection" value="unity"/>
<add key="UnityContainer" value="WebContainer"/>
</appSettings>
<connectionStrings>
<add name="CoreContext"
connectionString="metadata=res://Data.Core/DataCoreModel.csdl|res://*/DataCoreModel.ssdl|res://*/DataCoreModel.msl; provider=System.Data.SqlClient;provider connection string="
data source=reveverv.database.windows.net;initial catalog=rrvr;
persist security info=True;user id=erverver;password=erverver;
multipleactiveresultsets=True;application name=EntityFramework""
providerName="System.Data.EntityClient" />
<add name="wdsefreContext" connectionString="metadata=res://Data.Core/erverModel.csdl|res://*/ervercvModel.ssdl|res://*/erverv.msl; provider=System.Data.SqlClient;provider connection string="
data source=erfververv.database.windows.net;initial catalog=rverv;
persist security info=True;user id=erververv;password=dfvdfv;
multipleactiveresultsets=True;application name=EntityFramework""
providerName="System.Data.EntityClient" />
<add name="ApplicationServices"
connectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\aspnetdb.mdf;User Instance=true"
providerName="System.Data.SqlClient" />
</connectionStrings>
<system.web>
<compilation debug="true" targetFramework="4.0" />
<authentication mode="Forms">
<forms loginUrl="~/Account/Login.aspx" timeout="2880" />
</authentication>
<membership>
<providers>
<clear/>
<add name="AspNetSqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="ApplicationServices"
enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false"
maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10"
applicationName="/" />
</providers>
</membership>
<profile>
<providers>
<clear/>
<add name="AspNetSqlProfileProvider" type="System.Web.Profile.SqlProfileProvider" connectionStringName="ApplicationServices" applicationName="/"/>
</providers>
</profile>
<roleManager enabled="false">
<providers>
<clear/>
<add name="AspNetSqlRoleProvider" type="System.Web.Security.SqlRoleProvider" connectionStringName="ApplicationServices" applicationName="/" />
<add name="AspNetWindowsTokenRoleProvider" type="System.Web.Security.WindowsTokenRoleProvider" applicationName="/" />
</providers>
</roleManager>
</system.web>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
|
Toda sección posee un atributo configSource en el cual se puede indicar la ruta donde se encuentra definido el XML, asi que podemos extraer toda la sección de Unity en un archivo Unity.config , incluyendo la etiqueta y sus atributos, y el archivo de configuración quedaria de la siguiente forma, bastante más legible y manteniendo toda su funcionalidad.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | <?xml version="1.0"?>
<configuration>
<configSections>
<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration" />
</configSections>
<unity configSource="Unity.config" />
<appSettings>
<add key="UnitySection" value="unity"/>
<add key="UnityContainer" value="WebContainer"/>
</appSettings>
<connectionStrings>
<add name="CoreContext"
connectionString="metadata=res://Data.Core/DataCoreModel.csdl|res://*/DataCoreModel.ssdl|res://*/DataCoreModel.msl; provider=System.Data.SqlClient;provider connection string="
data source=reveverv.database.windows.net;initial catalog=rrvr;
persist security info=True;user id=erverver;password=erverver;
multipleactiveresultsets=True;application name=EntityFramework""
providerName="System.Data.EntityClient" />
<add name="wdsefreContext" connectionString="metadata=res://Data.Core/erverModel.csdl|res://*/ervercvModel.ssdl|res://*/erverv.msl; provider=System.Data.SqlClient;provider connection string="
data source=erfververv.database.windows.net;initial catalog=rverv;
persist security info=True;user id=erververv;password=dfvdfv;
multipleactiveresultsets=True;application name=EntityFramework""
providerName="System.Data.EntityClient" />
<add name="ApplicationServices"
connectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\aspnetdb.mdf;User Instance=true"
providerName="System.Data.SqlClient" />
</connectionStrings>
<system.web>
<compilation debug="true" targetFramework="4.0" />
<authentication mode="Forms">
<forms loginUrl="~/Account/Login.aspx" timeout="2880" />
</authentication>
<membership>
<providers>
<clear/>
<add name="AspNetSqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="ApplicationServices"
enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false"
maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10"
applicationName="/" />
</providers>
</membership>
<profile>
<providers>
<clear/>
<add name="AspNetSqlProfileProvider" type="System.Web.Profile.SqlProfileProvider" connectionStringName="ApplicationServices" applicationName="/"/>
</providers>
</profile>
<roleManager enabled="false">
<providers>
<clear/>
<add name="AspNetSqlRoleProvider" type="System.Web.Security.SqlRoleProvider" connectionStringName="ApplicationServices" applicationName="/" />
<add name="AspNetWindowsTokenRoleProvider" type="System.Web.Security.WindowsTokenRoleProvider" applicationName="/" />
</providers>
</roleManager>
</system.web>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
|
Y desde luego ese mismo atributo lo podemos usar en todas las secciones que superen un tamaño pequeño.
Enjoy it!
Artículo original de mi blog
http://juank.black-byte.com/varios-galardonado-como-microsoft-mvp-visual-c-2012-4to-ano-consecutivo/
------------

Hola,
hace un mes fui galardonado MVP por 4to año consecutivo. He tardado en hablar al respecto más que nada porque ando atravesando una etapa de mi vida bastante compleja en lo que a nivel laboral se refiere, sobrabundancia se podría llamar, y eso me ha obligado a reducir muchos de los espacios que tenía antes disponibles para todas estas actividades.
Tras 4 años es muy difícil no repetirse, eso o tengo muy mala imaginación.
Gracias a todos porque lograr esto no es fácil requiere del apoyo de muchos nerds o geeks como yo
.
con algo de suerte el año que viene puede que sea nombrado de nuevo, y de seguro tendre algo muy interesante para escribir.
Hasta pronto.
Artículo original de mi blog
http://juank.black-byte.com/sistemas_operativos-necesitan-programas-para-hacer-programas/
------------
Me preguntaron con que programa, se hacen los programas que hacen programas?
Si nos ponemos a pensar, parece ser un ciclo infinito, una paradoja. Se necesitan programas para hacer programas.
Pero este tema repasando un poco de historia es mucho más fácil de entender.
No pretendo en este artículo hacer un informe detallado y preciso de la historia de los lenguajes de programación, simplemente aportare los elementos mínimos para resolver esta paradoja: “
Se necesitan programas para hacer programas ”.
En un principio siempre se programaba en lenguaje de máquina, el lenguaje de maquina son opcodes, lenguajes de 1ra generación, es decir solo números en código binario, cada instrucción [opcode] tiene un equivalente mas nemotécnico en ensamblador, es decir por cada instrucción[numero de instrucción] que entiende el procesador existe una palabra que la representa y es mas fácil de recordar, esto es el lenguaje ensamblador.
Así que inicialmente se hicieron programas en opcode que al ‘ensamblarlos’ generaban un archivo binario con códigos de maquina. Ensamblador es entonces un lenguaje de 2da generación.
Después vinieron los lenguajes de 3ra generación: cobol y fortran por ejemplo, que con una instrucción podían representar varias instrucciones de Ensamblador, sin embargo los programas siguieron creciendo y hacer software se hizo difícil, así que se genero la necesidad de tener lenguajes que permitieran reusar más código y que fueran más fácil de entender, que estuvieran mejor estructurados.
Así nació el lenguaje C, luego de que Ritchie se diera cuenta de la gran cantidad de instrucciones repetitivas y de la enorme complejidad del software, decidió crear un lenguaje donde cada palabra representara varias instrucciones y estas además pudieran ser agrupadas de manera lógica(funciones) en componentes reutilizables. También pensó en que todas estas virtudes no deberían ser una limitante para manejar instrucciones de maquina a bajo nivel así que incluyo los apuntadores para acceso directo a memoria y le dio al lenguaje la capacidad de incluir fragmentos de ensamblador cuando fuera necesario,así creo los while, los if y los for del lenguaje C, las funciones. etc. C es uno de los lenguajes de 3ra generación, de hecho el lenguaje más popular de esa generación que incluso hoy día con nuevas generaciones y formas de hacer las cosas sigue vigente aunque ha cedido mucho terreno (casi todo) a C++.
Desde 3ra generación en adelante hay algunas variantes adicionales pero este es el resumen.
En los lenguajes 4ta generación tenemos lenguajes aún más orientados a objetos, con otras características que permiten que el desarrollador se preocupe más en el ‘que debo hacer‘ que en el ‘como se hace‘, por ello tenemos lenguajes con memoria administrada como Java, C# y Visual Basic entre otros que abstraen gran parte de las complejidades de la máquina en pro de enfocarse en el resultado.
Finalmente los lenguajes de 5ta generación, enfocados en gran parte a la inteligencia artificial pero no únicamente a ello, ya que también se ha abierto espacio para los lenguajes híbridos, como es el caso de C# que hoy día es POO pero también tienesentencias dinámicas funcionales que le dan un comportamiento muy similar a los lenguajes de 5ta generación.
F# es un lenguaje de 5ta generación así como Lisp y Prolog estos últimos con un intenso uso en temas de inteligencia artificial.
Con esto queda resuelta la paradoja de Se necesitan programas para hacer programas. Los primeros programas creados se hicieron directamente en lenguaje de máquina, y según el software se fue haciendo más complejo se generó la necesidad de tener programas que permitieran escribir de forma más natural, inicialmente ensamblador donde cada instrucción del lenguaje equivalía a una instrucción de la máquina, y luego con lenguajes de nivel superior donde una instrucción correspondía a muchas instrucciones de la maquina, esa tarea de traducir de un lenguaje más ‘natural’ al lenguaje de máquina sed hace por medio de programas llamados compiladores, los cuales no solo traducen sino que analizan el conjunto del programa escrito para escribir la misma versión del programa en lenguaje de máquina con tan pocas instrucciones como sea posible.
Como se darán cuenta no todo tiempo pasado fue mejor, cosas tan habituales el día de hoy como procesar el evento clic de un botón pueden tener tras de sí miles de instrucciones ya en el lenguaje de máquina, instrucción es que antes debían escribir los desarrolladores una y otra vez.
Por suerte los ingenieros y desarrolladores hemos sido muy ingeniosos y aunque el resto de la industria se ha dedicado a mejorar a costa de funcionalidades más y más complejas hemos sabido jugar nuestras fichas, hemos mejorado nuestras herramientas con nuestros propios programas y hoy día hacemos en un clic lo que antes nos tomaba semanas, o incluso meses.
Artículo tomado de http://juank.black-byte.com/varios/uncategorized-volcados-memoria-server-2008-r2-adplus/
El caso de los volcados de memoria en Windows Server 2008 R2 con adplus.vbs
----------
Hace tiempos que no necesitaba hacer una sesión de depuración, y esta vez realizando consultoria con uno de mis clientes me reportaron un problema ejecutando adplus.vbs.
Lo primero que me encontré es que adplus.vbs ahora fue reemplazado con adplus_old.vbs ya que en su lugar hay una nueva versión de adplus que es un .exe que se ejecuta con powershell. Eso ya es una tarea para aprender.
Sin embargo una vez subsanado esto me di cuenta que tampoco funcionaba, al tratar de generar el volcado ejecute esta instrucción arrojándome el resultado que se ve a continuación:
adplus_old.vbs -hang -pn w3wp.exe -o c:\volcado
Attaching the debugger to: W3WP.EXE_-DefaultAppPool-_-v_-v2.0-_-l_-webengine4.dll-_-a_-.-pipe-iisipm06ba2546-4f31-46b0-8 953-d2ce72ddb19e_-h_-C-inetpub-temp-apppools-DefaultAppPool-DefaultAppPool.config-_-w_–_-m_0_-t_20 (Process ID: 1008) Error creating file: c:\volcado\Hang_Mode__Date_02-07-2012__Time_09-51-11m.\CDBScripts\PID-1008__W3WP.EXE_-DefaultAppPoo l-_-v_-v2.0-_-l_-webengine4.dll-_-a_-.-pipe-iisipm06ba2546-4f31-46b0-8953-d2ce72ddb19e_-h_-C-inetpub-temp-apppools-Defau ltAppPool-DefaultAppPool.config-_-w_–_-m_0_-t_20.cfg Error: 76 – Ruta de acceso no encontrada
Se me hizo raro, verifique que el directorio al que hacia referencia existiera y que tuviese los persmisos necesarios, y todo esraba OK.
Digamos que me quede barado, pero decidí hecharle un vistazo al código, pues adplus es un archivo .vbs ( visual basic script ), así que no debería ser muy complicado.
Me detuve a analizar el error y vi "Attaching the debugger to:" lo cual esta un poco antes de "Error creating file:" así que abri el archivo adplus_old.vbs desde el editor y busqué ese trozo de código
Todo parecia normal, no encontraba nada en el código que mmostrara un error. Así que regrese al nombre del archivo demasiado largo se veia, eso si. Conte los caracteres y el resultado fué 273… OOOOps se supone que el path máximo son 255 caracteres, así que decidí acortar el path.
La ruta a la carpeta no la puedo modificar, debe ser tan autonoma como sea posible, pero el nombre del paquete si lo puedo modificar, y es fácil hacerlo ya que justo despues de "Attaching the debugger to:" se hace referencia a strPackageNamesimplemente lo deje de 25 caracteres ya que está demasiado grande.
Así que inmediatamente despues de "Attaching the debugger to:" adicione este trozo de código:
1 2 3 | If LEN(strPackageName)>25 then
strPackageName=LEFT(strPackageName,25)
End If
|
Procedí a ejecutar nuevamente el proceso y…. Funciona todo OK
Attaching the debugger to: W3WP.EXE_-DefaultAppPool-_-v_-v2.0-_-l_-webengine4.dll-_-a_-.-pipe-iisipmdd4ec914-7997-4b58-9
2ec-330e042592d7_-h_-C-inetpub-temp-apppools-DefaultAppPool-DefaultAppPool.config-_-w_–_-m_0_-t_20
(Process ID: 2764)
Caso Cerrado!
Articulo originalmente escrito en el blog: http://juank.black-byte.com/varios-caso-problemas-live-writer-wordpress/
Sigueme en Twitter: @JuanKRuiz
-------------------------------------------------------
Como de seguro a muchos de mis lectores les sucede Live Writer se ha convertido e una herramienta fundamental.
Live Writer es una de las herramientas por excelencia para los blogueros más avanzados.
Por mucho tiempo fue mi herramienta infaltable hasta que un día… no se que paso, ni como ni donde ni porqué… pero lo cierto es que dejo de funcionar.
Lo acepto, me dio pereza utilizar mis super poderes de developer, así que busque en foros , blogs, amigos etc. sin éxito y comencé a hacerlo de nuevo en el blog de notas… probé otros blog writers, sin quedar satisfecho.
Hasta que en un día de Junio me harté.
Respire, mire a mis adentros y me dije, es hora de utilizar mis super poderes y lo solucione.
Esta es la historia.
El error
Cada vez que trataba de hacer algo con mi blog desde Live Writer me salía este error

Así que decidí volver a inscribir el blog en Live Writer con tan mala suerte que sucedió exactamente lo mismo y ya nunca más funciono.

En busca de soluciones
El Log
Como pueden ver el mensaje de error sirve para poco y nada.
"Error al intentar conectar con tu servicio de blog:
Respuesta de servidor no válida –
La respuesta al método blogger.getUsersBlogs recibida desde el servidor de blogs no era válida:
Invalid response document returned from XmlRpc server Intenta solucionar el problema y, a continuación, inténtalo de nuevo."
Me pregunto que $#%#$ es blogger.getUsersBlogs y que tiene que ver con WordPress :S
Así que era el momento de buscar logs.
El log de Live Writer en Windows Vista y Windows 7 esta en "%localappdata%\Windows Live Writer" , en el caso de XP y otras versiones de Windows puede variar.
Allí esta el archivo "Windows Live Writer.log" el cual podemos revisar.

Lo primero que notamos es que vuelve a aparecer el tema de XmlRpc lo cual aún no nos dice nada, pero algo si es muy importante: "La respuesta del servidor no es válida" aunque hasta el momento eso tampoco nos sirve de nada.
Este es uno de esos momentos en que te das por vencido esperando que alguna vez WordPress o Live Writer corrijan un bug en su código… si algún día.
Salvo que uses tus super poderes de developer.
Buscando en internet encontré muchos problemas diferentes de Live Writer los cuales para solucionarlos hay que revisar el archivo xmlrpc.php de WordPress, sin embargo para no comer entero busqué de donde salía ese archivo.
Lo usual es que podemos cambiar el inicio de Live Writer para que el log sea más detallado, eso se hace llamando al ejecutable de Live Writer así
WindowsLiveWriter.exe /verbose
Una vez hecho de esa manera, debes replicar el error y de nuevo revisar el log el cual ahora es más detallado, en mi caso encontré esto:

La palabra clave es Request y la URL de dicho Request … así llegamos al archivo xmlrpc.php de WordPress.
http://juank.black-byte.com/wordpress/xmlrpc.php
Con esta información podemos suponer que ese Request esta devolviendo una respuesta incorrecta.
Al revisar el archivo xmlrpc.php de WordPress me pregunte ¿Cómo es que de la noche a la mañana ahí hay algo mal si yo nunca le he hecho nada?
Gran pregunta, pero sospeche de los plugin, por lo cual desactive todos ellos y taraaaaaaaaaaaaaaaan: no paso nada, el error persistia. #Fail
Revise el código meticulosamente, pero no encontré nada extraño.
Toco sacar el developer super sayayin nivel 2.
Revisando el request
Al ingresar http://juank.black-byte.com/wordpress/xmlrpc.php por el explorador web, obtengo la respuesta
XML-RPC server accepts POST requests only.
así que tenia que hacer un Request vía POST y de seguro comenzar a obtener tanta información como pudiera de su respuesta.
Comencé a indagar en internet acerca de como hacer un Request a una URL sin necesidad de hacer mi propio programa, lo cual era de una vez mi plan B. De esta forma encontré una herramienta llamada Feedler la cual tiene un nombre bastante self explained: "Feedler Web Debugging Proxy".
Lo pueden obtener acá: http://www.fiddler2.com/fiddler2/
No entrare en detalles de como hace feedler para funcionar, pero el que lo desee puede investigarlo.
Así que uso feedler para hacer un Request a http://juank.black-byte.com/wordpress/xmlrpc.php .
Voy a la pestaña "Request Builder" donde configuro la URL y el método del Request el cual es POST:

Le doy execute e inmediatamente obtengo esto:

Content-Length mismatch: Response Header indicated 386 bytes, but server sent 389 bytes.
Bingo!! mm no tan rápido.
Doy doble clic sobre el Request fallido, recién hecho, para examinar sus detalles, estos detalles de la respuesta salen a la derecha en la parte inferior, aparentemente no dice nada del otro mundo pero entonces me voy a la pestaña Raw para ver la respuesta sin procesar, tal como es enviada por el servidor.

Tampoco veo nada anómalo, entro en depresión. (jejeje)
De repente veo la pestaña HexView la cual es aún más Raw (jejeje), ahora si estamos hablando el mismo idioma: bytes.
Comparando la vista Raw con la Hexa me doy cuenta que puedo diferenciar fácilmente el header del Response de su contenido, sumado a que en la vista Hexa Feedler me pone el header de color verde como se ve aquí:

Todo va bien hasta que comienzo a ver los bytes traspasar por mi cuerpo y lo veo allí…
Neo: Hiya, fellas.
Agent Johnson: It’s him.
Agent Thompson: The anomaly.
Agent Jackson: Do we proceed?
Agent Johnson: Yes…
Agent Thompson: …he is still…
Agent Jackson: …only human.
Estos 3 caracteres  son los 3 primeros caracteres después de los header.
Desconozco los detalles de longitud de los headers, pero el error anterior era claro: "en el header se indican 386 bytes, pero el servidor envió 389 bytes".
La diferencia según el mensaje son 3 bytes y casualmente ‘la anomalía’ es de 3 bytes. Te tengo!
Como muchos de ustedes pueden saber y sino de una vez les cuento PHP tiene la particularidad de que si se incluyen líneas en blanco antes o después de los tag <?php … ?> se pueden generar resultados inesperados… que belleza.
Procedí, entonces a revisar el archivo xmlrpc.php para eliminar dichos espacios, pero para mi sorpresa no había ninguno.
Como es de suponerse las funcionalidades de ese archivo son llamadas desde otros archivos así que por descarte escogí los archivos de WordPress que yo si había modificado: los de el tema actual del blog, los revise uno por uno y encontré varios con líneas en blanco al inicio o al final… o en ambos casos.
Procedí a eliminarlos pero al probar Live Writer… no había funcionado.
Nuevamente me quede sin opciones.No había podido solucionar el problema. #fail
A debugguear! o algo así.
Solución … a medias pero solución
Estaba seguro que el problema estaba en los 3 bytes, eso era un hecho, para descartar fui a xmlrpc.php de WordPress y verificando sus referencias llegue a class-wp-xmlrpc-server.php y a class-IXR.php.
Para mi alegre sorpresa encontré que class-wp-xmlrpc-server.php esta repleto de llamados a métodos llamados getUsersBlogs y que casualmente cuando se llama a wp_getUsersBlog aparece esto
1 2 3 4 5 6 7 8 9 10 | function wp_getUsersBlogs( $args )
{
global $current_site;
if ( !is_multisite() )
{
array_unshift( $args, 1 );
return $this->blogger_getUsersBlogs( $args );
}
}
|
De allí se origina el error que al inicio del blog nos arrojaba el Live Writer. Continúe con mi búsqueda revisando en donde se escribían los headers exactamente el header de la longitud del Response, pero no lo encontré, por lo cual supuse que era una funcionalidad heredada.
Verificando el código línea a línea llegue a class-IXR.php y allí estaba:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | function output($xml)
{
$xml = '<?xml version="1.0"?>'."\n".$xml;
$length = strlen($xml);
header('Connection: close');
header('Content-Length: '.$length);
header('Content-Type: text/xml');
header('Date: '.date('r'));
echo $xml;
exit;
}
|
Lo revise meticulosamente y en apariencia no había nada que hiciera que el header "Content-Length" reportara un tamaño incorrecto.
Así que nada más por descartar en la parte donde se establece el tamaño, en el encabezado, le sume 3 bytes.
Ejecuté Live Writer y FUNCIONO!!
Ok, pero esta no es una solución decente, porque si me volvía a pasar que debería hacer?
modificar todas las veces este fuente y forzar que el conteo sea el correcto.
Eso no es nada profesional… y por demás… dónde se genera la anomalía?
Hasta acá no tenia idea de que más hacer y ya se había hecho bastante
Pero bueno, podemos ser super saiyayin nivel 3.
Buscando la anomalía, desde sus raíces – BOM .
Los bytes anómalos son EF BB BF respectivamente: 
Inicie mi búsqueda por internet con los caracteres anómalos y aunque habían algunas pistas no me llevaba a nada concreto, así que busque por los valores hexa y el primer artículo que salió era de Wikipedia:
Byte order mark : http://en.wikipedia.org/wiki/Byte_order_mark
Resulta que exactamente estos tres caracteres (BOM) son una marca de bytes utilizada en archivos de texto de manera opcional para indicar que codificación trae el archivo, si lo trae el archivo es un archivo codificado en UTF-8 sin lugar a duda… pero BOM ya es poco usado porque se presta para malas interpretaciones.
Esos caracteres BOM pudieron haber sido agregados a cualquier archivo de php dentro de mi WordPress, de hecho mi problema original era con 6 caracteres y no con 3 como lo he explicado para simplificar un poco el problema, lo cual me hacia pensar que como mínimo habían dos archivos con ese problema.
El problema con BOM es que muchos editores no muestran esos caracteres porque precisamente saben que son BOM y que no se muestran sino que se usan como guía para saber que tipo de codificación tiene el archivo. Así que no es cuestión de abrir los archivos y editarlos.
Estas imagen muestran como se ve un archivo con BOM en un editor de texto y como se ve en un editor binario:


Potencialmente cualquier archivo .php en mi WordPress podría tener ese problema pero revisar algo así como 1000 archivos en modo binario desde Visual Studio para remover 3 bytes en cada uno podría ser dispendioso, más aún cuando no en todos debería quitar esos 3 bytes sino solo en los que tuviesen BOM.
Deshice los cambios que sumaban 3 bytes en el header.
De nuevo hacer un programa por mi cuenta era el plan B. Buscando por Internet Llegué a esta herramienta gratuita
Replace Pioner http://www.mind-pioneer.com/
Debo admitir… es un enrredo internamente muy bueno pero una UI de la vieja guardia.
Les diré como usarlo para este problema puntual. Lo primero es que baje mi sitio de WordPress a carpeta local.
- Abrimos replace pioner
- Vamos a Tools>_Batch Runner
- Como no sabemos cuantos archivos de nuestra instalación de WordPress tienen ese problema usamos la opción Search Files y filtramos todos los archivos .php del directorio y subdirectorios de WordPress

- Clic en Search y listo tenemos listados todos los archivos .php
- Cerramos el dialogo
- En la parte inferior de Batch Runner tenemos el botón "Fast Replace" lo presionamos.
- En el dialogo que se abre seleccionamos el template de "binary file — remove utf-8 BOM"
- Presionamos Add
- Seguidamente Start

Tomara unos segundos y podemos ver el log de los cambios realizados, eso nos permitirá saber que archivos eran los culpables.
Una vez finalice el proceso copiamos los archivos de nuevo a nuestro sitio, vamos a Windows Live Writer y BINGO!!
Ahora si todo funcionando y de la manera más profesional posible.
Como prevenirlo
En algún lugar de la web encontré algo ingenioso.
Si bien puedes ser prevenido y siempre desde tu editor darle "guardar como" y seleccionar todo menos UTF-8 un truco es que al menos en los comentarios incluyan una letra que no sea de UTF-8 por ejemplo la ‘ñ’ con esto automáticamente el editor no hará uso del BOM ni nada similar.
Estoy seguro que este artículo les habrá encantado.
Byte!
Tomado de
El bucle de mensajes - message loop - WndProc
-------------------
Debido a que este es un tema recurrente en este blog, he decidido extraer este pequeño aporte hecho en otro artículo para poder referenciarlo puntualmente cuando se requiera.
Las ventanas – y los demás controles – funcionan gracias a un bucle de mensajes, todo lo que manejamos nosotros como eventos : click del mouse, mover, cerrar, cambiar tamaño, maximizar etc, realmente es controlado por un bucle en donde se envían diferentes mensajes a la ventana, esta a su vez tiene un procedimiento que recibe estos mensajes y con base a los mensajes recibidos puede hacer una u otra cosa según se programe.
Si, para algunos esto ya debe estar sonando a cuento, pero las cosas son así por debajo de lo que usamos tradicionalmente. El tema del artículo no es explicar como funciona un ciclo de mensajes así que por el momento lo dejaremos hasta allí y quien quiera profundizar puede consultar esta fuente en internet
http://www.winprog.org/tutorial/message_loop.html
Esta es una copia cruzada de mi blog original.
Puedes leer el articulo original con código coloreado y demás utilidades en
C# - Como obtener un manejador (handle) para una ventana de WPF
-------------------------------------
WPF es una parte del .Net Framework muy robusta pensada para ser multiplataforma, pero a veces necesitamos que nuestra aplicación interactue con aspectos más relacionados con el sistema operativo donde se ejecuta. En estos casos requerimos el menejador ( handle ) de la ventana el cual no es expuesto por WPF.
Para obtenerlo debemos hacer uso de una clase utilitaria llamada WindowInteropHelper la cual tiene un elemento muy importante, la propiedad Handle que no es ni más menos que el manejador a la ventana de WPF. Su uso es muy sencillo:
[csharp]
Window miVentana = this;
WindowInteropHelper interopHelper = new WindowInteropHelper(miVentana);
IntPtr manejadorVentana = interopHelper.Handle;
[/csharp]
El código esta así por claridad, dentro del código de una ventana de WPF a la que querramos obtenerle el manejador basta con hacer:
[csharp]
WindowInteropHelper interopHelper = new WindowInteropHelper(this);
IntPtr manejadorVentana = interopHelper.Handle;
[/csharp]
Ya teniendo el manejador de la ventana podemos acceder a muchas otras funcionalidades fuertemente atadas con el SO como por ejemplo las expuestas en Win32Api o equivalente en otras plataformas
Esta es una copia cruzada de mi blog original.
Puedes leer el articulo original con código coloreado y demás utilidades en
C# - usar el WndProc en una Ventana WPF
----------------------------------
WPF es una parte del .Net Framework muy robusta pensada para ser multiplataforma, pero a veces necesitamos que nuestra aplicación interactue con aspectos más relacionados con el sistema operativo donde se ejecuta. En estos casos requerimos interceptar mensajes en el WndProc.
Para lograr acceder al WndProc debemos obtener un manejador (handle) para la ventana WPF y seguidamente utilizar la clase utilitaria HwndSource para crear el Hook, allí creamos un delegado el cual hara las veces de WndProc de nuestra ventana.
[csharp]
WindowInteropHelper interopHelper;
private void Window_Loaded(object sender, RoutedEventArgs e)
{
//Conseguir el Handle de la ventana
interopHelper = new WindowInteropHelper(this);
//Crear un hook al WndProc
HwndSource sourceWindow = HwndSource.FromHwnd(interopHelper.Handle);
sourceWindow.AddHook(WndProc);
}
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
//Hacer algo...
return IntPtr.Zero;
}[/csharp]
Y eso es todo ;)
Esta es una copia cruzada de mi blog original.
Puedes leer el articulo original con código coloreado y demás utilidades en
C# - Recibir notificaciones cuando hayan cambios de sesión parte 3 - WPF
------------------------
Artículos de este tema:
*Realmente son 6 articulos si contamos los mini post a los que se hace referencia
En artículos anteriores enseñe como crear una librería para interceptar las notificaciones generadas en el sistema cuando se hacen cambios de sesión y como utilizar esa librería en Windows Forms. En este artículo enseñare como hacer uso de ese componente en una aplicación para Windows Presentation Foundation - WPF.
LETS CODE!
Para Windows forms esta tarea es bastante sencilla e intuitiva, pero este no es el caso de WPF dadas las propias características de esta tecnología.
He creado una aplicacion WPF sencilla con un ListBox que se irá llenando a medida que lleguen notificaciones de cambios en las sesiones.
Para comenzar recibiendo notificaciones lo primero que se supone debemos hacer es registrar nuestra Ventana ya que eso dice en la documentación de msdn:
WTSRegisterSessionNotificationSession change notifications are sent in the form of a WM_WTSSESSION_CHANGE message. These notifications are sent only to the windows that have registered for them using this function.
Para el caso de WPF esto no es necesario ya que al parecer PresentationCore ya lo hace por nosotros.
Ya que por defecto ya estamos recibiendo las notificaciones de cambios en las sesiones, lo que debemos hacer es interceptar estos mensajes en el WndProc de manera muy similar a como lo hicimos con Windows Forms en el artículo anterior. Fácil, solo que... una ventana de WPF no expone el WndProc pequeño problema. :(
En resumen lo que debemos tener en cuenta para poder interceptar los mensajes desde WPF es:
- Obtener el manejador de la ventana, ya que lo necesitamos para el siguiente punto , y de paso también por default es inaccesible para WPF.
- Crear un Hook para el WndProc nativo, el cual es por default inaccesible desde WPF
- (No)Registrar la ventana para recibir notificaciones
- Modificar el comportamiento del WndProc
Obtener el manejador de la ventana
Como ya lo comente necesitamos el manejador para posteriormente crear un Hook al WndProc, en este mini artículo explico C# - Como obtener un manejador (handle) para una ventana de WPF , pero en resumen el código esta acá:
[csharp]
WindowInteropHelper interopHelper;
private void Window_Loaded(object sender, RoutedEventArgs e)
{
//Conseguir el Handle de la ventana
interopHelper = new WindowInteropHelper(this);
}[/csharp]
Crear un Hook para el nativo
Aunque ya estamos recibiendo las notificaciones lo cierto es que no estamos haciendo nada con ellas, para interceptarlas y comenzar a hacer algo es necesario usar el WndProc de la ventana WPF y capturar el mensaje de notificación que se envía desde el sistema de ventanas.
Como ya lo escribí arriba, el WndProc no esta disponible para una ventana WCF, para utilizarlo debemos obtener el manejador de la ventana, cosa que ya hicimos y crear un Hook al WndProc, en este artículo explico C# - Como usar el WndProc en una Ventana WPF , pero en resumen el código esta acá:
[csharp]
WindowInteropHelper interopHelper;
private void Window_Loaded(object sender, RoutedEventArgs e)
{
//Conseguir el Handle de la ventana
interopHelper = new WindowInteropHelper(this);
//Crear un hook al WndProc
HwndSource sourceWindow = HwndSource.FromHwnd(interopHelper.Handle);
sourceWindow.AddHook(WndProc);
}[/csharp]
Donde el parámetro WndProc es realmente un delegado a un método llamado intencionalmente así, como lo veremos más adelante.
Una vez creado el hook, debemos interceptar los mensajes del WndProc, revisamos la variable wParam del mensaje ya que esta nos da detalles adicionales acerca del evento que se ha generado. Para efectos de este ejemplo simplemente convierto ese valor a su equivalente en los enum de la librería creada en el articulo previo, y adiciono esa cadena al listbox para que básicamente nos vaya mostrando los mensajes que van llegando.
[csharp]
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg == W32HandleSessionChanges.WM_WTSSESSION_CHANGE)
{
var name = Enum.GetName(typeof(SessionNotificationMsg), (SessionNotificationMsg)wParam);
this.listBoxOne.Items.Add(name);
handled = true;
return (IntPtr)1;
}
return IntPtr.Zero;
}[/csharp]
NOTA IMPORTANTE
WPF por defecto nos permite recibir notificaciones de la sesión actual, si queremos recibir notificaciones de todas las sesiones debemos des registrar la ventana y luego registrarla nuevamente con el parámetro NOTIFY_FOR_ALL_SESSIONS, así:
[csharp]
//Conseguir el Handle de la ventana
interopHelper = new WindowInteropHelper(this);
//Des Registramos
W32HandleSessionChanges.WTSUnRegisterSessionNotification(interopHelper.Handle);
//Registramos la forma para recibir notificaciones
W32HandleSessionChanges.WTSRegisterSessionNotification(interopHelper.Handle, NotifyType.NOTIFY_FOR_ALL_SESSIONS);
[/csharp]
El resultado
Ejecutamos el programa

Bloquemos nuestra sesión de Windows, volvemos a ingresar y…

Perfecto!!
eso fue todo.
Esta es una copia cruzada de mi blog original.
Puedes leer el articulo original con código coloreado y demás utilidades en
C# – Recibir notificaciones cuando hayan cambios de sesión parte 2 – Windows Forms
----------------------
Artículos de este tema:
*Realmente son 6 articulos si contamos los mini post a los que se hace referencia
En mi artículo anterior enseñe como crear una librería para interceptar las notificaciones generadas en el sistema cuando se hacen cambios de sesión, en este artículo enseñare como hacer uso de ese componente en una aplicación para Windows Forms.
LETS CODE!
Divide y vencerás!, mi principio favorito. Seguiremos estos tres pasos:
- Registrar la ventana para recibir notificaciones
- Modificar el comportamiento del WndProc
- Des registrar la ventana para dejar de recibir notificaciones
He creado una aplicacion Windows Forms sencilla con un ListBox que se irá llenando a medida que lleguen notificaciones de cambios en las sesiones.
Registrar la ventana para recibir notificaciones
Para comenzar recibiendo notificaciones lo primero que debemos hacer es registrar nuestra Ventana, la Form, utilizando la API, para ello utilizamos la libreria que cree en C# - Recibir notificaciones cuando hayan cambios de sesión parte 1 simplemente usamos el evento load del form.
[csharp]
private void Form1_Load(object sender, EventArgs e)
{
//Registramos la forma para recibir notificaciones
W32HandleSessionChanges.WTSRegisterSessionNotification(this.Handle, NotifyType.NOTIFY_FOR_ALL_SESSIONS);
}
[/csharp]
Con esto nuestra ventana ya comienza a recibir notificaciones de cambios en las sesiones.
Modificar el comportamiento del WndProc
Aunque ya estamos recibiendo las notificaciones lo cierto es que no estamos haciendo nada con ellas, para interceptarlas y comenzar a hacer algo es necesario hacerle override al WndProc del form y capturar el mensaje de notificación que se envía desde el sistema de ventanas.
Una vez interceptado debemos revisar la propiedad wParam del mensaje ya que esta nos da detalles adicionales acerca del evento que se ha generado. Para efectos de este ejemplo simplemente convierto ese valor a su equivalente en los enum de la librería creada en el articulo previo, y adiciono esa cadena al listbox para que básicamente nos vaya mostrando los mensajes que van llegando.
En este caso paso como parámetro NOTIFY_FOR_ALL_SESSIONS para recibir notificaciones de cambios en todas las sesiones no solo en la actual
[csharp]
protected override void WndProc(ref Message m)
{
//Verificamos cuando el mensaje recibido sea el de cambios en la sesión
if (m.Msg == W32HandleSessionChanges.WM_WTSSESSION_CHANGE)
{
//convertimos el valor de wParam a su equivalente en nombre del enum
var name = Enum.GetName(typeof(SessionNotificationMsg), (SessionNotificationMsg)m.WParam);
this.listBox1.Items.Add(name);
}
base.WndProc(ref m);
}
[/csharp]
Des registrar la ventana para dejar de recibir notificaciones
Esta es la parte más fácil, antes de cerrar la ventana la des registramos:
[csharp]
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
//Des Registramos la forma para no recibir notificaciones
W32HandleSessionChanges.WTSUnRegisterSessionNotification(this.Handle);
}
[/csharp]
El resultado
Ejecutamos el programa

Bloquemos nuestra sesión de Windows, volvemos a ingresar y…

Perfecto!! 
En un próximo articulo veremos como hacer lo mismo con WPF.
Esta es una copia cruzada de mi blog original.
Puedes leer el articulo original con código coloreado y demás utilidades en
C# – Recibir notificaciones cuando hayan cambios de sesión parte 1
--------------
Artículos de este tema:
*Realmente son 6 articulos si contamos los mini post a los que se hace referencia
A veces necesitamos que nuestro software audite ciertos eventos generados por el equipo, como por ejemplo cuando se abren o cierran sesiones. Esto es importante por ejemplo para disparar procesos pesados cuando el computador no este en uso o para realizar procesos de auditoria.
Como es de suponerse el .Net Framework no trae nada que nos apoye en esa tarea ya que esta profundamente relacionada con el sistema operativo y ya que el CLR es multiplataforma este tipo de cosas no vienen soportadas. Se debe hacer uso de la Api de Windows.
En este artículo crearé una librería sencilla que permite ser notificado cuando suceden estos eventos bien sea en la sesión actual o a través de las diferentes sesiones iniciadas en el sistema.
NUESTRO KIT DE HERRAMIENTAS
Las cosas que necesitamos de la Api de Windows para realizar esta labor se describen a continuación
Funciones
Constantes para llamar a WTSRegisterSessionNotification
- NOTIFY_FOR_THIS_SESSION : Notifica eventos de la sesión actual
- NOTIFY_FOR_ALL_SESSIONS : Notifica eventos de todas las sesiones del sistema
Constantes relacionadas con las notificaciones
- WM_WTSSESSION_CHANGE : Mensaje generado cuando suceden los eventos de cambios en la sesión
- Parámetros:
- WTS_CONSOLE_CONNECT: Una sesión se ha conectado por terminal de consola.
- WTS_CONSOLE_DISCONNECT: Una sesión se ha desconectado por terminal de consola.
- WTS_REMOTE_CONNECT: Una sesión se ha conectado por una terminal remota.
- WTS_REMOTE_DISCONNECT: Una sesión de terminal remota se ha desconectado.
- WTS_SESSION_LOGON: Un usuario se ha logueado en la sesión.
- WTS_SESSION_LOGOFF: Un usuario se ha deslogueado de la sesión
- WTS_SESSION_LOCK: Una sesión se ha bloqueado.
- WTS_SESSION_UNLOCK: Una sesión se ha desbloqueado.
- WTS_SESSION_REMOTE_CONTROL: Una sesión ha cambiado su estado de control remoto. Par determinar el estado se debe hacer uso de GetSystemMetrics y revisar la métrica SM_REMOTECONTROL.
LETS CODE!
Preparando las funcionalidades de la Win32 API
Creamos una clase para centralizar los llamados a la API, allí con ayuda de DllImport importamos las funciones que requerimos y definimos todas las constantes necesarias, de preferencia agrupadas en enums:
Enums necesarias
[csharp]
/// Notificaciones a recibir
public enum NotifyType
{
/// Notificacion para la sesion actual
NOTIFY_FOR_THIS_SESSION = 0,
/// Notificacion para todas las sesiones del sistema
NOTIFY_FOR_ALL_SESSIONS = 1
}
/// Tipo de notificacion recibida
public enum SessionNotificationMsg
{
/// Una sesión se ha conectado por terminal de consola.
WTS_CONSOLE_CONNECT = 0x1,
/// Una sesión se ha desconectado por terminal de consola.
WTS_CONSOLE_DISCONNECT = 0x2,
/// Una sesión se ha conectado por una terminal remota.
WTS_REMOTE_CONNECT = 0x3,
/// Una sesión de terminal remota se ha desconectado.
WTS_REMOTE_DISCONNECT = 0x4,
/// Un usuario se ha logueado en la sesión.
WTS_SESSION_LOGON = 0x5,
/// Un usuario se ha deslogueado de la sesión.
WTS_SESSION_LOGOFF = 0x6,
/// Una sesión se ha bloqueado.
WTS_SESSION_LOCK = 0x7,
/// Una sesión se ha desbloqueado.
WTS_SESSION_UNLOCK = 0x8,
/// Una sesión ha cambiado su estado de control remoto. Par determinar el estado se debe hacer uso de GetSystemMetrics y revisar la métrica SM_REMOTECONTROL.
WTS_SESSION_REMOTE_CONTROL = 0x9
}
[/csharp]
Ahora la clase para manejar la W32API
[csharp]
using System;
using System.Runtime.InteropServices;
public static class W32HandleSessionChanges
{
///
/// Registra una ventana para recibir notificaciones de cambios en las sesiones
///
/// Manejador de la ventana
/// Modificadores
/// NOTIFY_FOR_THIS_SESSION, NOTIFY_FOR_ALL_SESSIONS
///
///
[DllImport("wtsapi32.dll", SetLastError = true)]
public static extern bool WTSRegisterSessionNotification(IntPtr hWnd, NotifyType dwFlags);
///
/// Des Registra una ventana que recibe notificaciones de cambios en las sesiones
///
/// Manejador de la ventana
///
[DllImport("wtsapi32.dll", SetLastError = true)]
public static extern bool WTSUnRegisterSessionNotification(IntPtr hWnd);
/// Mensaje recibido cuando hay cambios en las sesiones
public const int WM_WTSSESSION_CHANGE = 0x2b1;
}
[/csharp]
Para usarla basta con hacer uso del método W32HandleSessionChanges.WTSRegisterSessionNotification, el parámetro hWnd es el manejador de la ventana donde queremos recibir la notificaciones, esto nos permite registrar la ventana actual para recibir este tipo de mensajes, asi que una vez hecho esto se deben interceptar los mensajes para hacer lo que necesitemos. Una vez se valla a cerrar nuestro programa siempre es coveniente llamar a WTSUnRegisterSessionNotification
La librería que he creado se puede usar en diferentes tipos de aplicación para comenzar a recibir notificaciones, en próximos artículos les mostrare como utilizarla en Windows Forms y en WPF.
Esta es una copia cruzada del artículo escrito en el blog original:
C# – WPF – Escalar el tamaño de la fuente al cambiar el tamaño de la ventana o control
---------------------------------------------------------
Cambiar el tamaño de la fuente a medida que el control cambia de tamaño es una tarea frecuente, pero esta pobremente documentada, en este articulo esta la respuesta.
Este es uno de esos temas…
Puedes pasar horas buscando diferentes alternativas alrededor de la web, encontraras cosas como
- ViewBox
- FontSizeConverter
- IValueConverter
- etc.
Nada de eso funciona al menos no como se espera, aunque según el caso pueden dar una buena aproximación a la solución.
He escrito este artículo para ayudar a muchos desarrolladores (y diseñadores) a resolver este problema de manera definitiva.
Cómo realizar el cálculo de tamaño de fuente?
Dado que las fuentes, en su mayoría, son más altas que anchas es importante entonces que usemos como referencia la propiedad Height del control contenedor para definir el tamaño de la fuente con respecto a su dimensión más grande.
El alto de la fuente esta dictado por la medición de tres partes básicas:
- Ascendente
- Descendente
- Inicial
Observando esta gráfica es fácil hacerse una mejor idea:

La clase FontFamily en WPF posee la propiedad LineSpacing, la cual es ni más ni menos que el alto total de la fuente de acuerdo a los parámetros anteriormente citados.
Sin embargo esto no es todo, la propiedad LineSpacing es un valor genérico para la FontFamily sin importar el tamaño actual de la fuente utilizada, es decir este atributo nos da una relación proporcional respecto al tamaño de la fuente en unidades em.
Por ende podemos decir que el alto de una fuente en unidades em es
Alto = tamaño fuente * FontFamily.LineSpacing
Eso es correcto, pero nosotros no necesitamos calcular el alto de la fuente, sino calcular el tamaño de la fuente con respecto al Height del contenedor ( Button, Window etc), en ese caso la formula a utilizar sería:
tamaño fuente = Alto / FontFamily.LineSpacing
Implementación
Creamos una ventana de WPF con el siguiente código
1 2 3 4 5 6 7 8 9 10 | <Window x:Class="AutoScaleFont.MainWindow"
Title="MainWindow" Height="350" Width="525">
<DockPanel>
<Label HorizontalContentAlignment="Center" VerticalContentAlignment="Center"
SizeChanged="Control_SizeChanged">
Test</Label>
</DockPanel>
</Window>
|
En el archivo de código creamos el controlador para el evento SizeChanged
1 2 3 4 5 | private void Control_SizeChanged(object sender, SizeChangedEventArgs e)
{
Control tmp = sender as Control;
tmp.FontSize = e.NewSize.Height / tmp.FontFamily.LineSpacing;
}
|
El código se explica a si mismo, sin embargo haré una explicación breve. Establecemos la propiedad FontSize de acuerdo a la formula explicada más arriba tomamos el nuevo Alto del control y lo dividimos en la propiedad LineSpacing del FontFamily utilizado por el control.
Una optimización adicional es hacer que el alto de la fuente sea calculado con un valor levemente menor al del control contenedor para dejar un espacio de margen, con el ánimo de hacerlo proporcional le restamos solo un porcentaje respecto al alto total, en este caso el 5%, quedando así:
1 2 3 4 5 | private void Control_SizeChanged(object sender, SizeChangedEventArgs e)
{
Control tmp = sender as Control;
tmp.FontSize = (e.NewSize.Height - e.NewSize.Height * .05d) / tmp.FontFamily.LineSpacing;
}
|
Iniciemos la ejecución y revisemos el resultado:



Eso es justo lo que deseamos!
Si lo deseas puedes hacerlo respecto al ancho del control en lugar de respecto al alto, según sea tu necesidad, en ese caso debes ayudarte con la clase FormattedText y su propiedad Width para hallar el largo total en pixeles de la cadena.
Una semana agitada sin duda, negocios, aprendizaje, cambios en el trabajo, nuevas propuestas, mucho trasnocho… y enfermo.
Ha sido difícil. Sin embargo tengo una hermosa familia y muchas cosas positivas que lo compensan todo.
Así que las cosas son buenas, pero serían mejor.
Viernes 1 Abril 2011 09:12:17
Salía para una reunión, pero decidí ver el correo justo antes de salir, me lleve una agradable sorpresa

Inmerecido?
No lo se, de verdad no se que pensar, cada día que paso metido en temas tecnológicos me encuentro con gente grande, verdaderamente GRANDE, no solo en el sentido técnico sino también en su espíritu profesional, en su pasión y en su vida. No me puedo igualar con ninguno.
Han sido duras lecciones, seguramente muchos pasan eso en algún momento y supongo que, tristemente, no todos se logran dar cuenta de lo equivocados que estaban.
En el año 2003, o por esa época, solía creerme el super programador, el mejor en todo, sin duda era muy bueno en muchas cosas, era ‘un enorme genio’ frente a mi computador donde solo contaba Yo.
Así es fácil creerse un genio.
Con el tiempo la vida, como de costumbre, me ha dado duras lecciones, que considero me han hecho un mejor hombre y un mejor profesional.
Mis diferentes trabajos me fueron aterrizando, luego en 2007 me comencé a vincular con las comunidades y allí comenzaron a cambiar, de raíz, dos cosas:
- Ya no estaba frente al computador de mi casa, ahora estaba en una comunidad de muchas personas genio
- Ya no era un genio, me di cuenta que nunca lo fui.
Con el paso de los años he continuado aprendiendo cosas, técnicas y humanas, y también he conocido mucha gente, diferentes personas distribuidas geográficamente en lo que en otro momento llamábamos el enorme planeta tierra, hoy todos estamos a un clic de distancia.
Esta corta distancia me permitió descubrir a todos los verdaderos genios y talentos que hay allí justo a un clic de distancia de mí, cada semana o incluso cada día logro descubrir personas que son mucho mejores que yo, y que de una u otra forma, son mis maestros.
En mi opinión muchos o tal vez todos ellos merecen ser reconocidos como MVP, muchos ya lo son, pero he aprendido y tengo que aprender tantas cosas de ellos que bueno, a veces me pregunto si verdaderamente lo merezco.
Para ser reconocido como MVP he necesitado de muchas personas
Creo que no soy Juan Carlos Ruiz Microsoft MVP a secas.
Para lograr este reconocimiento he necesitado del apoyo de muchas personas, de mi equipo de amigos colaboradores de BogotaDotNet, de mi familia, de mis compañeros de trabajo, de mis followers en las redes sociales, de mis inspiradores y…
de mis detractores.
Mi nombramiento no es solo un reconocimiento para mí, sino es un reconocimiento para todos ustedes.
Soy Juan Carlos Ruiz Microsoft MVP porque cuento con personas como ustedes, alguien que "se cree un genio detrás del computador de su casa" no puede ser un MVP por si solo, mucho menos tres veces seguidas. He necesitado de su apoyo incondicional, de sus críticas, de sus ideas, de los espacios que me han brindado, de sus ganas de aprender, de sus ganas de enseñar, de su ejemplo y de su reconocimiento.
Gracias a todos por esta tercera vez y por todas las anteriores.
Esta es una copia cruzada del artículo escrito en el blog original:
MVP por tercer año consecutivo – no se como me aguantan
---------------------------------------------------------
Esta es una copia cruzada del artículo escrito en el blog original:
Porqué mis soluciones de SharePoint instaladas por PowerShell no se ven en la galería de soluciones?
---------------------------------------------------------
Interesante pregunta.
SharePoint 2010 posee una característica llamada Sandboxed Solution, estas soluciones son las instaladas por ‘el usuario final’ y estas quedan en una ‘capsula’ de seguridad que evita la ejecución de código malintencionado o dañino dentro de SharePoint. Solo las soluciones instaladas y creadas como Sandboxed Solution aparecen en la galería de soluciones del sitio, así mismo las características de estas soluciones solo son visibles si la solución es de tipo SandBoxed.
Por el contrario las soluciones ‘normales’ o avanzadas de SharePoint solo pueden ser instaladas a través de un Project setup o de comandos vía PowerShell, al ser soluciones no ‘de usuario’ estas son visibles únicamente desde el sitio de administración central de SharePoint 2010 y no es posible que un usuario las instale agregándolas a la galería de soluciones de su sitio, ya que sería alertado con que la solución no contiene un XML esperado… el XML de las Sanboxed Solutions.
Así las cosas si deseas que tu solución de SharePoint 2010 permita ser instalada tan solo agregándola a la galería de soluciones y que sus características sean habilitadas o deshabilitadas desde las pantallas del usuario, tendrás que crearlas como Sandboxed Solution, de lo contrario crea y desplega una solución normal.
Incluso si tu solución solo consta de WebParts la única forma de que SharePoint desempaquete todo el .wsp desde la UI de aplicación es que tu solución sea de tipo sandbox, de lo contrario debes hacer la instalación asistida por comandos de PowerShell.
Saludos,
Esta es una copia cruzada del artículo escrito en el blog original:
Como eliminar un .webpart de SharePoint 2010 que no se borra despues de desinstalar la solución via PowerShell
---------------------------------------------------------
Como lo comenté en un artículo anterior una vez se desinstala una solución que contiene un .webpart por alguna razón este .webpart persiste en la Galería de elementos web de SharePoint 2010, para borrarlo hay que utilizar un poco de ‘astucia’ de desarrollador utilizando PowerShell.
He creado este sencillo script de PowerShell el cual con solo indicar el url del sitio y el nombre del .webpart es capaz de encontrarlo y borrarlo.
Para mayor funcionalidad el nombre del .webpart lo he dejado como una cadena de expresiones regulares de tal forma que podamos hacer una selección más fléxible delos .webpart que deseamos remover.
Como todo, no es perfecto, es susceptible de mejora, una primera mejora sería hacerlo independiente del idioma ya que el nombre de la galería esta establecido por defecto en español pero cambia si utilizas la versión en inglés o en otro idioma.
Acá les dejo el script que sin lugar a dudas sacara de apuros a más de uno al rededor de la web.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.WebPartPages")
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Publishing")
$url = Read-Host "Ingrese el nombre del servidor"
$wps = Read-Host "Escriba el patrón del webpart"
$SPSite = New-Object Microsoft.SharePoint.SPSite($url)
$SPWeb = $SPSite.OpenWeb()
$WebPartGallery = $SPWeb.Lists["Galería de elementos web"]
$gall = $WebPartGallery.Items | select Name
$count = $gall.Count
$count
for ( $i =0; $i -lt $count;$i++)
{
Write-Host "Actual:" $gall[$i].Name
if ($gall[$i].Name -match $wps)
{
Write-Host "found"
$WebPartGallery.Items.Delete($i)
$SPWeb.Update()
Write-Host "$wp borrado"
}
}
$SPWeb.Dispose()
|
Un ejemplo de uso para eliminar el .webpart del que hablamos en este artículo “Como instalar una solución (.wsp) de SharePoint 2010 via PowerShell” es
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | .\borrarWebpart.ps1
GAC Version Location
--- ------- --------
True v2.0.50727 C:\Windows\assembly\GAC_MSIL\Microsoft.SharePoint\14.0.0.0__71e9bce111e9429c\Microsoft.SharePo...
Escriba el patrón del webpart: ^TestWeb.*$
11
Actual: MSContentEditor.dwp
Actual: MSPageViewer.dwp
Actual: MSImage.dwp
Actual: MSMembers.dwp
Actual: MSSimpleForm.dwp
Actual: MSUserDocs.dwp
Actual: MSUserTasks.dwp
Actual: MSXml.dwp
Actual: MSPictureLibrarySlideshow.webpart
Actual: Silverlight.webpart
Actual: TestWebPart_VisualWebPart1.webpart
found
borrado
|
Estoy imaginando muchas sonrrisas en este momento ! XD
Esta es una copia cruzada del artículo escrito en el blog original:
Como instalar una solución (.wsp) de SharePoint 2010 via PowerShell
---------------------------------------------------------
Hola, dado la poca documentación que existe en la web al respecto de este tema he decidido escribir este artículo que estoy seguro le será de mucha utilidad a todos ustedes.
Una vez generado el paquete desde Visual Studio 2010, abrimos una consola de administración de SharePoint, sobra decir que la debemos abrir con privilegios de administrador ( clic derecho, ejecutar como administrator ).
Inicia el trabajo, revisaremos primero la forma de realizar la instalación, seguidamente como hacer la desinstalación y finalmente un tip que les será útil a todos.
Instalación de la solución
La instalación se divide en 3 partes
- Subir la solución
- Instalarla
- Activar las características
Procedemos a ejecutar los siguientes pasos en la consola de administración de SharePoint 2010, como la instalación puede ser un proceso ‘incomodo’ entonces lo primero que realizaremos será crear tres variables, una de ellas para la ubicación del sitio, otra para el nombre de la solución y una última para el nombre de la característica.
En este ejemplo los valores para esas variables son:
- url del sitio esta en http://localhost
- nombre de la solución TestWebPart.wsp
- nombre de la única característica de la solución “TestWebPart Feature1″ o su id = “64C2C32C-064D-4216-BB63-6A67EFE828D1″
Así que los primeros comandos a ejecutar son para inicializar las variables
1 2 3 | $SolName="TestWebPart.wsp"
$FeaName="TestWebPart_Feature1"
|
1. Subir la solución
Cambiamos al directorio donde esta el archivo .wsp
seguidamente ejecutamos el siguiente comando, -LiteralPath nos pide el path completo del archivo .wsp, no importa si ya estamos en el directorio en todo caso debemos poner la ruta completa.
1 | Add-SPSolution -LiteralPath "C:\TestWebPart.wsp"
|
Esto nos debe generar la siguiente salida
1 2 3 | Name SolutionId Deployed
---- ---------- --------
testwebpart.wsp 2361bfd2-d113-4f4d-8941-cfdb66edb891 False
|
2. Instalar la solución
Una vez hemos subido la solución al servidor procedemos a instalarla así
1 | Install-SPSolution -Identity $SolName -WebApplication $SiteUrl -GACDeployment
|
Si el comando fue exitoso no hay ningún feedback por consola.
3. Activación de las características de la solución
La solución ya está instalada así que ahora debemos activar las características que hemos incluido. Si hemos desarrollado un Webpart desde Visual Studio 2010 este crea automáticamente una característica, podemos instalarla haciendo uso de su nombre o de is en caso de que lo hayas generado
Tip: si el nombre de la característica tiene espacios, deberás reemplazarlos por el carácter ‘_’ (línea al piso)
1 | Install-SPSolution -Identity $SolName -WebApplication $SiteUrl -GACDeployment
|
Si el comando fue exitoso no hay ningún feedback por consola.
Con eso finalizamos la parte de la instalación, así que vamos a SharePoint y verificamos.
En este caso estamos instalando un webpart así que vamos a Acciones del sitio, Configuración, Elementos web y allí debes encontrar el webpart que acabamos de instalar.

Desinstalación de la solución
Esta parte es básicamente lo mismo pero al revez, si, así de fácil.
- Desactivar las características
- Desinstalar la solución
- Remover la solución
1. Desactivar las características
1 | Disable-SPFeature -Identity $FeaName -Url $SiteURL -Confirm:$false
|
Si es exitoso no hay respuesta
3. Remover la solución
Este comando no sirve pada nada. Así es lo tenemos que ejecutar pero no hace lo que se supone que debe hacer, o mejor, lo hace a medias…
1 | Remove-SPSolution -Identity $SolName -Confirm:$false
|
Si es exitoso no hay respuesta.
Sin embargo si revisamos nuestro webpart aún aparece solo que no se puede usar para nada. Se supone que precisamente este comando lo remueve, pero realmente remueve la solución pero no todos sus componentes, de seguro un bug.
En un próximo artículo les mostraré como eliminar por completo el rastro del webpart que no desapareció.
Más artículos
Página siguiente >