Category: Microsoft .NET

  • Schemalagda meddelanden i Akka .NET

    Schemalagda meddelanden i Akka .NET

    Denna gång tänker jag använda en Windows Forms Application för att visa schemaläggaren i Akka .NET. Som vanligt, för att komma åt Akka .NET i ditt projekt, växla till fönstret Package Manager Console och skriv Install-Package Akka. Om du inte ser Package Manager Console, klicka på rullgardinsmenyn Tools, välj Library Package Manager och Package Manager Console.

    Programmet består av följande meddelandeklass:

    public class TimedMessage
    {
       public string Message { get; private set; }
       public TimedMessage(string message)
       {
          this.Message = message;
       }
    }

    …och följande aktör:

    public class Listen : ReceiveActor
    {
       public Listen()
       {
          this.Receive<TimedMessage>(x =>
          {
             System.Diagnostics.Debug.WriteLine(x.Message);
          });
       }
    }

    Huvudfönstret har läst in namnrymden Akka.Actor för att några extension methods ska vara tillgängliga…

    using Akka.Actor;

    …och innehåller en knapp som heter button1. I formulärets Load-event skapas aktörssystemet och aktören och under knappen så skickar jag ett meddelande (TimedMessage) till aktören.

    public partial class Form1 : Form
    {
       private ActorSystem actorSystem;
       private IActorRef listen;
    
       public Form1()
       {
          InitializeComponent();
       }
    
       private void button1_Click(object sender, EventArgs e)
       {
          this.listen.Tell(new TimedMessage("Helloooo!"));
       }
    
       private void Form1_Load(object sender, EventArgs e)
       {
          this.actorSystem = ActorSystem.Create("ActorSystem");
          this.listen = this.actorSystem.ActorOf(
             Props.Create(typeof(Listen)));
       }
    }

    Om du testar detta lilla exempel så märker du att meddelandet går iväg till aktören i samma ögonblick som du klickar på knappen. Men istället för att anropa aktörens Tell-funktion i Click-eventet, så kan vi använda aktörssystemets Scheduler-property. Den har ett antal funktioner för schemaläggning och upprepning. Följande förändring gör att meddelandet går iväg först tre sekunder efter att man klickar på knappen.

    private void button1_Click(object sender, EventArgs e)
    {
       this.actorSystem.Scheduler.ScheduleTellOnce(
          TimeSpan.FromSeconds(3), this.listen,
          new TimedMessage("Helloooo!"), ActorRefs.Nobody);
    }

    Funktionen ScheduleTellOnce schemalägger ett meddelande istället för att skicka iväg det direkt. Det är det första argumentet som bestämmer när meddelandet ska gå iväg. Uttrycket TimeSpan.FromSeconds(3) säger att meddelandet ska gå iväg efter tre sekunder, oavsett vad klockan är. Schemaläggaren förväntar sig att man anger relativa tider, så om jag vill att meddelandet ska gå iväg ett bestämt klockslag, t.ex. den 19/5 kl. 13:30, kan jag istället skriva new DateTime(2015, 5, 19, 13, 30, 0).Subtract(DateTime.Now).

    Det andra argumentet är aktören som ta emot meddelandet. I mitt exempel finns endast en aktör, så den skickar jag in. Det tredje argumentet är meddelandet som ska skickas. Slutligen, det fjärde argumentet är avsändaren. Om det är en aktör som skickar meddelandet, skriver man normalt this.Self, men det går bra att skicka in en annan aktör här.

    I mitt fall när det inte finns någon aktör som avsändare (det är ju formuläret som skickar) så kan det vara frestande att skicka in null, men i dagsläget fungerar inte det. Klassen ActorRefs innehåller konstanter som kan användas som substitut för en avsändare, och Nobody betyder just ingen. (Detta kan komma att ändras.)

    Men tänk dig att du vill bli informerad när något inte händer. Från första klicket vill du veta om användaren fortsätter att klicka var tredje sekund, eller om användaren har blivit passiv. Det kan vi lösa på följande vis:

    1. När första klicket inträffar, säger vi att vi vill ha ett meddelande om tre sekunder.

    2. När knappen blir klickad på nästa gång, inom tre sekunder, så avbryter vi beställningen, och gör om den på nytt.

    3. Skulle användaren inte klicka inom tre sekunder så går meddelandet iväg eftersom det inte hunnit avbrytas. Således vet vi att användaren har blivit passiv.

    Detta kräver minimala förändringar. Först vill vi ha ett kvitto på beställningen. För detta använder jag en medlemsvariabel av typen Akka.Actor.ICancelable.

    private ICancelable idle_detector = null;

    Funktionen ScheduleTellOnce ger ingen retur, men ScheduleTellOnceCancelable ger ett svar i ICancelable-format som jag kan lagra i min nya medlemsvariabel. När användaren klickar, kan jag kolla om det finns en liggande beställning, och i så fall kan jag avbryta den – eftersom användaren klickat så är han ju inte inaktiv.

    private void button1_Click(object sender, EventArgs e)
    {
       if (!(this.idle_detector == null))
          this.idle_detector.Cancel();
       this.idle_detector =
          this.actorSystem.Scheduler.ScheduleTellOnceCancelable(
          TimeSpan.FromSeconds(3), this.listen,
          new TimedMessage("Idle!!!"), ActorRefs.Nobody);
    }

    För att testa programmet, starta och klicka lite då och då på knappen. För varje gång tre sekunder får passera utan något klick så går meddelandet iväg till aktören.

  • Akka .NET Remote duplex

    Akka .NET Remote duplex

    Jag har tidigare visat hur man skickar enkla meddelanden med Akka .NET Remote. Exemplet bestod av tre projekt, en server, ett datalager och en klient. Här tänkte jag visa hur man använder Akka .NET Remote för att både skicka och ta emot meddelanden. I detta exempel återanvänder jag servern BioServer och datalagret BioData från det förra exemplet.

    vs

    Tanken är alltså att programmet är ett enkelt bokningssystem för en liten biograf med tre sittplatser. Denna gång tänker jag utöka datalagret med lite nya meddelanden och servern med kapaciteten att svara på inkommande anrop. Dessutom bygger jag en ny grafisk klient.

    Datalagret
    I den förra versionen hade vi bara ett enda definierat meddelande i datalagret, klassen Bokningsmeddelande. Detta meddelande finns kvar, men nu kompletterar vi med Bokningssvar som ska skickas tillbaka till klienten som skickar in ett Bokningsmeddelande.

    public class Bokningsmeddelande
    {
       public int StolNr { get; private set; }
       public int BokadAv { get; private set; }
       public Bokningsmeddelande(int stolNr, int bokadAv)
       {
          this.StolNr = stolNr;
          this.BokadAv = bokadAv;
       }
    
       public override string ToString()
       {
          return string.Format(
             "Bokning från {0} på stol {1}.",
             this.BokadAv, this.StolNr);
       }
    }
    
    public class Bokninssvar
    {
       public bool BokningAccepterad { get; private set; }
       public int StolNr { get; private set; }
       public Bokninssvar(bool bokningAccepterad, int stolNr)
       {
          this.BokningAccepterad = bokningAccepterad;
          this.StolNr = stolNr;
       }
    }

    Servern
    Låt oss börja med att implementera stödet för Bokningsmeddelande och Bokningssvar.

    Klassen Stollista, alltså den bokningsbara resursen, har jag valt att utöka med en funktion som kan uppge vem som bokat en plats.

    public int BokadAv(int stolNr)
    {
       var stol = this.Find(m => m.StolNr == stolNr);
       if (stol == null)
          return 0;
       else
          return stol.BokadAv;
    }

    Det innebär att hela klassen nu ser ut så här:

    class Stollista : List
    {
       public override string ToString()
       {
          var ret = new System.Text.StringBuilder();
          foreach (var s in this)
             ret.AppendLine(s.ToString());
          return ret.ToString();
       }
    
       public bool Boka(int stolNr, int bokadAv)
       {
          var stol = this.Find(m => m.StolNr == stolNr);
          if (stol == null)
             return false;
          stol.BokadAv = bokadAv;
          return true;
       }
    
       public int BokadAv(int stolNr)
       {
          var stol = this.Find(m => m.StolNr == stolNr);
          if (stol == null)
             return 0;
          else
             return stol.BokadAv;
       }
    }

    Dessutom har jag modifierat aktören Bokningsaktor så att den kontrollerar huruvida den önskade stolen är bokningsbar, och meddelar klienten om bokningen accepteras. Notera hur aktören använder propertyn Sender för att kommunicera med avsändaren.

    class Bokningsaktor : Akka.Actor.ReceiveActor
    {
    
       public Bokningsaktor()
       {
          this.Receive(b => {
             Console.WriteLine("Ny bokning!");
             if (Program.stolar.BokadAv(b.StolNr) == 0 ||
                Program.stolar.BokadAv(b.StolNr) == b.BokadAv)
             {
                Program.stolar.Boka(b.StolNr, b.BokadAv);
                this.Sender.Tell(new BioData.Bokninssvar(true, b.StolNr));
             }
             else
                this.Sender.Tell(new BioData.Bokninssvar(false, b.StolNr));
             Console.WriteLine(Program.stolar.ToString());
          });
       }
    }

    Den nya klienten
    I detta fall vill jag ha en grafisk klient för att kunna representera svaren från servern på ett någorlunda snyggt sätt. Jag har skapat en applikation av typen Windows Forms Application, satt referenser till Akka .NET och Akka .NET Remote med hjälp av NuGet samt satt en referens till datalagret BioData. Dessutom vill jag läsa in namnrymden Akka.Actor för att komma åt en extension method – en överlagring av funktionen ActorOf.

    using Akka.Actor;

    Vidare väljer jag att hålla en referens till mitt aktörssystem i huvudformuläret.

    private Akka.Actor.ActorSystem system;

    På formuläret har jag placerat ut ett textfält där användaren förväntas infoga sitt användar-ID (ett heltal) samt tre knappar som representerar de tre bokningsbara stolarna. Man förväntas ange sitt ID i textfältet innan man klickar på någon knapp.

    form

    I formulärets Load-event initierar jag aktörssystemet på samma sätt som tidigare, men sparar nu referensen i medlemsvariabeln som jag deklarerade ovan.

    private void Form1_Load(object sender, EventArgs e)
    {
       var config = Akka.Configuration.ConfigurationFactory.ParseString(@"
    akka {
        actor {
            provider = ""Akka.Remote.RemoteActorRefProvider, Akka.Remote""
        }
        remote {
            helios.tcp {
                port = 0
                hostname = localhost
            }
        }
    }
    ");
       this.system = ActorSystem.Create("Bokningsklient", config);         
    }

    Eventet FormClosed får sköta uppstädningen.

    private void Form1_FormClosed(object sender, FormClosedEventArgs e)
    {
       this.system.Shutdown();
       this.system.Dispose();
    }

    Sedan ska Click-eventet under varje knapp inleda bokningsförfarandet.

    private void btnStol1_Click(object sender, EventArgs e)
    {
       this.Boka(1);
    }
    
    private void btnStol2_Click(object sender, EventArgs e)
    {
       this.Boka(2);
    }
    
    private void btnStol3_Click(object sender, EventArgs e)
    {
       this.Boka(3);
    }

    För att aktören ska kunna komma åt knapparna direkt, har jag även en enkel funktion som tar ett stolsnummer och ger en referens till en knapp.

    public Button Stolreferens(int StolNr)
    {
       Button[] ret = { this.btnStol1, this.btnStol2, this.btnStol3 };
       return ret[StolNr - 1];
    }

    Sista funktionen i formuläret är den som utför själva bokningen. Notera att vi skickar med en referens till en lokal aktör som ska kunna ta emot svaret från servern.

    private void Boka(int StolNr)
    {
       var avsandare = this.system.ActorOf();
       var bokare = this.system.ActorSelection(
          "akka.tcp://AllaBokare@localhost:8080/user/Bokare");
       bokare.Tell(new BioData.Bokningsmeddelande(StolNr,
          int.Parse(txtAnvID.Text)), avsandare);
    }

    Den lokala aktören ser ut så här. Notera att den innehåller lite fulkod för att erhålla en referens till formuläret i fråga. Koden förmodar att formuläret är ensamt i programmet.

    public class LocalActor : Akka.Actor.ReceiveActor
    {
       public LocalActor()
       {
          this.Receive(s =>
          {
             var stol = (Application.OpenForms[0]
                as Form1).Stolreferens(s.StolNr);
             stol.BackColor = s.BokningAccepterad ? Color.Green : Color.Red;
          });
       }
    }

    Varje klient som klickar på en knapp för att utföra en bokning, kommer att få en bekräftelse genom att knappen blir grön. Om stolen inte är bokningsbar blir istället knappen röd.

    form2

  • Introduktion till Akka .NET Remote

    Introduktion till Akka .NET Remote

    Akka .NET Remote låter aktörerna i Akka .NET skicka meddelanden till andra processer genom Windows Sockets. Det innebär att ett system kan distribueras över flera processer oavsett om de ligger på samma fysiska maskin eller på en annan maskin i nätverket.

    Arkitekturen i Akka .NET Remote är serverfri – varje peer kan kontakta och kommunicera med vilken annan peer som helst, givet att namn och port är känt. Det innebär att om du bygger en server, kan den utan problem förmedla direktkontakt mellan sina klienter.

    Detta exempel visar ett mycket enkelt bokningssystem av en biosalong med tre stolar. Systemet består av tre stycken projekt, en server, ett datalager och en klient. Servern och klienten är Console Applications (C#) och datalagret är ett klassbibliotek.

    vs

    Servern
    Låt oss börja med att titta på servern. I mitt exempel heter den BioServer. All kod som visas i servern förutsätter följande:

    1. Akka .NET är installerat. Detta kan göras med följande Nuget-kommando:

    Install-Package Akka

    2. Akka .NET Remote är installerat.

    Install-Package Akka.Remote

    3. Följande using-sats:

    using Akka.Actor;

    Så här ser huvudprogrammet ut:

    class Program
    {
       public static Stollista stolar;
    
       static void Main(string[] args)
       {
          var config =
             Akka.Configuration.ConfigurationFactory.ParseString(@"
    akka {
        actor {
            provider = ""Akka.Remote.RemoteActorRefProvider, Akka.Remote""
        }
    
        remote {
            helios.tcp {
                port = 8080
                hostname = localhost
            }
        }
    }
    ");
    
          stolar = new Stollista()
             { new Stol(1), new Stol(2), new Stol(3) };
          Console.WriteLine(stolar.ToString());
    
          using (var system =
             Akka.Actor.ActorSystem.Create("AllaBokare", config))
          {
             var bokare = system.ActorOf(new
                Akka.Actor.Props(typeof(Bokningsaktor)),"Bokare");
             Console.ReadLine();
          }
       }
    }

    Notera att konfigurationen anger vilken port servern ska lyssna på (8080). Den kodraden har jag klippt ut från dokumentationen för Akka .NET Remote och klistrat in här. Portnumret måste vara förutbestämt för att den första klienten ska kunna hitta servern.

    Därefter har jag min biosalong bestående av tre stolar. Dessa beskrivs av följande klasser:

    class Stollista : List<Stol>
    {
       public override string ToString()
       {
          var ret = new System.Text.StringBuilder();
          foreach (var s in this)
             ret.AppendLine(s.ToString());
          return ret.ToString();
       }
    
       public bool Boka(int stolNr, int bokadAv)
       {
          var stol = this.Find(m => m.StolNr == stolNr);
          if (stol == null)
             return false;
          stol.BokadAv = bokadAv;
          return true;
       }
    }

    Därefter använder jag Akka.Actor.ActorSystem.Create för att skapa mitt aktörssystem (kallad AllaBokare) på samma sätt som om jag hade tänkt att använda Akka .NET i en och samma process, och i using-blocket för aktörssystemet så skapar jag min aktör (kallad Bokare). Det som återstår i servern är klassen som beskriver aktören. Den ser ut så här:

    class Bokningsaktor : Akka.Actor.ReceiveActor
    {
    
       public Bokningsaktor()
       {
          this.Receive(b => {
             Console.WriteLine("Ny bokning!");
             Program.stolar.Boka(b.StolNr, b.BokadAv);
             Console.WriteLine(Program.stolar.ToString());
          });
       }
    }

    Datalagret
    Datalagret har jag valt att lägga i ett annat projekt i samma lösning som servern. Jag har kallat datalagret för BioData. Här finns en klass som beskriver meddelandet som klienten kan skicka till servern.

    public class Bokningsmeddelande
    {
       public int StolNr { get; private set; }
       public int BokadAv { get; private set; }
       public Bokningsmeddelande(int stolNr, int bokadAv)
       {
          this.StolNr = stolNr;
          this.BokadAv = bokadAv;
       }
    
       public override string ToString()
       {
          return string.Format("Bokning från {0} på stol {1}.",
             this.BokadAv, this.StolNr);
       }
    }

    Både servern och klienten ska ha en referens till datalagret.

    Klienten
    Klienten är mycket enkel. Notera först skillnaden i konfigurationen mellan klienten och servern. Servern har port 8080, vilket klienten måste veta om för att kunna hitta servern. Men när klienten gjort sig tillkänna så vet servern vilken port klienten använder, därför behöver vi inte bestämma någon port åt klienten. Att ange port 0 är att begära dynamisk port.

    Därefter skapar vi ett aktörssystem med det godtyckliga namnet Bokningsklient. Från systemet i klienten väljer vi att ansluta oss till servern genom att anropa ActorSelection. Som argument använder jag sökvägen till aktören på servern (som hette Bokare i systemet AllaBokare). Slutligen samlar jag in information från slutanvändaren som skickas till servern med metoden Tell. Så här ser källkoden för klienten ut:

    class Program
    {
       static void Main(string[] args)
       {
          var config = Akka.Configuration.ConfigurationFactory.ParseString(@"
    akka {
        actor {
            provider = ""Akka.Remote.RemoteActorRefProvider, Akka.Remote""
        }
        remote {
            helios.tcp {
                port = 0
                hostname = localhost
            }
        }
    }
    ");
    
          using (var system =
             Akka.Actor.ActorSystem.Create("Bokningsklient", config))
          {
             var bokare = system.ActorSelection(
                "akka.tcp://AllaBokare@localhost:8080/user/Bokare");
             Console.Write("Vad är ditt användar-ID? Skriv ett heltal. ");
             var userId = int.Parse(Console.ReadLine());
             while(true)
             {
                Console.Write("Vilken stol vill du boka? (1-3) ");
                var stol = Console.ReadLine();
                if (stol == "")
                   break;
                bokare.Tell(new
                   BioData.Bokningsmeddelande(int.Parse(stol), userId));
             }
             system.Shutdown();
          }
       }
    }

    Bilden visar servern bakom en klient.

    akka_remote

    Eftersom portnumret tilldelas till klienten dynamiskt så kan flera klienter startas och boka platser. Och eftersom arkitekturen i Akka .NET Remote är peer-to-peer så kan dessa skicka meddelanden till varandra.

  • Fem nyheter i VB.NET 2015

    Fem nyheter i VB.NET 2015

    Nu när Visual Studio 2015 CTP finns att ladda hem, går det bra att testa vad som är nytt i senaste versionen av Visual Basic. Och i ärlighetens namn är det inte speciellt mycket som hänt i språket, men här är fem stycken guldkorn.

    Enterslag i strängar
    I tidigare versioner av VB.NET fanns inget sätt att ange att en sträng skulle innehålla radbryten. För att skapa en sträng med radbryten var man tvungen att t.ex. konkatenera in ControlChars.CrLf eller använda StringBuilder-objektets AppendLine. Men nu är det fullt tillåtet att skriva enterslagen direkt i källkoden. Detta exempel skapar en sträng innehållande tre textrader:

    Dim X = "Jag
    är en
    sträng med tre rader!"

    Stränginterpolering
    Och apropå strängar så stöder nu VB.NET stränginterpolering. Tidigare när man infogade variabla värden i en sträng använde man funktionen String.Format. I detta exempel är X och Y flyttal:

    Dim S =
       String.Format("Värdet av X är {0:n1} och y är {1:n1}",
       X, Y)

    Notera hur jag först anger mina platshållare i strängen, för att sedan låta övriga parametrar fylla dessa platshållare. Med prefixet $ kan jag stoppa in referenserna direkt in i strängen. Så istället för att först ange plats 0 och sedan fylla ut den med X, så kan jag direkt säga att jag vill ha in värdet av X i strängen. Och editorns IntelliSense hänger med!

    Dim S = $"Värdet av X är {X:n1} och y är {Y:n1}"

    Null propagation
    Tänk dig att du har en variabel som representerar en anställd (klassen Employee). Du vill läsa av dess property FirstName, så här:

    Dim N = E.FirstName

    Problemet är bara att variabeln E kan vara oinitierad, och i så fall uppstår NullReferenceException i programmet. Men du kanske vill ha ut förnamnet om det finns ett Employee-objekt i E, annars en tom sträng. Detta brukar VB-programmerare hantera så här:

    Dim N = If(E Is Nothing, "", E.FirstName)

    Med hjälp av null propagation kan man nu skriva så här:

    Dim N = E?.FirstName

    Om E är oinitierad (Nothing i VB), så är nu N en oinitierad strängvariabel.

    NameOf
    Igen, tänk dig att jag har en klass som heter Employee och att den har en property som heter FirstName. Om jag vill att en strängvariabel ska innehålla namnet på propertyn FirstName, kanske för att jag vill använda reflection mot ett objekt av typen Employee, skulle jag kunna göra så här:

    Dim S = "FirstName"

    Problemet med ovanstående kod är givetvis att om jag ger min property ett nytt namn så slutar koden att fungera, eftersom strängkonstanten “FirstName” inte längre delar namn med propertyn i fråga. Det har inte funnits något bra sätt att göra detta på i VB. Om jag t.ex. vet att FirstName är den första propertyn, kan jag förvisso skriva så här:

    Dim S = GetType(Employee).GetProperties()(0).Name

    Men detta är precis lika instabilt eftersom koden nu rasar om någon lägger till en ny property före FirstName. Men i VB.NET 2015 kan jag kort och gott skriva så här:

    Dim S = NameOf(E.FirstName)

    Nu kommer värdet “FirstName” lagras i S, och om vi refaktorerar koden, kommer ovanstående rad att följa efter.

    Kommentarer i LINQ
    Den sista språkliga förbättringen ger oss möjlighet att skapa kommentarer i en LINQ-fråga. Tänk att vi har en lista av Employee-objekt enligt följande:

    Dim X As New List(Of Employee)()
    X.Add(New Employee("Sven"))
    X.Add(New Employee("Gunnar"))

    Om jag vill ha en fråga som hämtar de objekt vars förnamn börjar på G, kan jag uttrycka mig så här:

    Dim Svar = From E In X
               Where E.FirstName.StartsWith("G")
               Select E

    Men om jag skulle få för mig att kommentera mitt i programsatsen, t.ex. efter X på rad 1, efter (“G”) på rad två eller efter E på rad 3, skulle programmet rasa.

    Dim Svar = From E In X                       'Men nu kan jag
               Where E.FirstName.StartsWith("G") 'kommentera
               Select E                          'vart jag vill!

    Avslutningsvis vill jag kommentera att kodeditorn fått sig ett rejält lyft, där det som sticker ut mest är en referensräknare på alla objekt man skapar – gissningsvis ett mycket efterfrågat tillägg.

  • Enkel trådning i .NET med Akka

    Enkel trådning i .NET med Akka

    Historiskt sett har det varit ganska komplicerat att bygga multitrådade applikationer i .NET. Rent tekniskt var det enkelt att sjösätta en tråd med hjälp av klassen System.Threading.Thread, men om mycket skulle göras började koden ganska snabbt likna spaghetti. För att minska ner koden kan man använda multitrådade delegater istället för objekt av typen Thread, men det löste inte problemet med spaghettikod. Nyckelorden asynk och await löste både komplexiteten med hopp och returvärde, men var ganska hårt knutet till modellen TAP.

    Om jag väljer att jobba med Akka .NET blir trådningen ännu mer hanterad, fast kring en mycket friare modell än TAP, nämligen Actor Model. (I alla nedanstående exempel jobbar jag i Visual Studio 2013.) Tänk dig att jobbar i Windows Forms och att du vill utföra något som kräver ungefär fem sekunders arbete och sedan visar ett meddelande när arbetet är utfört. Min erfarenhet är att Akka .NET fortfarande kan utsättas för förändringar i sitt publika API, så den exakta kodens utseende kan variera – jag kör Akka 1.0.0. För att visa detta skapar jag ett helt nytt Windows Forms-projekt (C# med .NET Framework 4.5.1) och installerar Akka .NET från Package Manager Console genom att skriva:

    Install-Package Akka

    Om du inte ser Package Manager Console, Klicka Tools, NuGet Package Manager och Package Manager Console.

    Akka .NET använder meddelanden för att kommunicera. Meddelanden är kort och gott godtyckliga objekt som initieras och skickas i samband med att ett asynkront anrop görs. Meddelandet bör vara immutable, alltså meddelandet ska inte kunna modifieras, vilket kan implementeras genom att objektets data inte har några publika setters.

    class AkkaMessage
    {
       public string MyValue { get; private set; }
    
       public AkkaMessage(string myValue)
       {
          this.MyValue = myValue;
       }
    }

    En actor (aktör) är den t.ex. det objekt som kan ta emot ett meddelande och agera på det. Det som utmärker en sådan aktör är basklassen Akka.Actor.ReceiveActor samt konstruktorn som tar emot meddelandet som skickas till den. För att ta emot meddelandet används den generiska metoden Receive vars argument är det som ska göras med meddelandet. Den generiska metodens typparameter är meddelandeklassen. Så i följande kod anropar vi Receive och skickar med kod jobbar i fem sekunder för att sedan visa en meddelanderuta.

    class AkkaActor : Akka.Actor.ReceiveActor
    {
       public AkkaActor()
       {
          this.Receive(x =>
             {
                System.Threading.Thread.Sleep(5000);
                System.Windows.Forms.MessageBox.Show(x.MyValue);
             }
          );
       }
    }

    Nu återstår bara initieringen och själva anropet. Följande kod har jag skrivit i mitt programs huvudformulär. Först har jag ett privat fält av typen Akka.Actor.ActorSystem som representerar motorn i Akka – det s.k. actorsystemet. I Load-eventet för formuläret initierar jag systemet med funktionen Create. Create vill ha ett namn på systemet i sin kostruktor. Slutligen, under Click-eventet på en knapp på formuläret så gör jag anropet som ska hanteras av aktören ovan.

    Den första raden anropar funktionen ActorOf för att erhålla en referens till en aktör. Den andra raden utför utför anropet med hjälp av funktionen Tell, och låter ett meddelande skickas med som argument. Meddelandet måste vara av typen AkkaMessage, eftersom jag hårdkodade aktören att hantera den typen.

    public partial class Form1 : Form
    {
       private Akka.Actor.ActorSystem actorSystem;
    
       public Form1()
       {
          InitializeComponent();
       }
    
       private void Form1_Load(object sender, EventArgs e)
       {
          this.actorSystem =
             Akka.Actor.ActorSystem.Create("ActorSystem");
       }
    
       private void button1_Click(object sender, EventArgs e)
       {
          var m = this.actorSystem.ActorOf(new
             Akka.Actor.Props(typeof(AkkaActor)));
          m.Tell(new AkkaMessage("Hello!"), m);
       }
    }

    När du kör programmet, notera att programmets fönster är svarsbenäget under den tid programmet pausar pausar (anropet på Sleep), vilket säger oss att aktören och formuläret körs på olika trådar.

    Om du istället hade velat implementera detta i Visual Basic, skulle ditt meddelande kunna se ut så här:

    Public Class AkkaMessage
       Public Property MyValue() As String
       Public Sub New(MyValue As String)
          Me.MyValue = MyValue
       End Sub
    End Class

    Aktören skulle kunna se ut så här:

    Public Class AkkaActor
       Inherits Akka.Actor.ReceiveActor
    
       Public Sub New()
          Me.Receive(Of AkkaMessage)(AddressOf MyMessageHandler)
       End Sub
    
       Private Sub MyMessageHandler(X As AkkaMessage)
          System.Threading.Thread.Sleep(5000)
          MessageBox.Show(X.MyValue)
       End Sub
    
    End Class

    Och slutligen, formuläret skulle kunna se ut så här:

    Public Class Form1
    
       Private ActorSystem As Akka.Actor.ActorSystem
    
       Private Sub Form1_Load(sender As Object, _
          e As EventArgs) Handles MyBase.Load
          Me.ActorSystem = Akka.Actor.ActorSystem.Create("ActorSystem")
       End Sub
    
       Private Sub Button1_Click(sender As Object, _
          e As EventArgs) Handles Button1.Click
          Dim M = Me.ActorSystem.ActorOf( _
             New Akka.Actor.Props(GetType(AkkaActor)))
          M.Tell(New AkkaMessage("Hello!"), M)
       End Sub
    
    End Class
  • Lorenz-attraktionen

    Lorenz-attraktionen

    Läs gärna min text om Loernz-attraktionen, med tillhörande PowerShell-implementation, på Humanistbloggen!

    Uppdatering 2015-01-02: Jonas Elfström har översatt PowerShell-koden till Swift.

  • Anropa en web service från PowerShell

    För att sätta en servicereferens inne i Visual Studio måste man (numera) följa dessa steg:

    1. Högerklicka på References i Solution Explorer, välj Add Service Reference.

    2. Klicka på knappen Advanced.

    3. Klicka på knappen Add Web Reference.

    4. Ange sin URL, typiskt en asmx-fil i Microsoft-världen, och klicka Add Reference.

    Som exempel finns en publik web service som konverterar mellan Celsius och Fahrenheit (och vise versa) på följande URL: http://www.w3schools.com/webservices/tempconvert.asmx

    Därefter genereras en proxy, som kan användas inifrån projektet, t.ex. så här (i C#):

    using (var x = new com.w3schools.www.TempConvert())
    {
       Console.WriteLine(x.CelsiusToFahrenheit("20"));
    }

    I PowerShell har vi inte samma möjlighet att generera en proxy via att använda ett grafiskt användargränssnitt, men vi kan antingen utveckla en DLL-fil i C# och använda den från PowerShell, eller använda en CmdLet som heter New-WebServiceProxy. Detta skapar en proxy, och lagrar resultatet i $FtoC:

    $FtoC = New-WebServiceProxy -Uri http://www.w3schools.com/webservices/tempconvert.asmx

    Sedan är det bara att anropa:

    $FtoC.CelsiusToFahrenheit("20")

    Förhoppningsvis borde både PowerShell och C# vara överens om att 20 grader C är lika med 68 grader F.

  • Simple full screen support in Windows Forms

    These simple steps lets you create a Windows Forms application with full screen support. I have changed the DoubleBuffered property to true for flicker free redrawing, StartPosition to Manual to be able to manage startup position in code and KeyPreview to true.

    This code in the Load event handler will position the window and restore the fullscreen state.

    var s = this.GetScreen();
    this.Top = s.WorkingArea.Top + 40; this.Left = s.WorkingArea.Left + 40;
    this.Width = s.WorkingArea.Width - 80; this.Height =
                                                 s.WorkingArea.Height - 80;
    if ((Application.UserAppDataRegistry.GetValue("Fullscreen",
                                             "false") as string) == "true")
       this.ToggleFullscreen();

    This is the KeyDown event handler that will enable the user to press F11 or Alt+Enter to toggle fullscreen.

    private void MainForm_KeyDown(object sender, KeyEventArgs e)
    {
       if(((e.KeyCode == Keys.Enter) && e.Alt) || (e.KeyCode == Keys.F11))
          this.ToggleFullscreen();
    }

    The FormClosing event handler stores the screen state:

    private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
    {
       if (this.FormBorderStyle ==
                            System.Windows.Forms.FormBorderStyle.Sizable)
          Application.UserAppDataRegistry.SetValue("Fullscreen", "false");
       else
          Application.UserAppDataRegistry.SetValue("Fullscreen", "true");
    }

    And here are the GetScreen and ToggleFullscreen functions:

    private Screen GetScreen()
    {
       var s = Screen.FromPoint(new Point((int)(this.Left + (this.Width / 2)),
                                        (int)(this.Top + (this.Height / 2))));
       return s ?? Screen.PrimaryScreen;
    }
    
    private void ToggleFullscreen()
    {
       var s = this.GetScreen();
       if (this.FormBorderStyle ==
           System.Windows.Forms.FormBorderStyle.Sizable)
       {
          this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
          this.Top = s.Bounds.Top;
          this.Left = s.Bounds.Left;
          this.Width = s.Bounds.Width;
          this.Height = s.Bounds.Height;
       }
       else
       {
          this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.Sizable;
          this.Top = s.WorkingArea.Top + 40; this.Left =
             s.WorkingArea.Left + 40;
          this.Width = s.WorkingArea.Width - 80; this.Height =
             s.WorkingArea.Height - 80;
       }
     }

    Finally, the Resize event handler should invalidate the form, and the Paint event handler should contain the drawing instructions.

  • Evolutionary sudoku

    This is a successful attempt to use an evolutionary algorithm to generate a sudoku board. A complete board is created after usually less than a million iterations, sometimes after a couple of hundred generations.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace ConsoleApplication1
    {
       class Program
       {
          static void Main(string[] args)
          {
             var s = new Sudoku();
             s.Display();
             Console.Write("Done. Press enter to quit.");
             Console.ReadLine();
          }
       }
    
       class Sudoku
       {
          int[,] field = new int[9,9];
          const int mutation_speed = 3;
          const int dead_end_limit = 60000;
    
          public Sudoku()
          {
             var r = new Random();
             //Create a list of possible characters on the game field.
             var l = new List<int>();
             for (var i = 1; i < 10; i++)
                for (var j = 1; j < 10; j++)
                   l.Add(i);
             //Place them on the field randomly.
             for (var i = 0; i < 9; i++)
                for (var j = 0; j < 9; j++) {
                   var index = r.Next(0, l.Count);
                   var value = l[index]; l.RemoveAt(index);
                   this.field[j, i] = value;
                }
             //Prepare for score counting. Low is better.
             int score = int.MaxValue, iterations = 0, generations = 0,
             iterations_since_last_climb = 0;
             //Define how a mutation works - a random element swap.
             Action<int[,]> mutate = a => {
                var speed = (score > 2 ? mutation_speed : 1);
                for (var i = 0; i < speed; i++) {
                   int x1 = r.Next(0, 9), y1 = r.Next(0, 9),
                     x2 = r.Next(0, 9), y2 = r.Next(0, 9);
                   var v = a[x1, y1]; a[x1, y1] = a[x2, y2]; a[x2, y2] = v;
                }
             };
             //Show progress.
             Action status = () => {
                Console.Title = string
                   .Format("Score: {0:00} - Generations: {1:000} - " +
                   "Iterations: {2:000000}" +
                   " - Since last climb: {3:00000}",
                   score, generations, iterations, iterations_since_last_climb);
             };
             //Let evolution work.
             do {
                iterations++;
                //If adaptation has stopped, the parent must mutate.
                if (iterations_since_last_climb >= dead_end_limit) {
                   mutate(this.field);
                   score = this.GetScore(this.field);
                }
                //Breed two new sudokos and modify them slightly.
                int[,] child1 = (int[,])this.field.Clone();
                int[,] child2 = (int[,])this.field.Clone();
                mutate(child1); mutate(child2);
                //Check new scores.
                var child1score = this.GetScore(child1);
                var child2score = this.GetScore(child2);
                //Keep the best one, if any.
                Action<int[,], int> keep = (a, s) => {
                   this.field = (int[,])a.Clone(); score = s; generations++;
                   iterations_since_last_climb = 0; };
                if (child1score < score)
                   keep(child1, child1score);
                else if (child2score < score)
                   keep(child2, child2score);
                else
                   iterations_since_last_climb++;
                System.Threading.Thread.Yield();
                if ((iterations % 1000) == 0)
                   status();
    #if DEBUG
                this.Display();
                Console.CursorTop = 0;
    #endif
             } while (score > 0);
             status();
          }
    
          private int GetScore(int[,] p)
          {
             //Define how fitness is determined. A better solution is wanted.
             Func<int[,], int, int, bool> checkrow = (arr, x, y) => {
                var val = arr[x, y]; var count = 0;
                for (var i = 0; i < 9; i++)
                   if (arr[i, y] == val) count++;
                return (count == 1);
             };
             Func<int[,], int, int, bool> checkcol = (arr, x, y) => {
                var val = arr[x, y]; var count = 0;
                for (var i = 0; i < 9; i++)
                   if (arr[x, i] == val) count++;
                return (count == 1);
             };
             Func<int[,], int, int, bool> checksection = (arr, x, y) => {
                var section_x = x; while (!((section_x % 3) == 0)) section_x--;
                var section_y = y; while (!((section_y % 3) == 0)) section_y--;
                var val = arr[x, y]; var count = 0;
                for (var row = section_x; row < section_x + 3; row++)
                   for (var col = section_y; col < section_y + 3; col++)
                      if (arr[col, row] == val) count++;
                return (count == 1);
             };
             var score = 0;
             for (var i = 0; i < 9; i++)
                for (var j = 0; j < 9; j++) {
                   if (!(checkrow(p, j, i))) score++;
                   if (!(checkcol(p, j, i))) score++;
                   if (!(checksection(p, j, i))) score++;
                }
             return score;
          }
    
          public void Display()
          {
             for (var y = 0; y < 9; y++) {
                for (var x = 0; x < 9; x++)
                   Console.Write(field[x, y]);
                Console.WriteLine();
             }
          }
    
       }
    }

    Sudoku

    Update 2023-02-09: .NET 7.0 source code

  • Five cool features in Visual Basic

    1. Case tests

    Test a value against a limit, a range or constants.

    2. Typedefs

    Create custom names for any type. Demo:

    3. Object templates

    Create an enumeration of any type. Demo:

    4. Conditional exception handling

    Exception handlers that combine type checking and logical tests. Demo:

    5. XML literals

    Built in support for XML. Demo:

  • Processor information

    Beginners tend to ask how they can write a program that displays the processor model of a computer. There are a few different methods that can be used for this. You can call the SET command or you can query the registry. To call the SET command, connect to the output from a process and find the processor information in the output data.

    'Load processor information.
    Dim ProcessorIdentifier = ""
    Dim Ps = New ProcessStartInfo("cmd", "/c set")
    Dim Raw As String
    Ps.RedirectStandardOutput = True
    Ps.UseShellExecute = False
    Using P = Process.Start(Ps)
       P.WaitForExit()
       Raw = P.StandardOutput.ReadToEnd()
    End Using
    Dim Rows() = Raw.Split(ControlChars.CrLf.ToCharArray(),
                 StringSplitOptions.RemoveEmptyEntries)
    For Each Row As String In Rows
       If Row.StartsWith("PROCESSOR_IDENTIFIER=") Then
          ProcessorIdentifier = Row.Substring(21)
          Exit For
       End If
    Next
    
    'Display processor information.
    MessageBox.Show(ProcessorIdentifier)

    Another method is to check the computer registry in HKEY_LOCAL_MACHINE at HARDWARE\DESCRIPTION\System\CentralProcessor\0. The key is Identifier.

    'Load processor information.
    Dim ProcessorIdentifier = ""
    Dim Hardware = Microsoft.Win32.Registry.LocalMachine.OpenSubKey("HARDWARE")
    If Not Hardware Is Nothing Then
       Dim CP = Hardware.OpenSubKey("DESCRIPTION\System\CentralProcessor\0")
       ProcessorIdentifier = If(Not CP Is Nothing,
                    CP.GetValue("Identifier").ToString(), "")
    End If
    
    'Display processor information.
    MessageBox.Show(ProcessorIdentifier)
  • Första dagarna med Windows 8 på jobbet

    Första dagarna med Windows 8 på jobbet

    Jag uppgraderade från Windows 7 till Windows 8 på jobbdatorn i förra veckan – en netbook från HP. Installationen var smärtfri när den väl kom igång, men innan jag fick påbörja, fick jag en rapport på saker som skulle avinstalleras först. Lågnivåsgrejer. Omstart efter varje avinstallation. När installationsprogrammet väl jobbade, var uppgraderingen gjord på ett par minuter, men sen skulle allt gås igenom. Alla installerade program, alla inställningar, allt. Det tog sin lilla tid, men det gick ju bra att äta lunch under tiden. Och väl tillbaka från lunchen möttes jag av inloggningsskärmen. Allt var på plats. Visst, jag ville ta bort några “tiles” från startskärmen och jag ville lägga till några, innan jag var helt nöjd, men det var bara kul.

    När jag körde Windows 7 på min jobbdator, tog det ett par minuter från det att jag tryckt Ctrl-Alt-Delete till dess att jag kunde börja jobba. Windows 8 har laddningstider på några sekunder, även efter kallstart, så vänta är just inget man gör längre.

    Skrivbordet är så snyggt! Skuggorna är nästan helt borta, alla runda hörn är borta, alla texturer är borta. Det som ska användas, är det som visas. Däremot ska jag säga att Windows-användare redan börjat uttrycka missnöje med att systemet har ett skrivbord. Det känns lite retro. Som vanlig användare är det bara att låta bli att gå dit om man inte skulle vilja. Du kan ju även ta bort den tilen från startskärmen. Men som professionell användare, vill du kanske in i kontrollpanelen eller komma åt dina desktopapplikationer.

    Att söka efter program eller filer funkar som en klocka. Tryck Win, och skriv vilket program du vill starta, eller tryck Win+F och skriv in vilken fil du vill öppna. Den gamla hederliga trädbaserade filhanteraren Utforskaren finns också kvar under Win+E. Jag har ingen förståelse för dem som gnäller över att Utforskaren har ribbons istället för rullgardinsmenyer. Klicka inte fram dem, så slipper du se dem.

    Hittills har Windows 8 varit en ljuvlig upplevelse, och jag är övertygad att det kommer att fortsätta så. Och för min del, njuter jag av en ren arbetsyta och av alla de små kvalitetsförhöjande detaljerna som man stöter på under vägen. Och apropå det, jag passade även på att uppgradera från Visual Studio 2010 till 2012. Detta är förvisso en annan historia, men även där är alla texturer borta. En ren, fin och vit arbetsyta är vad man ser. Symbolspråket är lite annorlunda, så jag får läsa mig till var allt sitter, och det tog ett bra tag innan jag fattade hur man kom igång med byggandet av det som kallas för Windows Store Apps, alltså de som körs i det nya gränssnitett istället för på desktopen. Men det är nog där man vill hålla sig ändå. Härlig hårdvarurenderad grafik och stora, rena arbetsytor.

    Windows 8 är ett klockrent operativsystem. Som Windows 7, fast snabbare, snyggare och med tillgång till det nya gränssnittet med Windows Store Apps. På bilden visar jag en twitterklient för Windows 8 som heter MetroTwit.

  • Play some music COM music

    Play some music COM music

    PowerShell can make use of the .NET Framework, and can load assemblies using the Load function in System.Reflection.Assembly. Also, PowerShell can also use any COM class that is registered on your system. This feature gives you the ability to automate applications like Microsoft Word and Excel, or why not Windows Media Player? An error will be thrown if you specify an unexisting COM type name. This code will create an instance of Windows Media Player, if you have it installed:

    $player = New-Object -ComObject WMPLAYER.OCX

    Then, the Windows Media Player API is at your fingertips, as described on MSDN. This command will give you some kick ass rock:

    $player.URL = "F:\Music\ACDC - Who made who.mp3"

    Enjoy!

  • What’s all this then?

    What’s all this then?

    This might look strange to a C programmer:

    Dim I(10) As Integer
    Console.WriteLine(I.Length)
    Dim J(I.Length - 1) As Integer
    Console.Write(J.Length)

    This will give the output 11 and 11. The array named I has 11 elements because the last index (10) is given when the array is created. The array named J has 11 elements bacause Length (11) – 1 equals 10, and a 0-based array with last element 10 gives you 11 elements. Confusing.

  • Non-related implicit type casting

    Non-related implicit type casting

    As always, I use Visual Basic in strict mode. I have this function that expects a Foo array:

    Sub DoSomething(X() As Foo)
       Console.WriteLine(X.Length)
    End Sub

    What I’m showing here is true for single variables too, but I am showing this using arrays. This cannot be called using an Integer array as follows:

    DoSomething({1, 2, 3})

    Adding a Integer constructor to the Foo class does not help. However, you can add a widening operator to the Foo class, and define how an implicit conversion is done, like so:

    Public Class Foo
    
       Private mX As Integer
    
       Public Sub New(X As Integer)
          Me.mX = X
       End Sub
    
       Shared Widening Operator CType(X As Integer) As Foo
          Return New Foo(X)
       End Operator
    
    End Class

    Now, both the above method call is accepted. And because this also works on arrays, this simple line constructs three Foo objects:

    Dim X() As Foo = {4, 5, 6}

    The equivalent with a single (non arrayed) object would look like this:

    Dim Y As Foo = 7

    The opposite to Widening is called Narrowing and is used to define explicit type casts.

  • Declaring multiple variables

    Declaring multiple variables

    In PowerShell, variables are created when they are first used. Just by assigning a value to a variable, that variable is created.

    $x = 4

    If you assign a different kind of value to that same variable, the type of the variable is changed.

    $x = 4
    Write-Output $x.GetType()
    $x = "Hello"
    Write-Output $x.GetType()

    To lock a variable to a desired type, you can specify the type on the line where the variable is created. Now, this will fail, because “Hello” is a string value, not an integer.

    [int]$x = 4
    Write-Output $x.GetType()
    $x = "Hello" #fails here!
    Write-Output $x.GetType()

    However, you can still change the type, if you declare the new type. This change to line 3 will make the code run again:

    [int]$x = 4
    Write-Output $x.GetType()
    [string]$x = "Hello" #Success!
    Write-Output $x.GetType()

    Multiple variables can be created in one line of code. The first line will assign 1 to $a, 2 to $b and 3 to $c.

    $a, $b, $c = 1, 2, 3
    Write-Output $a
    Write-Output $b
    Write-Output $c

    If you want type checking enforced on these variables, the type name are added next to each variable.

    [int]$a, [int]$b, [int]$c = 1, 2, 3
    Write-Output $a
    Write-Output $b
    Write-Output $c

    The output is:

    1
    2
    3
  • The easiest way to get started with Basic

    The easiest way to get started with Basic

    Let’s say that you’re not really a programmer, but perhaps an old Sinclair-user or Commodore user. What is the easiest way to get started with programming on a modern PC?

    Install Microsoft Small Basic from here (it’s completely free). Click Download Small Basic, and just follow the instructions. When the installation is complete, you will have a start menu item that looks like this:

    Now, things are really easy. A document is a program. Write your code and hit F5 to run it. Here I have written a Hello world program, started it, and the result is this:

    Press any key to continue editing.

    Context help is always displayed to the right in the main windows of Small Basic, so that you will always know what the code you write actually does. And if you don’t know what to write at all, an easy tutorial can be found here.

    Are you looking for a random number generator, try Math.GetRandomNumber. Specify the largest number you want. This code will display 100 numbers between 1 and 10.

    For I=1 To 100
      TextWindow.WriteLine(Math.GetRandomNumber(10))
    EndFor
  • Calling methods on uninitiated variables

    Calling methods on uninitiated variables

    If you don’t assign a value to an object variable, it will have the value Nothing (equivalent to null in C#). These two lines of code will therefore effectively do exactly the same thing, even though the second version will produce slightly more assembly:

    Dim MyString As String

    …and…

    Dim MyString As String = Nothing

    If you create an extension method on the String class, and you write it in such fashion that it can handle uninitialized variables, it will be able to do so. The extension is done to the type, not to the object. This is an example of a function that checks if a string is empty:

    <System.Runtime.CompilerServices.Extension()> _
    Public Function IsEmpty(ByVal S As String) As Boolean
       If S Is Nothing Then
          Return True
       Else
          Return (S = "")
       End If
    End Function

    When the above extension is present, the following piece of code…

    Dim MyString As String = Nothing
    Console.WriteLine(MyString.IsEmpty())

    …displays the word True in your console window!

  • Reading out SQL Data with named columns

    Reading out SQL Data with named columns

    This code reads out names from the Employees table of the Northwind database. You must correct the Data Source property in the connection string for it to run.

    #Create a connection object and open it.
    [String]$cns="Data Source=XXX;Initial Catalog=Northwind;
       Integrated Security=True"
    [System.Data.SqlClient.SqlConnection]$connection=New-Object 
       -TypeName System.Data.SqlClient.SqlConnection -ArgumentList $cns
    $connection.Open()
    
    #Create a command and execute it.
    [String]$query="SELECT FirstName, LastName
       FROM dbo.Employees ORDER BY LastName, FirstName" 
    [System.Data.SqlClient.SqlCommand]$command=New-Object
       -TypeName System.Data.SqlClient.SqlCommand
    $command.Connection=$connection
    $command.CommandText=$query
    $r=$command.ExecuteReader()
    
    #Iterate the result.
    while($r.Read()) {
        
        #Read out first name.
        [String]$firstname=""
        if( -not $r.IsDBNull(0)) {
            $firstname=$r.GetString(0)
        }
        
        #Read out last name.
        [String]$lastname=""
        if( -not $r.IsDBNull(1)) {
            $lastname=$r.GetString(1)
        }
        
        #Display.
        Write-Output ($firstname + " " + $lastname)
    }
    
    #Close the reader.
    $r.Close()
    
    $connection.Close()
    $connection.Dispose()

    Here I use column indexes when referring to columns. A change in the SQL query will produce errors in the code that reads out the result. The solution is to call the GetOrdinal function of the reader to get the indexes of the columns, like this:

    #Create a connection object and open it.
    [String]$cns="Data Source=XXX;Initial Catalog=Northwind;
       Integrated Security=True"
    [System.Data.SqlClient.SqlConnection]$connection=New-Object 
       -TypeName System.Data.SqlClient.SqlConnection -ArgumentList $cns
    $connection.Open()
    
    #Create a command and execute it.
    [String]$query="SELECT FirstName, LastName
       FROM dbo.Employees ORDER BY LastName, FirstName" 
    [System.Data.SqlClient.SqlCommand]$command=New-Object 
       -TypeName System.Data.SqlClient.SqlCommand
    $command.Connection=$connection
    $command.CommandText=$query
    $r=$command.ExecuteReader()
    
    #Get use named columns.
    [int]$Index_FirstName=$r.GetOrdinal("FirstName")
    [int]$Index_LastName=$r.GetOrdinal("LastName")
    
    #Iterate the result.
    while($r.Read()) {
        
        #Read out first name.
        [String]$firstname=""
        if( -not $r.IsDBNull($Index_FirstName)) {
            $firstname=$r.GetString($Index_FirstName)
        }
        
        #Read out last name.
        [String]$lastname=""
        if( -not $r.IsDBNull($Index_LastName)) {
            $lastname=$r.GetString($Index_LastName)
        }
        
        #Display.
        Write-Output ($firstname + " " + $lastname)
    }
    
    #Close the reader.
    $r.Close()
    
    $connection.Close()
    $connection.Dispose()
    

    Now, if you change the the query, the reader will still find the desired columns.

  • Five reasons to choose Windows before Mac

    Five reasons to choose Windows before Mac

    5. Design. There are a huge number of computers to choose from. The only constant is change. The few Mac machines on the market are OK, but you can find lots and lots of machines running Windows, including masterpieces Mac users only can dream of.

    4. Software. The “killer software” that makes a Mac worth owning (Safari, Cubase, Photoshop, Propellerheads Reason, Firefox) is perfectly available on Windows. Also, for each Mac specific application you can find, there are at least ten Windows specific alternatives.

    3. Memory cost. A larger number of vendors and in some cases larger vendors, provides customer value.

    2. Ease of use. Windows is well documented, logically constructed. To install an application on Windows, you download it and confirm that you want to install it. You don’t have to know what drag and drop operations that you expect to perform, and therefore, you don’t need any experience to get by. Experience gives you advantages, but is not required.

    1. Customisation and extensibility. The smallest edition of the extremely powerful code editor is free to use for any purpose, and just about any Microsoft application comes with a well documented programming interface. And if you want to start from scratch, the .NET Framework is without competition. In both cases, no matter what programming language you know.

  • Iterators in Visual Basic

    Iterators in Visual Basic

    The concept of iterators is well known to C# programmers, but it is new in Visual Basic (available in Visual Studio 11), so this post is probably only interesting for VB programmers. I got some great help from my friend Roger Alsing in explaining what it is that is good about iterators.

    An iterator is similar to a function that returns a collection, but an iterator allows the caller to iterate before the collection is populated. The iterator is implemented as a function with the keyword Iterator, but it is actually compiled to an object.

    Public Iterator Function Test() As IEnumerable(Of Integer)

    This is an iterator named Test that returns integers. The return type declared must be an IEnumerable of the type your iterator contains. This iterator returns Integer values, and therefore the return type is set to an IEnumerable(Of Integer). This is a usage example of our iterator:

    For Each I As Integer In Me.Test()
       MessageBox.Show(I.ToString())
    Next

    Of course, a bunch of integer values will pop up on screen. But lets check the full implementation of the Test iterator.

    Public Iterator Function Test() As IEnumerable(Of Integer)
       Yield 10
       Yield 20
       Yield 30
    End Function

    When the For Each loop is done iterating, three message boxes have popped up. They first displays 10, the second 20 and the third 30. So why not just return an array of {10, 20, 30}?

    Like I mentioned, a function that returns a collection must load the collection before returning it. Imagine that you want to return 10 objects, each object takes one second to load. This gives you a pause of 10 seconds before the iteration starts. Example:

    Public Function ReturnTenThings() As List(Of String)
       Dim Ret As New List(Of String)()
       For I As Integer = 0 To 9
          Threading.Thread.Sleep(1000)
          Ret.Add((I + 1).ToString())
       Next
       Return Ret
    End Function

    This iteration will not start until 10 seconds have passed:

    For Each X As String In Me.ReturnTenThings()
       MessageBox.Show(X)
    Next

    If we rewrite ReturnTenThings to be an iterator, like this…

    Public Iterator Function ReturnTenThings() As IEnumerable(Of String)
       Dim Ret As New List(Of String)()
       For I As Integer = 0 To 9
          Threading.Thread.Sleep(1000)
          Yield (I + 1).ToString()
       Next
    End Function

    …the same iteration will still take 10 seconds to complete, but it will start after just one second.

    Finally, a word of warning. If you need to know before you start your iteration, how many elements it holds, don’t just read the Count property of your iterator, because that will execute your code. If you need to know, copy the elements to a list, and read the Count property of that list. This code will take 20 seconds to execute, because the iterator runs twice:

    MessageBox.Show(Me.ReturnTenThings().Count.ToString())
    For Each X As String In Me.ReturnTenThings()
       MessageBox.Show(X)
    Next
  • Stealing keys

    Stealing keys

    Events and everything you might need to develop a user control, will tell you about mouse and keyboard activity so that you can respond the user correctly. If you want to be able to catch arrow keys or tab, you must overload this function:

    Protected Overrides Function ProcessCmdKey(ByRef msg
       As System.Windows.Forms.Message, ByVal keyData
       As System.Windows.Forms.Keys) As Boolean

    This method gets called no matter what key is pressed. Also, if you act on the key, and don’t want the original functionality, make the function return True. If you want the framework to act on the key press, make the function return False.

  • Comparing strings: What’s being compared?

    Comparing strings: What’s being compared?

    In a simple loop, I compare ten million short strings with other strings. 1.4 million of them are identical. Depending on how the comparison is done, the execution speed differs. When the compare operator is used, the ten million tests are done in 0.31 seconds on my laptop.

    If Strings(A1) = Strings(A2) Then

    When the String.Compare function is used, the ten million tests are done in somewhere between 3.35 to 3.39 seconds. For me, case sensitive tests tend to be slightly slower.

    If String.Compare(Strings(A1), Strings(A2)) = 0 Then

    The reason that the equals operator is faster, is because it only compares the addresses where the strings are located, and since strings are unique in .NET, two strings with the same value, are stored in the same address. The Compare function looks at the characters in the string, and is therefore slower.

    This is the disassembly for the test with the equals operator:

    0000018f  mov         eax,dword ptr [ebp-50h] 
    00000192  mov         edx,dword ptr [ebp-48h] 
    00000195  cmp         eax,dword ptr [edx+4] 
    00000198  jb          0000019F 
    0000019a  call        67E075C0 
    0000019f  mov         eax,dword ptr [edx+eax*4+0Ch] 
    000001a3  mov         dword ptr [ebp+FFFFFF70h],eax 
    000001a9  mov         eax,dword ptr [ebp-54h] 
    000001ac  mov         edx,dword ptr [ebp-48h] 
    000001af  cmp         eax,dword ptr [edx+4] 
    000001b2  jb          000001B9 
    000001b4  call        67E075C0 
    000001b9  mov         eax,dword ptr [edx+eax*4+0Ch] 
    000001bd  mov         dword ptr [ebp+FFFFFF6Ch],eax 
    000001c3  push        0 
    000001c5  mov         ecx,dword ptr [ebp+FFFFFF70h] 
    000001cb  mov         edx,dword ptr [ebp+FFFFFF6Ch] 
    000001d1  call        558156C0 
    000001d6  mov         dword ptr [ebp-74h],eax 
    000001d9  cmp         dword ptr [ebp-74h],0 
    000001dd  sete        al 
    000001e0  movzx       eax,al 
    000001e3  mov         dword ptr [ebp-64h],eax 
    000001e6  cmp         dword ptr [ebp-64h],0 
    000001ea  je          00000201

    This is the disassembly for the test with the String.Compare function:

    0000018f  mov         eax,dword ptr [ebp-50h] 
    00000192  mov         edx,dword ptr [ebp-48h] 
    00000195  cmp         eax,dword ptr [edx+4] 
    00000198  jb          0000019F 
    0000019a  call        67F275C0 
    0000019f  mov         ecx,dword ptr [edx+eax*4+0Ch] 
    000001a3  mov         eax,dword ptr [ebp-54h] 
    000001a6  mov         edx,dword ptr [ebp-48h] 
    000001a9  cmp         eax,dword ptr [edx+4] 
    000001ac  jb          000001B3 
    000001ae  call        67F275C0 
    000001b3  mov         edx,dword ptr [edx+eax*4+0Ch] 
    000001b7  call        5E514300 
    000001bc  mov         dword ptr [ebp-74h],eax 
    000001bf  cmp         dword ptr [ebp-74h],0 
    000001c3  sete        al 
    000001c6  movzx       eax,al 
    000001c9  mov         dword ptr [ebp-64h],eax 
    000001cc  cmp         dword ptr [ebp-64h],0 
    000001d0  je          000001E7

    It looks less, but it does more. The actual comparing is not shown, but it checks character until a mismatch is found. Since the difference is big, it’s important to pick the right method. If you add the compile option to compare text as text, the equal operator is almost just as slow as the String.Compare function, so the impact for this option…

    Option Compare Text

    …is huge.

  • The shortest code you need to draw vector graphics

    The shortest code you need to draw vector graphics

    This example shows the shortest code you need to draw vector graphics in PowerShell. However, this code demonstrates a problem rather than a solution. The .NET Framework wants you to inherit a Form class when you describe a picture, because you will need to be able to access protected properties and to respond to events. But since the CreateGraphics function is public, you can still do some hacking with an instance of a Form class. This code creates a window, draws an X on it, and leaves it visible for 5 seconds.

    #Load the Windows Forms library.
    [string]$WindowsFormsLibrary =
    "System.Windows.Forms,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b77a5c561934e089"
    [System.Reflection.Assembly]::Load($WindowsFormsLibrary)
    
    #Load the Drawing library.
    [string]$DrawingLibrary =
    "System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
    [System.Reflection.Assembly]::Load($DrawingLibrary)
    
    #Create a window, and set its properties.
    [System.Windows.Forms.Form]$f = New-Object System.Windows.Forms.Form
    $f.Width = 500
    $f.Height = 300
    
    #Display the form.
    $f.Show()
    #Force a complete draw before we add any graphics.
    $f.Refresh()
    
    #Acquire the graphics interface.
    [System.Drawing.Graphics]$g = $f.CreateGraphics()
    
    #Draw anything you like here using GDI+.
    $g.DrawLine([System.Drawing.Pens]::Black, 50, 20, 450, 250)
    $g.DrawLine([System.Drawing.Pens]::Black, 450, 20, 50, 250)
    
    #Dispose the graphics interface.
    $g.Dispose()
    
    #Wait for 5 seconds before closing it all down.
    Start-Sleep -s 5
    $f.Close()
    $f.Dispose()

    If we take the trouble to create a custom type based on the Form class, we can create form has double buffering enabled by definition, and is of correct size by definition. The size can be set from outside the form as shown above, but the DoubleBuffered property that controls double buffering could not. So by just replacing the predefined Form class with a custom extension, we are slightly closer to our goal.

    #Load the Windows Forms library.
    [string]$WindowsFormsLibrary =
    "System.Windows.Forms,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b77a5c561934e089"
    [System.Reflection.Assembly]::Load($WindowsFormsLibrary)
    
    #Load the Drawing library.
    [string]$DrawingLibrary =
    "System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
    [System.Reflection.Assembly]::Load($DrawingLibrary)
    
    #Create a custom form with double buffering.
    $Refs = @("System.Windows.Forms", "System.Drawing")
    Add-Type -ReferencedAssemblies $Refs @'
    public class MyGraphicsForm:System.Windows.Forms.Form
    {
       private System.ComponentModel.IContainer components = null;
    
       protected override void Dispose(bool disposing)
       {
          if (disposing && (components != null))
          {
             components.Dispose();
          }
          base.Dispose(disposing);
       }
    
       private void InitializeComponent()
       {
          this.SuspendLayout();
          this.ClientSize = new System.Drawing.Size(500, 300);
          this.DoubleBuffered = true;
          this.Text = "My graphics form";
          this.ResumeLayout(false);
    
       }
    }
    '@
    
    #Create our custom window.
    [System.Windows.Forms.Form]$f = New-Object MyGraphicsForm
    
    #Display the form.
    $f.Show()
    #Force a complete draw before we add any graphics.
    $f.Refresh()
    
    #Acquire the graphics interface.
    [System.Drawing.Graphics]$g = $f.CreateGraphics()
    
    #Draw anything you like here using GDI+.
    $g.DrawLine([System.Drawing.Pens]::Black, 50, 20, 450, 250)
    $g.DrawLine([System.Drawing.Pens]::Black, 450, 20, 50, 250)
    
    #Dispose the graphics interface.
    $g.Dispose()
    
    #Wait for 5 seconds before closing it all down.
    Start-Sleep -s 5
    $f.Close()
    $f.Dispose()

    To be continued.

  • Piping objects

    If you want to create and run a ps1 script, make sure to give yourself the permission to execute scripts. If you are running a newer operating system, you must start PowerShell as an administrator the time that you grant yourself the right to run scripts.

    When you type DIR, a list of DirectoryInfo and/or FileInfo objects are created and sent to the script host. Each object, no matter type, are displayed as strings, meaning that the directory name or file name is displayed. How ever, you can use the pipeline to access actual objects. I have some directories and a few files in my C root, so if I pipe the output from the DIR command to an iteration that displays the object’s type name, like so:

    DIR C:\ | ForEach-Object { Write-Host $_.GetType().Name }

    From that I will get the word DirectoryInfo for each directory and the word FileInfo for each file in my C root. These are the .NET classes that represent directories and files. Since the PowerShell pipeline actually is handling objects, you can use these objects by accessing the properties or calling the functions of each object. A simple task such as displaying the number of files in each directory, is a walk in the park, when the actual object you need to do this, already is in the pipeline.

    DIR C:\ | ForEach-Object {
    If ($_.GetType().Name -like "DirectoryInfo")
       {
          Write-Host $_.Name "(" $_.GetDirectories().Length
             " dirs and " $_.GetFiles().Length " files.)"
       }
    }

    The output for this, is the name of the directory and the number of child directories and files that it holds. I can see that my Windows folder holds 66 directories and 45 files.

  • Extension methods in Visual Basic

    Extension methods is a well known concept in C#. The idea is that you can add methods to a type without inheritance, as described here.

    Visual Basic doesn’t have any linguistic support for extension methods, but it can be done thanks to a method attribute. There are some rules for doing this. You must declare your sub or function in a standard module, not a class. You must have at least one parameter, and that parameter is the type you are extending. Any other parameters will be parameters in your function. Finally, your sub or function must have the System.Runtime.CompilerServices.Extension attribute.

    So if you want to add a function that takes no parameters to the Integer type, you will have to define a function that takes one parameter, an Integer. If you want to add a function that takes one parameter, you will have to define a function that takes two parameter, the first must be an Integer and the second (who will serve as the first parameter in your function) can be of any type you like.

    Public Function DoubleValue(ByVal I As Integer) As Integer
       Return I * 2
    End Function

    Remember, the code must be written in a standard module.

    The last thing that you have to do, is to add the attribute.

    <System.Runtime.CompilerServices.Extension()>
    Public Function DoubleValue(ByVal I As Integer) As Integer
       Return I * 2
    End Function

    (The above code is VBx syntax. For older Visual Basic versions, add a blank followed by an underscore to the attribute line.)

    Now you can call the DoubleValue function from any Integer, in this case 5:

    Console.WriteLine(5.DoubleValue())

    The output will of course be 10.

  • Visual Basic: Importing namespaces

    In C# you can use the using directive to import the classes in a given namespace to your current scope. If you want to use the classes in System.Data.SqlClient, you could refer to them using their full path, like so:

    var r = new System.Data.SqlClient.SqlDataAdapter();

    You can add namespaces to your scope by adding a using directive in the beginning of your source file. If you add this directive:

    using System.Data.SqlClient;

    You could then access the SqlDataAdapter class in your code, without typing the full path, like so:

    var r = new SqlDataAdapter();

    Visual Basic does not have the using directive, but it has a more powerful directive called Imports. Imports can import both classes and other namespaces. The code that creates a SqlDataAdapter in Visual Basic looks like this:

    Dim R As New System.Data.SqlClient.SqlDataAdapter()

    If you use the Imports directive to import System.Data in the beginning of your file, like so:

    Imports System.Data

    You can access both the namespaces (like SqlClient) and the classes in System.Data without providing the full path.

    Dim R As New SqlClient.SqlDataAdapter()

    If course, you can go on and import the SqlClient namespace to access the SqlDataAdapter class without specifying it’s full path, just as you can do in C#. So, the using directive in C# can import classes, but the Imports directive in VB imports both classes and namespaces.

  • A multithreaded sockets server, just a few lines of code

    This small piece of Visual Basic code (VBx) shows how you can do a multithreaded sockets server in just a few lines of code. I write all of this code in a console application. The main module will only hold an implementation of the Main function. Like so:

    Module Module1
    
        Sub Main()
          Dim L As New System.Net.Sockets.TcpListener(
             New System.Net.IPAddress({192, 168, 1, 100}), 80)
          L.Start()
          Dim ThreadCounter = 0
          Do
             ThreadCounter += 1
             Dim C = L.AcceptTcpClient()
             Dim S As New NetSession(C, ThreadCounter)
             Dim T As New Threading.Thread(AddressOf S.SessionLoop)
             Console.WriteLine("Starting thread " & ThreadCounter.ToString() & ".")
             T.Start()
          Loop
        End Sub
    
    End Module

    Note that I have hard coded my local IP address, and passed it as an argument to the TcpListener constructor, but there are easy ways collect this information using the .NET Framework. The variable C is a System.Net.Sockets.TcpClient, because that is what the AcceptTcpClient function returns. The ThreadCounter is just so that different connections will get a unique session identifier.

    The rest of the code takes place in the NetSession class.

    Public Class NetSession
    
       Private mC As System.Net.Sockets.TcpClient
       Private mS As System.Net.Sockets.NetworkStream
       Private mThreadCounter As Integer
       Private mIndex As String
    
       Public Sub New(ByVal C As System.Net.Sockets.TcpClient,
             ByVal ThreadCounter As Integer)
          Me.mC = C
          Me.mThreadCounter = ThreadCounter
          Me.mIndex = ""
       End Sub
    
       Public Sub SessionLoop()
          Me.mS = Me.mC.GetStream()
          Me.mC.LingerState.Enabled = False
          Me.WriteLine("Connected.")
          While Me.mC.Connected
             If Me.mS.DataAvailable Then
                Dim GotData As New System.Text.StringBuilder()
                While Me.mS.DataAvailable
                   Dim bytes(Me.mC.ReceiveBufferSize - 1) As Byte
                   Dim Len = Me.mS.Read(bytes, 0, Me.mC.ReceiveBufferSize)
                   If Len > 0 Then
                      GotData.Append(System.Text.Encoding.UTF8.GetString(bytes, 0, Len))
                   End If
                End While
                Dim D = GotData.ToString().Trim()
                If Not D = "" Then
                   If Not Me.Handle(D) Then
                      Exit While
                   End If
                End If
             End If
          End While
          Me.mS.Close()
          Me.mS.Dispose()
          Me.mC.Close()
          Console.WriteLine("Thread " & Me.mThreadCounter.ToString() & " is closing.")
       End Sub
    
       Private Sub WriteLine(ByVal T As String)
          Dim Bytes() As Byte = System.Text.Encoding.UTF8.GetBytes(T & ControlChars.CrLf)
          Me.mS.Write(Bytes, 0, Bytes.Count)
       End Sub
    
       Private Function Handle(ByVal D As String) As Boolean
          Console.WriteLine("Thread " & Me.mThreadCounter.ToString() & ": " & D)
          If D.ToLower() = "quit" Then
             Me.WriteLine("Bye.")
             Return False
          Else
    
             'Do parsing here! Return True no matter what.
             Me.WriteLine("Thanks!")
    
             Return True
          End If
       End Function
    
    End Class

    The constructor accepts the TCP client (representing the connected application) and the ThreadCounter variable. The SessionLoop function is the main loop for each thread.

    The WriteLine function sends responses to the connected client application and the Handle function is the place where you implement your parsing (or invokes some existing parser). Note that the Handle function must return True, even if your parsing fails. Failed parsing should render in an error message to the client application, but the function should still return True. The returning of the value False, is a signal that the client disconnects.

    When you run this code, you will get a warning from your Windows Firewall (I run a Swedish Windows 7 installation). Accept that this program can use your local network.

    To make this program actually do something, start a sockets client, like PuTTY. Configure it like so:

    Host IP: [Your local IP]
    Port: 80
    Encoding: UTF-8

    Note that we use UTF-8 encoding to convert between byte arrays and strings in the source code, so the TCP client must also use UTF-8.

    Since our server is multithreaded and have multiple connection awareness, you can connect more than one sockets client to your application.

    Send Quit from your client application to quit.

  • PowerShell functions argument catching

    PowerShell is not very object oriented. The support for creating classes is implemented through the Add-Type cmdlet that takes C# code. Here I show how to use Add-Type to define and expose classes that use any part of the .NET Framework. These classes can then be instantiated using the New-Object cmdlet.

    Functions are defined using the function keyword. This code defines a function that doesn’t require any arguments:

    #Define a function.
    function DoSomething()
    {
       Write-Output "Hello!"
    }
    
    #Call a function.
    DoSomething

    When defining parameters, you can choose what parameters that need to be strongly typed by adding the desired type name in front of the parameter. Here I have 3 calls to the TwoParams function. The first parameter can be anything, but the second must be and int. Both call 1 and call 2 will run, becase $a can accept a string or an int. Call 3 will fail because $b cannot be a string.

    function TwoParams($a, [int]$b)
    {
    	$b = $b + 1
    	Write-Output "a=$a"
    	Write-Output "b=$b"
    }
    
    #Two correct calls.
    Write-Output "Call 1"
    TwoParams "Hello!" 10
    
    Write-Output "Call 2"
    TwoParams 20 20
    
    Write-Output "Call 3 will fail!"
    TwoParams 30 "Hello!"

    Default values can be provided, so that omitted arguments still will have a value. In this case, it is assumed that the values 1 and 2 is passed to the function. All parameters are passed by value.

    function TestingDefaults($a=1, $b=2)
    {
    	Write-Output "$a $b"
    }
    
    TestingDefaults

    Now, let’s look at the strange things. All arguments that are sent in, but not declared in the function head, will be captured by the $args array. In this case, $args in SomeFunction will contain 4 elements, because 4 arguments are sent:

    function SomeFunction()
    {
    	$NumberOfArguments=$args.length
    	Write-Output "You gave me $NumberOfArguments arguments."
    }
    
    SomeFunction "10" "Hej" 5 10

    But here, still 4 arguments are sent, but the first argument is declared, so that only 3 arguments are catched by the $args array:

    function SomeFunction($x)
    {
    	$NumberOfArguments=$args.length
    	Write-Output "You gave me $NumberOfArguments arguments."
    }
    
    SomeFunction "10" "Hej" 5 10
  • Visual Basic: The coolest code editor you ever saw

    Visual Basic: The coolest code editor you ever saw

    Let’s say that you’re typing a word.

    As you type…

    …the IntelliSense filters out the word you are typing.

    If you type something that isn’t in the list, the list is closing.

    If you decide that the last character you typed is wrong, use backspace to delete it. Instantly, the IntelliSense is displayed again, with the possible option selected.

    The C# editor has a behavior that is similar to this, but if you go pass an membership access operator, or something like that, the C# IntelliSense is completely lost. You can bring it up again by deleting the line, and start typing again, or by pressing Ctrl+J. The Visual Basic editor picks up automatically, as shown above, whenever you press backspace to delete a word.

    Another big advantage in the Visual Basic editor is the enumeration awareness. The Visual Basic editor recognizes when an enumeration is an available option, and provides possible options from the right location in the framework. The C# editor seems very unaware of enumerations, and you might have to look up enumerations that you are unfamiliar of, in the Object Browser by pressing Ctrl+Alt+J.

    Demonstrated here:

  • Visual Basic: Serious error trapping

    The concept of filtering by exception type is familiar to any C# programmer. Visual Basic takes this one step further by also allowing a logical condition that also needs to be true for the block to be executed. If this feature is used, you can have one Try block with multiple Catch section that filters on the same exception class. This is not possible in C# and not allowed in VB without this extra logical condition. The result is better readability and a more logical structure.

    Imagine that you want to do an iteration, that fails after three errors. This is the ugly version:

    //Do something 10 times, bail after 3 errors.
    for (int x = 0; x < 10; x++)
    {
       try
       {
          Console.WriteLine("Try something.");
          //This operation will fail.
          throw new Exception();
       }
       catch (Exception ex)
       {
          Console.WriteLine("Failed.");
          if (x >= 2)
          {
             Console.WriteLine("Too many fails. Bail!");
             Console.ReadLine();
             return;
          }
       }
    }

    And this is the Visual Basic version. Note the When keyword after the Catch keyword:

    'Do something 10 times, bail after 3 errors.
    For X As Integer = 0 To 9
       Try
          Console.WriteLine("Try something.")
          'This operation will fail.
          Throw New Exception()
       Catch ex As Exception When X < 3
          Console.WriteLine("Failed!")
       Catch ex As Exception
          Console.WriteLine("Too many fails. Bail!")
          Return
       End Try
    Next

    The way it should be.

  • Visual Basic: The most excellent code editor

    I can’t hide the fact that I have a childish love for Visual Basic. I think this is worth a few blog posts. Than language and the code editor together works so incredible well for me. The language provides code blocks with keywords for opening and closing, so that you can read out what kind of block is closing. Because of this, the code editor knows about your intentions. Also, the C# editor cannot know if you intend to use curly brackets or not, because they are optional if only one statement will be contained within a block. In C#, to do an iteration with a test in, the iteration and its brackets has to be typed out, and then the test and its brackets has to be typed out.

    In Visual Basic, I just write the iteration opening, and when hitting Enter, the editor closes my iteration, does the indentation and places the cursor within, so that I can continue writing my test. Again, I just write the opening part of the test and hit Enter, and the editor closes it, does the indentation and place my cursor within the new block.

    for (int a = 0; a <= 10; a++)
    {
       if (true)
       {
          //Alcatraz style 
       }
    }
     
    For A As Integer = 0 To 10
      If True Then
         'Quick and nice!            
      End If
    Next

    Also, what } actually means, might depend. Yes, it is a closing block, but what block? In Visual Basic, the block closers are nice and readable. Next is closing For, End While is a closing While, End If is a closing If, and so on.

  • PowerShell knows about your USB devices

    One of many things you can do with the Management assembly is to get the USB devices that is currently connected to your computer. To load the Management assembly, use this line of code (no line break here):

    [System.Reflection.Assembly]::Load("System.Management, Version=2.0.0.0,
    Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")

    The class you want to create an instance from is called ManagementClass, and to its constructor you pass the management path that you want to use. USB devices are located in the Win32_USBHub path, so that is the argument that I pass to the constructor.

    $Man = New-Object System.Management.ManagementClass("Win32_USBHub")

    The GetInstances function returns a collection of objects, each object representing a device that actually is connected. Just for being crazy, I will make my target variable type safe.

    [System.Management.ManagementObjectCollection]$Devs = $Man.GetInstances()

    Now I can use ForEach-Obect cmdlet to iterate through the collection. For each device, I will write out the name of the device, the system ID and a blank line.

    $Devs | ForEach-Object {
    	Write-Output $_.GetPropertyValue("Name").ToString()
    	Write-Output $_.GetPropertyValue("DeviceID").ToString()
    	Write-Output ""
    }

    Finally, I have to free the resouces I have used.

    $Devs.Dispose()
    $Man.Dispose()

    When you run this code, you should see a list of devices that is registered as connected to your machine, including the USB hubs. If you connect a device and run the script again, that device will show up in the list. With this code as base, you could easily write programs that detects changes to the list. That is, programs that detects when a new device is added or removed. The last item should be the device you inserted while your computer was running, and the first items are the devices that were available at system startup.

  • Adding references to custom types

    In a great number of blog posts, I have used the Load function of System.Reflection.Assembly to load types from the .NET Framework. This (without line break) is an example that gives you access to the Forms library…

    [System.Reflection.Assembly]::Load("System.Windows.Forms, Version=2.0.0.0,
    Culture=neutral, PublicKeyToken=b77a5c561934e089")

    …so that calls like this is possible:

    [System.Windows.Forms.MessageBox]::Show("Hello!")

    (To see the available assemblies, check the assembly folder in your Windows folder.)

    When you use the Add-Type cmdlet to create your own types, the string that describes the type might need references as well. The required assemblies are specified in an array, and passed to the cmdlet as the -ReferencedAssemblies argument. This code adds a custom type…

    $references = @("System.Windows.Forms")
    Add-Type -ReferencedAssemblies $references @'
    public class Test
    {
       public void hej()
       {
          System.Windows.Forms.MessageBox.Show("Hello!");
       }
    }
    '@

    …gives you a code that when invoked, does the same thing:

    $test = New-Object Test
    $test.hej()

    The problem will show up if you have made any changes to your type and run your program again. The type called Test will already be loaded, so the Add-Type cmdlet will fail.

    (If you run your program again, without changing your custom type definition, Add-Type will just be ignored – your type is there and everything is fine.)

    Since types cannot be unloaded, you will need to unload your entire appdomain, and the easiest way to do this, is to close your PowerShell window. So any changes to a custom type, will be reflected in a new instance of PowerShell, thus in a new appdomain.

  • Environment variables

    Assuming that you are running Windows 7, the environment variables can be manually accessed if you right click on Computer, and select Properties. From there, you click Advanced system settings and on the Advanced tab, you click the Environment variables button. You can check your current variables, edit them and add new variables.

    I am running a Swedish installation of Windows 7.

    To read them from Visual Basic, you just use the GetEnvironmentVariables function to retrieve the collection of registered variables. This example is written in VBx (Visual Basic 10):

    Console.WriteLine(
       Environment.GetEnvironmentVariables().
          Item("PROCESSOR_REVISION").ToString())

    Remember, when you write code to manipulate this collection, adding or changing values, you would normally want your code to run as a custom step in an MSI file, and not in a regular EXE.

  • Calling C functions

    Like I mentioned earlier, functions that only are exposed through an external .NET interface are unreachable from PowerShell, but can be called using reflection. But how about C functions?

    This is not a problem at all. Like always when you attempt to call a C function in a DLL, you must know how it is exposed. This is not unique for PowerShell. The name of the link library, the name of the entry point, and the parameter types. This gives you a huge number of functionality ready to call, including third party libraries and the Windows API.

    I am going to use PowerShell to move the mouse cursor to location 100, 100 (left, top). The SetCursorPos function takes two integer values (X and Y) and returns a boolean. According to the Windows API documentation, the function resides in a library called User32.dll.

    One way to do this, is to write Visual Basic code, use PowerShell to compile it to an assembly, and then use reflection to call it. But there is another way.

    Create one array of arguments, and an array of argument types. In my case, since I’m calling the SetCursorPos function, this is what I need:

    $parameterTypes = [UInt32], [UInt32]
    $parameters = 100, 100

    Then, the rest of the code is something written by Jouko Kynsijärvi, that Lee Holmes used to make the Invoke-Win32 function. This is my complete code. Three lines! Check this out!

    #The parameter types.
    $parameterTypes = [Int], [Int]
    
    #The arguments.
    $parameters = 100, 100
    
    #The call. Library, return type, function name, types and values.
    Invoke-Win32 "User32.dll" ([Bool]) "SetCursorPos" $parameterTypes $parameters

    The rest of the listing is the definition of the Invoke-Win32 function that I extracted from this Lee Holmes’ post.

    As you run this script, note how the mouse cursor jumps up to the upper left corner, 100 pixels from the left edge, 100 pixels from the top.

    (I have a huge smile across my face when I’m writing this.)

  • .NET and speed: An int is just an int

    So what is true about .NET and preformance? As long as you treat the an int as an int, there is no COM overhead. From a new post by Roger Alsing:

    .NET have specific IL op codes in order to deal with primitives, and those opcodes will translate to pure machine code.

    Also:

    The value hex 7B (dec 123) is moved directly into the memory slot for the local variable.

    Check out Roger’s blog.

  • Create an exe using PowerShell

    This is, from what I know, the lest code you will need to write, to make PowerShell create a exe-file that do what you want it to do. It uses the VB compiler that is installed together with the .NET Framework together with the VB-specific CreateCompiler function, also installed with the .NET Framework.

    Before you run it, make sure that the folder you write your exe to really exists. In my case, C:\temp.

    First, let’s load an assembly. Remember, no line breaks here.

    #Load the Visual Basic assembly go get the code
    #that creates a compiler.
    [System.Reflection.Assembly]::Load("Microsoft.VisualBasic, Version=8.0.0.0,
    Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")

    Then we create the objects we need. The second line will cause some problems. The object returned by the CreateCompiler function has a method that isn’t exposed, so we can’t call it directly. Also note that we are specifying an output path here.

    $VB = New-Object Microsoft.VisualBasic.VBCodeProvider
    $Compiler = $VB.CreateCompiler()
    $Params = New-Object System.CodeDom.Compiler.CompilerParameters
    $Params.GenerateExecutable = $true
    $Params.OutputAssembly = "C:\temp\myprogram.exe"

    This is the code I want in my exe:

    [String]$S = "Imports System`n"
    $S = $S + "Module MyModule`n"
    $S = $S + "Sub Main(ByVal Args() As String)`n"
    $S = $S + "Console.WriteLine(`"Hello! Press Enter!`")`n"
    $S = $S + "Console.ReadLine()`n"
    $S = $S + "End Sub`n"
    $S = $S + "End Module`n"

    Now, I must use reflection to call the unexposed method. In C# or VB, this is not a problem because we can use interfaces. PowerShell can’t. Since the method expects two arguments, I will create an array with the two elements. Then, the Invoke method takes the object where the function resides and the arguments. Typing is important so that the correct function overload will be found.

    #Extract the method "CompileAssemblyFromSource". (No line break here!)
    $CompileMethod=
    [System.CodeDom.Compiler.ICodeCompiler].GetMethod("CompileAssemblyFromSource")
    
    #We must pass in the parameters and the source
    #when calling.
    $Args = New-Object System.Object[] 2
    $Args[0] = [System.CodeDom.Compiler.CompilerParameters]$Params
    $Args[1] = $S
    $Res = $CompileMethod.Invoke($Compiler, $Args);
    
    $VB.Dispose()

    Now, you have your own executable file that greets you when you start it!

  • Visual Basic/PowerShell interaction

    Through the .NET Framework, Visual Basic can talk to PowerShell. If PowerShell is installed, you can add a reference to an assembly named System.Management.Automation. You will have to browse for it, and you will find it here:

    C:\Program Files\Reference Assemblies\Microsoft\WindowsPowerShell\v1.0

    Also, scripting needs to be activated in PowerShell.

    A RunSpace is a context where PowerShell scripts run. Any variables that are set in one runspace, can be read from that same runspace, but not any other runspace. Before the opening Using, I will create a variable (Result) that will hold the response from PowerShell.

    Dim Result As _
       System.Collections.ObjectModel.Collection(Of System.Management.Automation.PSObject)
    
     Using R As System.Management.Automation.Runspaces.Runspace = _
       System.Management.Automation.Runspaces.RunspaceFactory.CreateRunspace()

    Next, you open the runspace and create a pipeline.

    R.Open()
    Dim P As System.Management.Automation.Runspaces.Pipeline = R.CreatePipeline()

    The pipeline has a Commands collection where you add your commands or complete scripts. These two lines will create two output objects.

    P.Commands.Add("C:\test.ps1")

    When you’re done, you can execute the script using the Invoke function of the pipeline object, and close your runspace. The response is saved in the Result variable I created earlier.

    Result = P.Invoke()
    R.Close()
    End Using
    
    For Each Res As System.Management.Automation.PSObject In Result
       MessageBox.Show(Res.ToString())
    Next

    The content of my script file, test.ps1, is:

    Write-Output "Hello!"
    $x = 10 + 3
    Write-Output $x

    The output of course will be one message box saying Hello! and another saying 13.

  • Easy archiving of files using PowerShell

    This example shows easy compressing and archiving of files using the WindowsBase library and PowerShell. This code will use the WindowsBase library to create a ZIP archive from a couple of images. In this example, I am working in the C root, and the files I want to add to my ZIP archive are also located there.

    #Load some assemblys. (No line break!)
    [System.Reflection.Assembly]::Load("WindowsBase,
       Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35")
    
    #Create a zip file named "MyZipFile.zip". (No line break!)
    $ZipPackage=[System.IO.Packaging.ZipPackage]::Open("C:\MyZipFile.zip",
       [System.IO.FileMode]"OpenOrCreate", [System.IO.FileAccess]"ReadWrite")
    
    #The files I want to add to my archive:
    $files = @("/Penguins.jpg", "/Lighthouse.jpg")
    
    #For each file you want to add, we must extract the bytes
    #and add them to a part of the zip file.
    ForEach ($file In $files)
    {
       $partName=New-Object System.Uri($file, [System.UriKind]"Relative")
       #Create each part. (No line break!)
       $part=$ZipPackage.CreatePart($partName, "application/zip",
          [System.IO.Packaging.CompressionOption]"Maximum")
       $bytes=[System.IO.File]::ReadAllBytes($file)
       $stream=$part.GetStream()
       $stream.Write($bytes, 0, $bytes.Length)
       $stream.Close()
    }
    
    #Close the package when we're done.
    $ZipPackage.Close()

    Now, my image files are archived to one ZIP file.

  • Reacting to user input

    Continued from here.

    The concept of events is that when a GUI component (a “control”) reacts on something like user actions, the control has the power to inform anyone who wants to know about that action. This is the event system of the .NET Framework. Thanks to delegates, the component can have a PowerShell function invoked. I want to add a button to my form, and then, I want a function to be called when the button is clicked.

    To start, before the ShowDialog call, I create a button and add that to the form.

    #Addition: Create a button and add it to the form.
    $myButton=New-Object Windows.Forms.Button
    $myButton.Text="Click me!"
    $myButton.Location=New-Object Drawing.Point(200,60)
    $myForm.Controls.Add($myButton)

    Now, before we add the function that will be called when the button is clicked, we need to add code to register events. In C#, we can add delegates to a list and in Visual Basic, we can call a member function for this. In PowerShell, there are a few steps that must be taken. Get an event reference, create a delegate and connect a function. The MSDN blogger Brett Ernst has written a function for this, that I add to my script.

    This function takes the object we want to listen to, the name of the event that will cause our function to be called, and the actual function that will be called.

    #Addition: Brett Ernst's function for adding an event handler.
    function AddHandler([object]$target,[string]$eventName,$script)
    {
    $evt = $target.GetType().GetEvent($eventName)
    $eh = [EventHandler]$script
    $del = [Delegate]::CreateDelegate($evt.EventHandlerType,$eh.Target,$eh.Method)
    $evt.AddEventHandler($target,$del)
    }

    This is my function. It extracts the user input from the text field and displays it in a message box.

    #Create the target function.
    $myHandler={
    
    #Exctract the user text from the text field.
    $userInput=$someField.Text
    
    #Show the text in a messagebox.
    [Windows.Forms.MessageBox]::Show($userInput)
    }

    This is the final row that I add before the existing ShowDialog call. It uses the AddHandler function to connect my function with the Click event of the button.

    #Event handling: Connect a function to a control event.
    AddHandler $myButton "Click" $myHandler

    This is the complete code:

    #Remenber: No line break here!
    [System.Reflection.Assembly]::Load("System.Windows.Forms, 
    Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")
    
    $myForm=New-Object Windows.Forms.Form
    $myForm.Size=New-Object Drawing.Size(360,200)
    $myForm.Text="Using Windows GUI from PowerShell"
    
    $someLabel=New-Object Windows.Forms.Label
    $someLabel.AutoSize=$true
    $someLabel.Text="Enter your name:"
    $someLabel.Location=New-Object Drawing.Point(10,10)
    
    $someField=New-Object Windows.Forms.TextBox
    $someField.Size=New-Object Drawing.Size(300,16)
    $someField.Location=New-Object Drawing.Point(10,30)
    
    $myForm.Controls.Add($someLabel)
    $myForm.Controls.Add($someField)
    
    #Addition: Create a button and add it to the form.
    $myButton=New-Object Windows.Forms.Button
    $myButton.Text="Click me!"
    $myButton.Location=New-Object Drawing.Point(200,60)
    $myForm.Controls.Add($myButton)
    
    #Addition: Brettern's function for adding an event handler.
    function AddHandler([object]$target,[string]$eventName,$script)
    {
    $evt = $target.GetType().GetEvent($eventName)
    $eh = [EventHandler]$script
    $del = [Delegate]::CreateDelegate($evt.EventHandlerType,$eh.Target,$eh.Method)
    $evt.AddEventHandler($target,$del)
    }
    
    #Create the target function.
    $myHandler={
    
    #Exctract the user text from the text field.
    $userInput=$someField.Text
    
    #Show the text in a messagebox.
    [Windows.Forms.MessageBox]::Show($userInput)
    }
    
    #Event handling: Connect a function to a control event.
    AddHandler $myButton "Click" $myHandler
    
    $myForm.ShowDialog()

    And this is the result:

    And now I take a two week vacation from blogging. I will have guests from the other side of the planet, and I will work with my podcast during their stay.

  • Using the Graphical User Interface

    If you are doing this as a script, you must have given yourself the permission execute scripts.

    To start, you must load the library that holds the classes that are used for GUI programming. Remember, you cannot do a line break here. I only do it so that the whole line will visible.

    [System.Reflection.Assembly]::Load("System.Windows.Forms,
    Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")

    (Again, the above code is one single line.)

    If you are unsure about versions and public keys, check your assembly folder in your Windows folder. If you right click on an assembly, and open the Properties dialog. There you highlight and copy the assambly information.

    When the assembly is loaded, you can create a Form. This code will give it a caption and a size.

    $myForm=New-Object Windows.Forms.Form
    $myForm.Size=New-Object Drawing.Size(360,200)
    $myForm.Text="Using Windows GUI from PowerShell"

    The next thing I want to do, is to add a text label and a text input fileld on my form. I will position the text field under my label field.

    $someLabel=New-Object Windows.Forms.Label
    $someLabel.AutoSize=$true
    $someLabel.Text="Enter your name:"
    $someLabel.Location=New-Object Drawing.Point(10,10)
    
    $someField=New-Object Windows.Forms.TextBox
    $someField.Size=New-Object Drawing.Size(300,16)
    $someField.Location=New-Object Drawing.Point(10,30)
    
    $myForm.Controls.Add($someLabel)
    $myForm.Controls.Add($someField)

    To show this form, call the ShowDialog function of the form object.

    $myForm.ShowDialog()

    This is the result:

    The next thing to do, is to react on user input.

  • Getting information

    The cmdlet for finding out what capabilities (members) an object have, is called Get-Member. You can pass any object to this cmdlet, and you can filter its return. This will give all members of a regular string object:

    Get-Member -InputObject "Hello"

    This will only display the properties, not for example the functions:

    Get-Member -InputObject "Hello" -MemberType Properties

    And this will display all the capabilities of a Uri object:

    $x=New-Object System.Uri("http://www.winsoft.se/")
    Get-Member -InputObject $x

    The Environment class in the System namespace holds all known information about the local machine and its operating system. This will display the name of the local computer:

    [System.Environment]::MachineName

    And this will display the version of your operating system:

    [System.Environment]::OSVersion

    MachineName and OSVersion are examples of class members, and they can be displayed aswell. To just show the class members of a string object, type:

    Get-Member -InputObject "Hello" -Static

    However, if you can’t get a reference to the objekt, you can’t use the Get-Member cmdlet. So the Get-Member cannot tell what the Environment class holds, because you can’t create an instance from that class. Reading the MSDN documentation seems to be the best way to get information. If someone knows a nice trick here, please post a comment.

  • Drag and drop GDI+ objects on a Panel

    This adventure takes place on a Panel that resides on a Form. I have a class that represents a GDI+ object (Thing). The Draw method that does the graphical representation of the object is very, very primitive, just enough to make it visible.

    Public Class Thing
    
       Private m_X As Integer
       Private m_Y As Integer
       Private m_Width As Integer
       Private m_Height As Integer
       Private m_IsDragging As Boolean
    
       Public Sub New(ByVal Rnd As Random, ByVal Width As Integer, _
    ByVal Height As Integer)
          Me.m_X = Rnd.Next(Width - 50)
          Me.m_Y = Rnd.Next(Height - 25)
          Me.m_Width = 100
          Me.m_Height = 50
       End Sub
    
       Public ReadOnly Property CenterX() As Integer
          Get
             Return Me.X + CType(Me.Width / 2, Integer)
          End Get
       End Property
    
       Public ReadOnly Property CenterY() As Integer
          Get
             Return Me.Y + CType(Me.Height / 2, Integer)
          End Get
       End Property
    
       Public Function GetDistance(ByVal FromX _
    As Integer, ByVal FromY As Integer) As Double
          Dim DistX As Double = Math.Abs(Me.CenterX - FromX)
          Dim DistY As Double = Math.Abs(Me.CenterY - FromY)
          Dim Dist As Double = (DistX + DistY)
          If Dist = 0 Then
             Return 0
          Else
             Return Dist / 2
          End If
       End Function
    
       Public Property X() As Integer
          Get
             Return Me.m_X
          End Get
          Set(ByVal value As Integer)
             Me.m_X = value
          End Set
       End Property
    
       Public Property Y() As Integer
          Get
             Return Me.m_Y
          End Get
          Set(ByVal value As Integer)
             Me.m_Y = value
          End Set
       End Property
    
       Public Property Width() As Integer
          Get
             Return Me.m_Width
          End Get
          Set(ByVal value As Integer)
             Me.m_Width = value
          End Set
       End Property
    
       Public Property Height() As Integer
          Get
             Return Me.m_Height
          End Get
          Set(ByVal value As Integer)
             Me.m_Height = value
          End Set
       End Property
    
       Public Property IsDragging() As Boolean
          Get
             Return Me.m_IsDragging
          End Get
          Set(ByVal value As Boolean)
             Me.m_IsDragging = value
          End Set
       End Property
    
       Public Sub Draw(ByVal G As System.Drawing.Graphics)
          G.FillRectangle(Brushes.Green, Me.X, Me.Y, Me.Width, Me.Height)
          G.DrawRectangle(Pens.Black, Me.X, Me.Y, Me.Width, Me.Height)
          If Me.IsDragging Then
             G.DrawRectangle(Pens.Black, Me.X - 2, Me.Y - 2, Me.Width + 4, Me.Height + 4)
          End If
       End Sub
    
       Public Function HitTest(ByVal PosX As Integer, ByVal PosY As Integer) As Boolean
          Return (PosX >= Me.X _
    AndAlso PosX <= (Me.X + Me.Width) _
    AndAlso PosY >= Me.Y AndAlso PosY <= (Me.Y + Me.Height))
       End Function
    
    End Class
    

    The ThingList keeps track of all dragable objects, and makes sure that all are positioned within the visible area of the Panel.

    Public Class ThingList
       Inherits System.Collections.CollectionBase
    
       Public Function Add(ByVal O As Thing) As Integer
          Return List.Add(O)
       End Function
    
       Default Public ReadOnly Property Item(ByVal Index As Integer) As Thing
          Get
             Return CType(List(Index), Thing)
          End Get
       End Property
    
       Public Sub Draw(ByVal G As System.Drawing.Graphics)
          For Each O As Thing In Me
             O.Draw(G)
          Next
       End Sub
    
       Public Function GetObjectAt(ByVal MouseX As Integer, ByVal MouseY As_
     Integer) As Thing
          If Me.Count > 0 Then
             For Each O As Thing In Me
                If O.HitTest(MouseX, MouseY) Then
                   Return O
                End If
             Next
             Return Nothing
          Else
             Return Nothing
          End If
       End Function
    
       Public Function GetObjectIfClose(ByVal MouseX As Integer, _
    ByVal MouseY As Integer) As Thing
          If Me.Count > 0 Then
             Dim CloseIndex As Integer = -1
             Dim CloseDistance As Double = 60
             For I As Integer = 0 To Me.Count - 1
                Dim Distance As Double = Me(I).GetDistance(MouseX, MouseY)
                If Distance < CloseDistance Then
                   CloseDistance = Distance
                   CloseIndex = I
                End If
             Next
             If CloseIndex >= 0 Then
                Return Me(CloseIndex)
             Else
                Return Nothing
             End If
          Else
             Return Nothing
          End If
       End Function
    
       Public Sub ResetIsDragging()
          For Each O As Thing In Me
             O.IsDragging = False
          Next
       End Sub
    
       Public Function MoveToVisibleArea(ByVal S As Size) As Boolean
          Dim Ret As Boolean = False
          For Each O As Thing In Me
             If O.X < 0 Then
                O.X += 2
                Ret = True
             End If
             If O.Y < 0 Then
                O.Y += 2
                Ret = True
             End If
             If (O.X + O.Width) > S.Width Then
                O.X -= 2
                Ret = True
             End If
             If (O.Y + O.Height) > S.Height Then
                O.Y -= 2
                Ret = True
             End If
          Next
          Return Ret
       End Function
    
    End Class
    

    The form (contains a panel named Panel1) basically keeps track of mouse actions. This does not include the drag and drop events of the Control class, because that deals with dragging and dropping controls, not GDI+ objects.

    Public Class Form1
    
       Private L As ThingList
       Private IsDragging As Boolean
       Private DragObject As Thing = Nothing
       Private DragOffsetX As Integer
       Private DragOffsetY As Integer
    
       Private Sub Form1_Load(ByVal sender As _
    System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
          L = New ThingList()
          Dim Rnd As New Random()
          L.Add(New Thing(Rnd, Panel1.Width, Panel1.Height))
          L.Add(New Thing(Rnd, Panel1.Width, Panel1.Height))
          L.Add(New Thing(Rnd, Panel1.Width, Panel1.Height))
       End Sub
    
       Private Sub Panel1_MouseDown(ByVal sender As Object, _
    ByVal e As System.Windows.Forms.MouseEventArgs) Handles Panel1.MouseDown
          Me.DragObject = L.GetObjectIfClose(e.X, e.Y)
          If Not DragObject Is Nothing Then
             Me.DragOffsetX = e.X - Me.DragObject.X
             Me.DragOffsetY = e.Y - Me.DragObject.Y
             Me.DragObject.IsDragging = True
             Me.IsDragging = True
             Panel1.Invalidate()
          End If
       End Sub
    
       Private Sub Panel1_MouseMove(ByVal sender As Object, _
    ByVal e As System.Windows.Forms.MouseEventArgs) Handles Panel1.MouseMove
          If Me.IsDragging And Not Me.DragObject Is Nothing Then
             Me.DragObject.X = e.X - Me.DragOffsetX
             Me.DragObject.Y = e.Y - Me.DragOffsetY
             Panel1.Invalidate()
          End If
       End Sub
    
       Private Sub Panel1_MouseUp(ByVal sender As Object, _
    ByVal e As System.Windows.Forms.MouseEventArgs) Handles Panel1.MouseUp
          If Me.IsDragging Then
             Me.IsDragging = False
             L.ResetIsDragging()
             Me.DragObject = Nothing
          End If
          L.MoveToVisibleArea(Panel1.Size)
          Panel1.Invalidate()
       End Sub
    
       Private Sub Panel1_Paint(ByVal sender As System.Object, _
    ByVal e As System.Windows.Forms.PaintEventArgs) Handles Panel1.Paint
          e.Graphics.FillRectangle(Brushes.White, 0, 0, Me.Width, Me.Height)
          L.Draw(e.Graphics)
       End Sub
    
       Private Sub Panel1_Resize(ByVal sender As Object, _
    ByVal e As System.EventArgs) Handles MyBase.Resize
          If Not L Is Nothing Then
             If L.MoveToVisibleArea(Panel1.Size) Then
                Panel1.Invalidate()
             End If
          End If
       End Sub
    
    End Class
    

    Now you can play around with three green boxes in the panel.

  • Word wrapping

    One limitation of the Command Line Interface control, is that it could only display as long strings of text as it’s width in characters at a time. The following text would be cut off just after “I like the way”:

    Dim S As New System.Text.StringBuilder()
    S.Append("Just gonna stand there and watch me burn ")
    S.Append("That's all right because I like the way it hurts ")
    S.Append("Just gonna stand there and hear me cry ")
    S.Append("That's all right because I love the way you lie ")
    S.Append("I love the way you lie")
    Cli1.WriteLines(S.ToString())

    Now, the WriteLines function also takes a boolean, and when True, the text will be devided into several lines, without breaking any words.

    Cli1.WriteLines(True, S.ToString())

    The CLI Control can be downloaded from here.

  • Keep track on USB devices

    Microsoft provides a library for talking to USB devices as part of the .NET Framework. This is just one thing you can do with the versatile System.Management namespace. If you want to keep track on the units that are connected or removed from a computer, you can use this library for regular checks. This code, lists the name and ID of all connected devises. The code requires a reference to the System.Management namespace:

    Using Mn As New System.Management.ManagementClass("Win32_USBHub")
       Using Devs As System.Management.ManagementObjectCollection _
          = Mn.GetInstances()
          For Each Dev As System.Management.ManagementObject In Devs
             Console.WriteLine(Dev.GetPropertyValue("Name").ToString())
             Console.WriteLine(Dev.GetPropertyValue("DeviceID").ToString())
          Next
       End Using
    End Using

    My code is written in an console application. The result will be a list of connected USB device names and their unique ID. Have fun!

  • For Each

    The ForEach keyword is used to iterate through a collection of objects that you have a reference to. You can get a reference to a collection by calling a function or by declaring and initializing an array. This example will give you an array of strings in a variable called $arr:

    $arr = "A", "B", "C"

    If you want to do something with each element in the array, the ForEach keyword is used. This example just writes out each element:

    ForEach ($x In $arr) {Write-Output $x}

    Sending data to the next object in the pipeline (that will be displayed in the console window if not picked up) is the default behaviour, so Write-Output can be ommited in this case.

    ForEach ($x In $arr) {$x}

    The result will be:

    A
    B
    C

    This works like the For Each keyword in Visual Basic, so you could do something with each element within the curly brackets. This will display the lower case version before the upper case version of each element:

    ForEach ($x In $arr) {$x.ToLower(); $x}

    The result:

    a
    A
    b
    B
    c
    C

    The ForEach-Object cmdlet can iterate through any collection of objects that is piped in. It works in the same way, but now you don’t have to specify the collection or the variable that will represent the elements. The collection is whatever is piped in, and the variable that represent the elements (I used $x in my examples) will be the “this token” ($_).

    This will add all running processes to the pipeline:

    Get-Process

    And this will give you the posibility to reference each process.

    Get-Process | ForEach-Object { Write-Host $_.Name }

    Get-Process cmdlet will send some process objects to the pipeline, they are picked up by the ForEach-Object cmdlet, and the names of the processes are sent to the pipeline. Since nothing picks up the names, the names will be displayed.

  • There is nothing that can’t be done with PowerShell

    Basically, what makes PowerShell a so much better command line shell and scripting language than its competitors, is that you can do anything and everything. If you want to create scripts, you must give yourself permission to do so (shown here). In addition, if you are using Windows 7 or later, you must start PowerShell as an administrator to be able to give yourself permission to run scripts.

    The secrets behind the versatility of PowerShell is the power of the syntax, excellent type management, and access to both COM components and the .NET Framework. My twitter example is really just an example of accessing the .NET Framework from PowerShell. I could just as well have shown how to convert a JPG image to PNG, which by the way could be done like this:

    #Load the Drawing library (no Enter strokes here):
    [System.Reflection.Assembly]::Load("System.Drawing, Version=2.0.0.0, 
    Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")
    
    #Load a JPG.
    $img=New-Object System.Drawing.Bitmap("C:\Anders\mypicture.jpg")
    
    #Save the desiered format in a variable.
    $format=[System.Drawing.Imaging.ImageFormat]::Png
    
    #Save as PNG.
    $img.Save("C:\Anders\converted.png", $format)
    
    #Delete the object.
    $img.Dispose()

    So, let’s say that you want to access a COM object from PowerShell. You would still use the New-Object, but you append the -ComObject argument. This gives me a handle to Excel (if you have it installed):

    $xl=New-Object -ComObject Excel.Application

    Now, you have state of the art spread sheet automation at your fingertips. You can display it like so:

    $xl.Visible=$true

    How about that!?

  • Checking a twitter feed using PowerShell

    To check a twitter feed using PowerShell, you must have an URL to an XML feed (probably RSS). Open the web site of the account you’re interested in (http://www.twitter.com/username/) and find the RSS link. Mine is http://twitter.com/statuses/user_timeline/33177615.rss.

    You can load the URL into a variable like so:

    $url="http://twitter.com/statuses/user_timeline/33177615.rss"

    Then, the Net assembly must be loaded. Use the Load function of the System.Reflection.Assembly class (without inserting any Enter strokes).

    [System.Reflection.Assembly]::Load("System.Net, 
    Version=3.5.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")

    If you’re not sure about public key token or version, check you assembly folder in your Windows installation folder. Next, you create a web client from the assembly that you just loaded.

    $wcli=New-Object System.Net.WebClient

    Use the OpenRead function of the web client to acquire a web stream.

    $s=$wcli.OpenRead($url)

    Use the stream object to create a stream reader.

    $r=New-Object System.IO.StreamReader($s)

    To save the result stream data in a variable, call the ReadToEnd function of the reader. You then have to close the reader and destroy the web client.

    $response=$r.ReadToEnd()
    $r.Close()
    $wcli.Dispose()

    You can just type the name of the variable to see its content.

    $response

    You should now see my twitter feed!

  • Getting started with Silverlight in an existing web application

    To get things started, I will show how to enhance a web application with a Silverlight object, and how to pass parameters to that object. To be able to follow, make sure that you have the Silverlight runtime installed. Also, you must have an existing ASP.NET Web Application loaded in Visual Studio 2010. If you’re using Visual Studio 2008, there is an Silverlight addon available for download from Microsoft.

    Adding a Silverlight object and passing data to it
    I want to have a Silverlight object on a sub page, so I add a new ASPX page to my web application called sl.aspx. Also, I create a link to sl.aspx from my default page. I want my Silverlight object to accept a QueryString argument, so I pass one in my link:

    <a href="sl.aspx?param=hello">Click here!</a>

    1. Add a new Silverlight project to your solution. I use the name MySL for mine. Default, a test page is added. I unchecked the option to make the test page my start page.

    2. The test page is a good help to copy the HTML code that is required to show the object from. The two JavaScript blocks goes in the head section and the OBJECT tag goes where you want your Silverlight object. Grab the DIV tag that contains the OBJECT tag and the IFRAME tag.

    Now you’re done with adding the object. If you test your application, and click on your link, your (empty) Silverlight object.

    3. I want to show the QueryString parameter in a textbox, so I add one to my Silverlight object (TextBox1). This is the code to grab the QueryString parameter and putting it in the textbox:

    Private Sub MainPage_Loaded(ByVal sender As Object, _
    ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded
       TextBox1.Text = _
       System.Windows.Browser.HtmlPage.Document.QueryString("param")
    End Sub

    The result of course, is the word “hello” in the textbox.