Nuevo hangout el próximo 10 de febrero: Experiencias del mundo real con Xamarin

Actualización: Aquí tienes el vídeo del evento:

Vuelven los hangouts en 2015! Tras el parón de navidades y la cuesta de enero volvemos con desarrollo móvil usando C# en otras plataforma no Microsoft. Veremos de primera mano algunas experiencias que han tenido nuestso invitados con proyectos y aplicaciones reales.

Además tenemos la suerte de contar no con uno, sino con dos miembros del equipo de desarrollo de Xamarin para darnos su visión desde el otro lado. Dos horas que seguro que se nos quedan cortas.

La cita es el próximo 10 de febrero a las 20:00 GMT+1 en Google Hangouts: https://plus.google.com/events/c8ojlcgbi8gtsseulj331hpu5eo.

Desarrollo móvil multiplataforma con Xamarin

Contamos con el siguiente panel para el debate:

  • Jose Miguel Torres: Desarrollador en Xamarin
  • Rodrigo Moya: Desarrollador en Xamarin y colaborador del proyecto Gnome
  • Francesc Jaumot: Desarrollador y CEO en Clibb
  • Josue Yeray: Desarrollador independiente y MVP de Microsoft
  • Javier Suarez: Desarrollador independiente y MVP de Microsoft
  • Juan Carlos Quijano: Desarrollador independiente
  • Un servidor, que no se pierde una

En esta ocasión nos acompaña una vez más Syncfusion, así que si vienes puedes llevarte una licencia de uno de sus productos de manera completamente gratuita.
Te esperamos allí!

Si no puedes asistir lo dejaremos grabado en cuanto finalice el evento.

Cómo empezar a jugar YA con lo presentado en #VSConnect

En el evento Connect de hoy, Microsoft nos ha presentado un montón de novedades, y muchas de ellas están disponibles desde este mismo momento para poder empezar a aprender con juguetes nuevos.

Microsoft <3 Open Source

Así lo han dejado ver poniendo a la disposición las Core Libraries de .NET (lo que convierte a .NET en un proyecto Open Source) sumándose a otros proyectos como Entity Framework, SignalR o ASP.net, que ya estaban alojados en Github.

microsoft-github

Visual Studio 2015 preview ya disponible, también en Azure

Visual Studio 2015 Preview incorpora soporte para todo lo que hemos podido ver en las diferentes demos. Podemos descargarlo e instalarlo en nuestro ordenador, o bien podemos recurrir a Azure, donde tendremos una máquina virtual con la última versión para que con solo unos minutos tengamos un entorno completo:

vs2015

Visual Studio 2013 Update 4

La nueva actualización de Visual Studio 2013 (y posiblemente la última antes de la versión 2015) incluye mejoras en los editores así como el soporte para Apache Cordova:

Visual Studio Community Edition – Gratis

Esta versión, que incluye lo mejor de la edición Profesional (como el uso de plugins, o la posibilidad de tener diferentes tipos de proyecto en una única solución, algo que no estaba disponible en la edición express) está destinada para desarrolladores independientes, colaboradores de proyectos Open Source, así como pequeñas empresas:

Pluralsight para suscriptores MSDN

Una cosa más! Pluralsight ha anunciado, con motivo de este evento, la disponibilidad de una parte de su colección de vídeos de manera gratuita para suscriptores MSDN.

Más información

vNext

Estas herramientas y algunas más las podremos ver en el hangout que estamos organizando para el próximo 19 de noviembre (dentro de apenas una semana). Apúntate aquí

Resumen de atajos de teclado de Visual Studio

Una de las sesiones que me resultaron más interesantes en el pasado TechEd 2014 fue la de Tips and Tricks de Visual Studio con Tarek Madkur.

En ella, comentaba un montón de atajos de teclado que nos proporciona Visual Studio para mejorar nuestra productividad. En este artículo resumo brevemente las que más me han llamado la atención:

Ctrl + Q: Quick Launch

Este menú nos permite acceder, desde el teclado, a todas las ventanas auxiliares, opciones de configuración y elementos del menú del IDE. Ventanas como por ejemplo el «Package Manager Console» de Nuget, o ventanas como el Test Explorer, sin tener que estar buceando por las opciones del IDE.

Ctrl + K, X: Insertar snippet

Una herramienta muy útil cuando queremos reutilizar trozos de código llamados snipets. Este atajo nos muestra la lista de snipets instalados en nuestro sistema, y nos permite insertarlos de manera inmediata.

Alt + Shift + Enter: Pantalla completa

La pantalla completa es una vista que nos permite centrarnos en una (o varias) secciones de código, o cuando queremos mostrar código a alguien (por ejemplo, en una charla).

Ctrl + F4: Cerrar documento

Nos permite cerrar los documentos abiertos dentro del entorno de visual studio.

Shift + Esc: Ocultar ventanas

Nos permite cerrar otras ventanas como Output o Search Results, sin que ello afecte al layout actual.

Ctrl + Alt + O: Convertir en documento normal

Convierte un documento cargado en modo «preview» (el que se activa cuando hacemos click en un documento o cuando estamos navegando usando F12) en un documento normal.

Alt + F12: Peak navigation

El comando F12 nos permite navegar a la definición de un método o una clase, pero podemos perder el contexto, así que con esta opción podemos mantener el contexto y poder navegar a la definición. Lo más curioso es que podemos, dentro del menú de Peak navigation, continuar navegando

Extra! Más atajos de teclado!

El ilustre Gorka Madariaga (@Gk_8) aporta estos tres atajos:

Ctrl+C

En una linea sin seleccionar nada te la copia entera, idem para Ctrl+X o Ctrl+V (te la pega completa en la linea de arriba).

Ctrl+K, C

Comenta la linea en la que estas entera si no seleccionas nada o lo que tengas seleccionado, Ctrl+K, U hace lo inverso del anterior.

Ctrl+K, D

Para dar formato a todo el archivo o a lo que tengas seleccionado.

Conclusiones

Esta es una lista bastante corta de atajos de teclado, Visual Studio cuenta con una opción en el menú para poder listar todos los atajos, las opciones a las que están asignados, y asignarnos nuestros propios atajos (Por ejemplo, yo tengo configurado Ctrl + < para ejecutar mis test de Javascript)

Más información

Si quieres ver estas y más, te recomiendo la charla de Tarek Madkour en el TechEd 2014: https://channel9.msdn.com/Events/TechEd/Europe/2014/DEV-B348

Vídeo: Lo que viene con C# 6

En este evento tuvimos la ocasión de juntarnos varios entusiastas de tecnologías Microsoft para comentar lo que viene con la nueva versión de C# y Visual Studio 14, así como las novedades a nivel de compilador con Roslyn. Además tuvimos la posibilidad de contar con Syncfusion como patrocinador estrella, que ofreció una licencia de su producto Essential Studio Enterprise Edition a un asistente.

Tras una introducción a cómo poner a punto un Visual Studio 14 para empezar a jugar por parte de Juan Quijano (@jc_quijano) usando las máquinas virtuales de Azure, el ilustre Eduard Tomás (@eiximenis) y un servidor nos metíamos en harina para repasar algunas de las características que trae esta nueva versión del lenguaje.

Entre las novedades destacan la propagación de nulos, los constructores principales, o la inicialización de variables dentro de bloques, y por otro lado, de manera un tanto negativa también para los asistentes, de la importación de métodos de clases estáticas.

En el segundo bloque, de mano de Juan Manuel Servera (@jmservera) vimos cómo podemos extender las capacidades de Visual Studio a través de Roslyn, para agregar más capas o reglas a nuestro propio código, ofreciendo además la posibilidad de dar sugerencias a los desarrolladores, y todo esto en un paquete nuget que puede formar parte de nuestro código fuente.

Se avecinan tiempos muy interesantes en el desarrollo de IDEs.

Antes de terminar, no quería dejar de compartir algunas estadísticas del evento:

  • 10 +1s en la página del evento
  • 24 asistentes de máxima
  • 32 personas han visto el evento, de acuerdo con su estatus en la página de Google Plus.
  • 85 tweets (incluyendo retweets) con el hashtag #vienecsharp6, «oficial» del evento, de acuerdo con las estadísticas de Topsy
  • 108 visitas a la página del evento, de acuerdo con las estadísticas de Karmacracy.
  • 124 visualizaciones del vídeo en Youtube en este momento.

Finalmente, en el vídeo comentamos algunos enlaces que se muestran a continuación:

Muchas gracias a los ponentes por hacer el evento posible, a nuestro patrocinador por el apoyo y finalmente a todos los asistentes.

Kata UpperCounter con Software Craftsmanship Madrid

El pasado martes 5 de agosto tuve la oportunidad de acudir a mi primer meetup de Software Craftsmanship Madrid, en el que se celebaba un coding dojo facilitado por Carlos Ble @carlosble. El objetivo de la sesión era hacer uso de un patrón diseñado por Robert «Uncle Bob» Martin llamado «Transformation Priority Premise» que nos lleva a una programación más genérica y funcional.

Tras sentarnos por parejas y escoger el entorno y el lenguaje de programación (En mi caso, C# con Visual Studio 2013 y XUnit como motor de pruebas) se desveló el objetivo de la kata:

Dada una cadena, devolver, en forma de array, las posiciones de dicha cadena cuyos caracteres sean la letra mayúscula

Ejemplos:
– A: {0}
– bA: {1}
– aBcdE: {1, 4}

Primera iteración, sin restricciones

Para esta primera iteración no teníamos ninguna limitación más allá de intentar resolver la kata. El resultado es el que se muestra en el vídeo:

El código completo, tanto del test como de la implementación se puede ver a continuación:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Sample
{
public class UppercaseSearcher
{
internal int[] Search(string source)
{
var result = new List<int>();
if (source.Length > 0)
{
for (int i = 0; i < source.Length; i++)
{
var current = source[i];
if (char.IsUpper(source, i))
{
result.Add(i);
}
}
}
return result.ToArray();
}
private bool IsUpperCase(char current)
{
return current.ToString().ToUpper()
== current.ToString();
}
}
}

view raw

Source.cs

hosted with ❤ by GitHub


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xunit;
using Xunit.Extensions;
namespace Sample
{
public class Test
{
[Fact]
public void ShouldReturnEmptyArrayIfEmptyString()
{
//Arrange
var source = "";
var searcher = new UppercaseSearcher();
//Act
var result = searcher.Search(source);
//Assert
Assert.Empty(result);
}
[Fact]
public void ShouldReturnValidUppercaseLocation()
{
//Arrange
var source = "A";
var searcher = new UppercaseSearcher();
//Act
var result = searcher.Search(source);
//Assert
Assert.Equal(1, result.Length);
Assert.Equal(0, result[0]);
}
[Fact]
public void ShouldReturnValidUppercaseInSecondPlace()
{
//Arrange
var source = "bA";
var searcher = new UppercaseSearcher();
var expected = new int[] { 1 };
//Act
var result = searcher.Search(source);
//Assert
Assert.Equal(expected, result);
}
[Theory]
[InlineData("A", new int[] { 0 })]
[InlineData("bA", new int[] { 1 })]
[InlineData("bbAab", new int[] { 2 })]
[InlineData("babC", new int[] { 3 })]
//Multiple uppercases
[InlineData("bCbC", new int[] {1,3})]
//No uppercase
[InlineData("qwerty", new int[] { })]
public void ShouldBeValidInDifferentSituations(string source, int[] expected)
{
//Arrange
var searcher = new UppercaseSearcher();
//Act
var result = searcher.Search(source);
//Assert
Assert.Equal(expected, result);
}
}
}

view raw

Test.cs

hosted with ❤ by GitHub

El enfoque es iterativo, utilizando un bucle para recorrer los caracteres de la cadena y la comprobación es bastante artesanal (a mejorar en la segunda iteración) y además, como teníamos tiempo, pudimos probar las Theories de XUnit, que nos permiten utilizar, en el mismo test, diferentes conjuntos de entrada y esperar diferentes resultados.

Segunda iteración, con restricciones

En esta segunda iteración teníamos una limitación importante: No podíamos asignar variables, ni modificar valores existentes. Esto nos deja sin la posibilidad de usar bucles (ya que vamos actualizando la posición del iterador) y forzando nuestro código a que sea más funcional. El resultado es el que se muestra:

El código completo es el siguiente, con el que intentamos seguir a rajatabla la indicación de no asignar o modificar los valores de las variables. En este caso el tiempo no permitió pasar de unos pocos test, pero se aprecia una diferencia notable por una parte en el test y por otra en el código de implementación:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Sample.WithLimits
{
class UppercaseSearcher
{
internal static int[] Search(string source)
{
return Search(source, 0);
}
internal static int[] Search(string source, int index)
{
if (IsOutOfBounds(source, index))
{
return new int[0];
}
if (char.IsUpper(source, index))
{
return new int[] { index }
.Concat(Search(source, index + 1))
.ToArray();
}
else
{
return Search(source, index + 1)
.ToArray();
}
}
private static bool IsOutOfBounds(string source, int index)
{
return source.Length == 0 || index >= source.Length;
}
}
}

view raw

Searcher.cs

hosted with ❤ by GitHub


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xunit;
namespace Sample.WithLimits
{
public class TestClass
{
[Fact]
public void ShouldReturnEmptyArray()
{
//Arrange, act, assert
Assert.Equal(new int[0], UppercaseSearcher.Search(""));
}
[Fact]
public void ShouldReturn0IfOneLetterIsUppercase()
{
//Arrange, act, assert
Assert.Equal(new int[] {0}, UppercaseSearcher.Search("A"));
}
[Fact]
public void ShouldReturn1IfSecondLetterIsUppercase()
{
//Arrange, act, assert
Assert.Equal(new int[] { 1 }, UppercaseSearcher.Search("bA"));
}
}
}

view raw

Test.cs

hosted with ❤ by GitHub

Como nota adicional, gracias a @DanielRoz0 que me ha estado ayudando con la edición del vídeo, se pudo simplificar la comparación de una letra con su correspondiente mayúscula mediante el uso de la función char.IsUpper(source, index).

Información y enlaces:

Preparando el examen 70-484

El pasado 30 de mayo aprobé el examen 70-484 de desarrollo de aplicaciones para Windows 8 con C#, lo que me acerca un paso más al MCPD en desarrollo de apps para la plataforma, y es a su vez una excusa y un reto para aprender más de la misma.

Al comentarlo por Twitter, algunos desarrolladores me preguntaron qué recursos había usado, y aquí va un pequeño resumen.

Continuar leyendo «Preparando el examen 70-484»

Y esto son las Interactive Rooms

En las últimas semanas he estado trabajando junto con el resto del equipo de VS Anywhere en una funcionalidad completamente nueva para nuestro Web Workspace, que hemos denominado Interactive Rooms.

Con ella, y aprovechando la recientemente presentada API de Visual Studio Online, podemos iniciar sesiones de colaboración directamente desde el navegador conectados con un repositorio Git o TFSVC, algo que, hasta ahora, resultaba imposible.

En este artículo veremos qué tecnologías y servicios hemos empleado para poder hacer posible este producto.

Obteniendo la información de Visual Studio Online

La API REST de Visual Studio Online, presentada en el pasado TechEd, permite acceder a la información de los ficheros almacenados en un repositorio, para poder comenzar una sesión en un punto específico de la historia del proyecto. Entre la información a la que podemos acceder están:

  • Team projects del portal de Visual Studio
  • Commits de un team project específico
  • Estado del repositorio en un commit específico, es decir, acceso a los ficheros.
  • Acceso a la Team Room del Team Project, para poder emitir mensajes.

Con esto, mostramos esta pantalla para que el usuario seleccione los datos antes de comenzar la sesión:

session

La autenticación está basada en OAuth2, lo que permite, una vez autorizado, poder realizar llamadas a la API sin tener que solicitar el usuario y la contraseña una y otra vez. El funcionamiento de OAuth va asociado a dos tokens, de autorización y de refresco, para asegurar la integridad de la cuenta en caso de que alguno de ellos se vea comprometido.

connectToVSO

Estos tokens, en nuestro caso, se asocian a la cuenta de usuario de VS Anywhere.

Almacenamiento y caché

Cuando creamos una sesión guardamos un snapshot de esta primera versión, que no contiene cambios. Esta snapshot se almacena dentro de Windows Azure Storage, concretamente dentro de un blob, que tiene esta estructura:

  • 123456789
    • 123456789000
    • 235123789021
    • 563473568561

Si accedemos desde el Azure Storage Explorer podemos ver qué se está almacenando:

blobs

Esta estructura de árbol nos permite obtener el histórico de una sesión y poder agregar nuevos items usando los ticks como clave. De esta manera podemos mostrar la fecha de creación sin necesidad de acceder al contenido del blob.

El resto de información almacenada (serializada como JSON) está relacionada con el tipo de autenticación, el team project, el commit o la lista de ficheros que se ha usado para poder re-crear la sesión en el futuro.

Para mantener una caché de sesiones activas usamos Redis, que nos permite un almacenamiento clave-valor con un acceso increíblemente rápido.

Descargando los datos

De la misma manera que podemos crear un snapshot, también podemos descargar el estado actual del proyecto, para integrarlo en nuestro workspace de git o TFS local, descargando un fichero que contiene solamente los documentos abiertos y los editados, siendo el resultado el que se muestra:

download

El fichero .zip se genera sobre la marcha, usando la información actual de la sesión y las opciones de compresión de .net 4.5 (ver más en MSDN).

Conclusiones

Mediante el uso de Azure Storage, Redis, y las API de Visual Studio Online hemos podido crear una funcionalidad adicional que complementa, por una parte el Web Workspace, y por otra el propio Visual Studio Online, dando nuevas opciones de colaboración.

La API, aún en estado beta, está bastante avanzada y productos como UserVoice o Zapier la están integrando dentro de sus propias soluciones.

¿Cómo empiezo?

Para poder empezar a usar las Interactive Rooms, solamente necesitas VS Anywhere 3.0.0.157 y una cuenta en Visual Studio Online. Puedes comenzar desde el propio Visual Studio siempre que:

  • Estés conectado a Visual Studio Online
  • El proyecto sea C# y esté en control de versiones
  • El team project esté conectado a visualstudio.com

Si se cumplen esos dos requisitos, las opciones se mostrarán al hacer click derecho sobre un proyecto:

options

Información y registro

Puedes encontrar más información (y registrarte) en la web de Interactive Rooms

Charla desarrollo Windows 8 en Valencia: Slides y código de ejemplo

El pasado 4 de abril tuve la oportunidad de volver a Valencia por tercera vez consecutiva para charlar con los alumnos de la’Escola Tècnica Superior d’Enginyeria (ETSE) sobre desarrollo de aplicaciones móviles en general, y en aplicaciones para Windows 8 y Windows 8 en particular.

Durante algo más de una hora estuvimos intentando dar respuesta a las siguientes preguntas:

  • ¿Merece la pena meterse en el mundo de desarrollo para aplicaciones móviles?
  • ¿Cuanto cuesta comenzar?
  • ¿Qué son los live tiles?
  • ¿Cómo integrarnos con el sistema operativo?
  • ¿Qué opciones de publicación tenemos?
  • Y muchas más.

Para ello, estuvimos desarrollando una pequeña aplicación con las siguientes características:

  • Cliente REST para consumir la API de datos de youtube.
  • Múltiples pantallas para poder ver detalles sobre un vídeo concreto
  • Posibilidad de cargar datos desde disco, usando el File Picker
  • Preferencias integradas en el cuadro de diálogo «Settings».
  • Posibilidad de compartir con otras aplicaciones a través del Share contract

El código fuente de ejemplo está disponible aquí: https://app.box.com/s/d5d6iot8y6v5ankz5kfy

Finalmente, la presentación se encuentra disponible en slideshare

Happy hacking!

Transformando web.config (o app.config) para depuración

Una de las características más interesantes de los ficheros web.config, es que al publicarlos podemos aplicar una serie de transformaciones a los mismos, de tal manera que ciertos datos que estén en depuración no lleguen en modo release, y viceversa.

Sin embargo, hay casos en los que nos puede ser útil tener varios ficheros config para las diferentes configuraciones de build. En mi caso, desarrollando RealPoll, me di cuenta que esto podría ser interesante, y he creado tres configuraciones:

  • Debug_FakeDB
  • Debug_LocalDB
  • Debug_RemoteDB

Para cada una de las opciones tengo un fichero web.config diferente. El problema es que la transformación solamente se aplica al publicar, y no en el proceso de depuración, por lo tanto son poco útiles estos perfiles. Sin embargo, buscando un poco en internet encontré este artículo en CodeProject en cuyos comentarios estaba la respuesta a mi problema, modificar (a mano) el fichero csproj y agregar la siguiente directiva tras la compilación (tenemos un ejemplo comentado al final de nuestro proyecto):

<Target Name="AfterBuild">
   <TransformXml Source="Web.Base.config" Transform="Web.$(Configuration).config" Destination="Web.config" StackTrace="true" />
 </Target>

Una vez agregada, deberemos entonces duplicar la información de nuestro web.config (o app.config si desarrollamos una aplicación de escritorio) en un fichero llamado web.base.config (por ejemplo), ya que tras cada compilación el fichero web.config se regenerará.

Dentro de cada fichero de configuración, tenemos diferentes opciones. En el caso de debug_fakedb se agrega una clave a appsettings, que luego consulto al inicializar mi código:

<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
  <appSettings>
    <add xdt:Transform="Insert" key="FakeDB" value="true" />
  </appSettings>
</configuration>

Esta clave luego la consulto a la hora de inicializar el código:

if (string.IsNullOrEmpty(ConfigurationManager.AppSettings["FakeDB"]) == false)
    Current.Bind<IQuestionRepository>().To<FakeQuestionRepository>();

else
    Current.Bind<IQuestionRepository>().To<DBQuestionRepository>();

Lo bueno de dejar estos valores en claves de configuración es que nos permite hacer cambios «en caliente» sin tener que recompilar la aplicación, como bien recomendaban Andy Hunt y Dave Thomas en su «Pragmatic Programmer».

En el caso de localDB agregamos la información de Entity Framework (que ya sabrá que hacer):

<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
  <entityFramework xdt:Transform="Insert">
    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
      <parameters>
        <parameter value="v11.0" />
      </parameters>
    </defaultConnectionFactory>
  </entityFramework>
</configuration>

Finalmente, para el caso de remoteDB, agregamos la información de Entity Framework, así como la cadena de conexión (que más adelante se sustituye en azure):

<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
  <connectionStrings xdt:Transform="Insert">
      <add name="QuestionContext"
           connectionString="YOUR_CONNECTION_STRING_HERE"
           providerName="System.Data.SqlClient" />
  </connectionStrings>
  <entityFramework xdt:Transform="Insert">
    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework"/>
    <providers>
      <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
    </providers>
  </entityFramework>
</configuration>

Para mí supone un ahorro considerable de tiempo y esfuerzo, además de que me permite probar las diferentes configuraciones sin recompilar.

Si quieres verlo en ejecución, echa un vistazo al código de Realpoll en github del que hablaré muy, muy pronto.

Moving windows programatically with Windows API, the path to WinResize

When we test VS Anywhere in a production environment, one of the things that we tend to do is to open 2 sessions of Visual Studio on either side of the screen, so we can make quick tests of specific features.

goal

This requires opening 2 different instances of visual studio by hand, and attach each side of the screen, something tedious, boring, and, above all, automatable. So I set out to find the way of solving this small issue.

The path

If we have Windows 7 or higher we can make use of Aero Snap, using Win+Left or Win+Right, it sets a window to the left or to the right of the screen. It seemed simple, I would only need to emulate this key combination, something that it seemed easy to do:

Theorically, we can solve this by using Powershell. In fact, in the following entry of TechNet Provide Input to Applications with PowerShell explains how to send commands to an application using SendKeys, resulting in the following code:

add-type -AssemblyName microsoft.VisualBasic
add-type -AssemblyName System.Windows.Forms
Calc
start-sleep -Milliseconds 500
[Microsoft.VisualBasic.Interaction]::AppActivate("Calc")
[System.Windows.Forms.SendKeys]::SendWait("1{ADD}1=")

According to the last line, we should be able to send to the program any combination of keys, so the next step was to find the Windows key in the SendKeys reference: http://msdn.microsoft.com/en-us/library/system.windows.forms.sendkeys.send(v=vs.110) .aspx

Surprise: is not there. On the other hand, looking a bit online, I found that the Windows keystroke could be simulated by using the Ctrl + Esc.

Second surprise:  IT SIMULATES the WINDOWS key, and nothing else. When you press that combination, It jumps right to the desktop or to the start menu, it is not possible to use it to simulate a key combination involving Win + whatever, so that by this way little more we can do.

On the other hand, if what we are doing is a keyboard shortcut, surely matches some kind of command available on the Windows API that makes the action of Aero Snap, but no, there is no API, no documentation and there is no reference except the brand name, so this is another dead end.

There was still another option, which was to move the window directly using a custom program, after some search I found this piece of code, allowing you to do what I wanted using Powershell:


# Win7 Powershell script to resize Minecraft to 1280×720 (HD for fraps youtube capture)
# use by typing the following at a command prompt:
# > PowerShell -ExecutionPolicy Bypass -File minecraft-sethd.ps1
# refs:
# http://stackoverflow.com/questions/2556872/how-to-set-foreground-window-from-powershell-event-subscriber-action
# http://richardspowershellblog.wordpress.com/2011/07/23/moving-windows/
# http://www.suite101.com/content/client-area-size-with-movewindow-a17846
Add-Type @"
using System;
using System.Runtime.InteropServices;
public class Win32 {
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetClientRect(IntPtr hWnd, out RECT lpRect);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
}
public struct RECT
{
public int Left; // x position of upper-left corner
public int Top; // y position of upper-left corner
public int Right; // x position of lower-right corner
public int Bottom; // y position of lower-right corner
}
"@
$rcWindow = New-Object RECT
$rcClient = New-Object RECT
$h = (Get-Process | where {$_.MainWindowTitle -eq "minecraft"}).MainWindowHandle
[Win32]::GetWindowRect($h,[ref]$rcWindow)
[Win32]::GetClientRect($h,[ref]$rcClient)
$width = 1280
$height = 720
$dx = ($rcWindow.Right – $rcWindow.Left) – $rcClient.Right
$dy = ($rcWindow.Bottom – $rcWindow.Top) – $rcClient.Bottom
[Win32]::MoveWindow($h, $rct.Left, $rct.Top, $width + $dx, $height + $dy, $true )

It was not too complex, but I chose to do a small application with C# so that it could solve the problem, using native calls to the Windows API through P/Invoke:

Importing functions and moving windows

To use the Windows API functions we have to copy their header in our function, define it as external (.NET framework will already know what to do) and define the DLL from which we import, in this case the function MoveWindow is located in user32.dll:

[DllImport ("user32.dll")]
public static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);

We will have to repeat this process for each function that we want to import, a we will also need to add the following using:

using System.Runtime.InteropServices;

To be able to move the window, we need its hWnd, which is a unique window identifier. There are many ways to locate it, and one of them is from the list of processes, selecting those whose main window matched with what was looking for, in this case “Visual Studio”.

foreach (Process proc in Process.GetProcesses ()
{
    if (proc.MainWindowTitle.Contains ("Visual Studio"))
    {
        IntPtr handle = proc.P:System.Diagnostics.process.MainWindowHandle;
        ...
        MoveWindow(handle...);
        ...
    }
}

For moving the window, we need to set an origin and a size, and for this we could either fix them manually, or rely on the resolution of the screen, using the following functions:

Screen.PrimaryScreen.WorkingArea.Width;
Screen.PrimaryScreen.WorkingArea.Height;

These are found within the namespace System.Windows.Forms, which requires in addition a reference as System.Drawing from our project.

The really interesting thing about this, is that it allows us to move the window to the position we would like with any size, so we can take advantage of it in order to set any number of windows, being these equally distributed.

Finally we need a couple of additional calls to Windows API functions to maximize the window before moving it, and to set the focus, which are imported in a similar way:

[DllImport ("user32.dll")]
public static extern bool ShowWindow(IntPtr hWnd, int X);
[DllImport ("user32.dll")]
public static extern bool SetFocus(IntPtr hWnd);

Launching applications and input parameters

In addition to the functionality of moving windows, it could be interesting to launch the apps we want to move, so a bit of extra code to generate a process, to set the name of the file, and, after launching it, a small sleep while loading:

Process p = new Process();
p.StartInfo.FileName = "notepad.exe";
p.Start ();
System.Threading.Thread.Sleep (2000);

To make it simpler, the last step is to convert all the parameters used to input arguments of the program, being finally the project a console application, which gets, in this order;

  • Path of the executable
  • Title of the window to search
  • Number of processes to launch
  • Waiting for each process

In the case of a 3 windows launch for notepad.exe, this is the output showing the console application:

WinResize

On the other hand we have 3 windows, equally distributed:

Result

As the last detail, the window title is set using the following code block:

Console.Title = "WinResize";

Wrapping up

This is a small app that solves a very specific scenario can be widely improved and I’ll probably work for some more time on it, here are some ideas for future improvements:

  • Make all the script in powershell, it’s possible, and we can make P/Invoke without problems
  • Emulate the keypress (must be a code associated with the windows key, and a way to press it!) simulating the keyboard.
  • Rather than take all processes available, use the ID of those we’ve just created.

The code is available for free and licensed under open source. If you want to contribute please send your pull request :)

Enjoy!

Additional links