Category: Microsoft .NET

  • Refresh denormalized fields

    I just had to share this beautiful SQL Server query that I composed today. It refreshes denormalized fields!

    UPDATE DestinationTable SET DestinationTable.Field=SourceTable.Field
    FROM dbo.DestinationTableName AS DestinationTable
    INNER JOIN dbo.SourceTableName AS SourceTable
    ON SourceTable.PK=DestinationTable.FK

    In other words, it copies the value from one column in one table to another column in another table, where the keys match (specified after ON). Beautiful! I use Microsoft SQL Server 2008, but I’m sure this works in 2005 too.

  • Compressing a web request

    Perhaps you remember my old GZip example that illustrated how to use the GZip compression feature of the .NET Framework. To follow, read the Main function. It starts with a 118 character string that is compressed to a array of 208 bytes, than decompressed and displayed.

    (The functions are not changed since wrote about them the last time.)

    Module Module1
    
        Sub Main()
    
            'Create some text.
          Dim S As String = "This is some text that I want to compress. " & _
          "Preferably it's a long string loaded from a text file or some XML document."
          Console.WriteLine("Original string charachter count: {0}", S.Length)
    
            'Assign the compressed version to the variable B.
          Dim B() As Byte = CompressText(S.ToString())
          Console.WriteLine("Compressed to bytes: {0}", B.Length)
    
            'Decompress it, and display the result.
          Dim Decompressed As String = DecompressText(B)
          Console.WriteLine("Decompressed text:")
            Console.WriteLine(Decompressed)
    
          Console.WriteLine()
          Console.Write("Press Enter to quit.")
          Console.ReadLine()
    
        End Sub
    
        Private Function CompressText(ByVal T As String) As Byte()
            Dim B() As Byte = System.Text.Encoding.UTF8.GetBytes(T)
            Using MemStream As New System.IO.MemoryStream()
                Using GZStream As New System.IO.Compression.GZipStream(MemStream, _
                 IO.Compression.CompressionMode.Compress)
                    GZStream.Write(B, 0, B.Length)
                    GZStream.Close()
                    Return MemStream.ToArray()
                End Using
            End Using
        End Function
    
        Private Function DecompressText(ByVal B() As Byte) As String
            Dim Result As New System.Text.StringBuilder()
            Using MemStream As New System.IO.MemoryStream(B)
                Using GZStream As New System.IO.Compression.GZipStream(MemStream, _
                 IO.Compression.CompressionMode.Decompress)
                    Do
                        Dim Buffer(1023) As Byte 'Note that this makes 1024 bytes in VB.
                        Dim BytesRead As Integer = GZStream.Read(Buffer, 0, 1024)
                        If BytesRead > 0 Then
                            Result.Append(System.Text.Encoding.UTF8.GetString(Buffer, 0, BytesRead))
                        End If
                        If BytesRead < 1024 Then
                            Exit Do
                        End If
                    Loop
                    GZStream.Close()
                    Return Result.ToString()
                End Using
            End Using
        End Function
    
    End Module
    

    You will need more data to get a positive effect of compression, and that is one thing to consider when you decide if to compress your data. Another thing to keep in mind is that compressed data isn’t searchable.

    If you were to build a web browser, one elementary thing that your program must be able to do, is to make a web request via http and download the response. This ability is also built in into the framework. This function (takes an URL and returns the HTML response) does just that:

    Private Function DoWebRequest(ByVal URL As String) As String
       Dim Result As String = ""
       Using Wc As New System.Net.WebClient()
          Dim S As System.IO.Stream = Wc.OpenRead(URL)
          Using R As New System.IO.StreamReader(S)
             Result = R.ReadToEnd()
          End Using
       End Using
       Return Result
    End Function

    Now, if I do a small change to the program, so that it downloads the response from a specific website, and compresses that, the numbers will be better. This is what the code looks like:

    Sub Main()
    
       'Create some text.
       Dim S As String = DoWebRequest("http://www.hurhomeopatifungerar.se/")
       Console.WriteLine("Original string charachter count: {0}", S.Length)
    
       'Assign the compressed version to the variable B.
       Dim B() As Byte = CompressText(S.ToString())
       Console.WriteLine("Compressed to bytes: {0}", B.Length)
     
       'Decompress it, and display the result.
       Dim Decompressed As String = DecompressText(B)
       Console.WriteLine("Decompressed text:")
       Console.WriteLine(Decompressed)
    
       Console.WriteLine()
       Console.Write("Press Enter to quit.")
       Console.ReadLine()
    
    End Sub

    This specific website gives a 2179 characters long response, that is compressed to 1359 bytes. This is the complete code:

    Module Module1
    
        Sub Main()
    
            'Create some text.
          Dim S As String = DoWebRequest("http://www.hurhomeopatifungerar.se/")
          Console.WriteLine("Original string charachter count: {0}", S.Length)
    
            'Assign the compressed version to the variable B.
          Dim B() As Byte = CompressText(S.ToString())
          Console.WriteLine("Compressed to bytes: {0}", B.Length)
    
            'Decompress it, and display the result.
          Dim Decompressed As String = DecompressText(B)
          Console.WriteLine("Decompressed text:")
            Console.WriteLine(Decompressed)
    
          Console.WriteLine()
          Console.Write("Press Enter to quit.")
          Console.ReadLine()
    
        End Sub
    
       Private Function DoWebRequest(ByVal URL As String) As String
          Dim Result As String = ""
          Using Wc As New System.Net.WebClient()
             Dim S As System.IO.Stream = Wc.OpenRead(URL)
             Using R As New System.IO.StreamReader(S)
                Result = R.ReadToEnd()
             End Using
          End Using
          Return Result
       End Function
    
        Private Function CompressText(ByVal T As String) As Byte()
            Dim B() As Byte = System.Text.Encoding.UTF8.GetBytes(T)
            Using MemStream As New System.IO.MemoryStream()
                Using GZStream As New System.IO.Compression.GZipStream(MemStream, _
                 IO.Compression.CompressionMode.Compress)
                    GZStream.Write(B, 0, B.Length)
                    GZStream.Close()
                    Return MemStream.ToArray()
                End Using
            End Using
        End Function
    
        Private Function DecompressText(ByVal B() As Byte) As String
            Dim Result As New System.Text.StringBuilder()
            Using MemStream As New System.IO.MemoryStream(B)
                Using GZStream As New System.IO.Compression.GZipStream(MemStream, _
                 IO.Compression.CompressionMode.Decompress)
                    Do
                        Dim Buffer(1023) As Byte 'Note that this makes 1024 bytes in VB.
                        Dim BytesRead As Integer = GZStream.Read(Buffer, 0, 1024)
                        If BytesRead > 0 Then
                            Result.Append(System.Text.Encoding.UTF8.GetString(Buffer, 0, BytesRead))
                        End If
                        If BytesRead < 1024 Then
                            Exit Do
                        End If
                    Loop
                    GZStream.Close()
                    Return Result.ToString()
                End Using
            End Using
        End Function
    
    End Module
    
  • Type inference in F#

    I have recently been to a short F# presentation at HiQ in Arboga. One of the things that got mentioned was type inference. Both Visual Basic and C# have type inference in their current version, but F# takes this one step further. This approach will produce two integers in VB when Option Infer is set to On:

    Dim X = 10
    Dim Y = 20

    This is the F# version of the above code:

    let mutable x=10
    let mutable y=20

    But when it comes to function declarations, VB is not support type inference anymore. This will not compile:

    Private Function DoSomething(ByVal X, ByVal Y)
       Return X
    End Function

    You will need to declare the input types and the return type, like so:

    Private Function DoSomething(ByVal X As Integer, ByVal Y As _
       Integer) As Integer
       Return X
    End Function

    In F#, type inference will work all the way. This is the F# version of the DoSomething function, with type inference:

    let DoSomething x y = x

    The DoSomething function can be called using any arguments. Type inference will take care of the argument and return typing. Once the function is called, the compiler knows what types the function will handle. Therefore, you can call the function using strings or integers but not a combination. Here, z1 will be a string and z2 will be an integer. This is the complete code listing:

    let mutable x=10
    let mutable y=20
    
    let DoSomething x y = x
    let z1 = DoSomething "winsoft" "rocks"
    let z2 = DoSomething 10 20

    Now, this is strange: If the types interact with each other, the first call will determine the types of the input and output. If I change my code, so that the function DoSomething returns x + y, only the first call will be accepted.

    let mutable x=10
    let mutable y=20
    
    let DoSomething x y = x + y
    let z1 = DoSomething "winsoft" "rocks"
    //let z2 = DoSomething 10 20

    The second call will fail, because the compiler in this case only provides a string version of the DoSomething function.

  • Writing a game using TurboSprite (2/2)

    Continued from here.

    Now I want to enable shooting. When the user presses the Control key, I create a bullet, sets its properties and adds it to the engine. This code is added to the KeyDown event. I have to modify the KeyUp event, because in the previous version, it unconditionally made the ship stop. Now when more keys are involved, I only want the ship to stop if it is the up or down buttons are released.

    This is the new version of the KeyDown event:

       Private Sub Form1_KeyDown(ByVal _
    sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles Me.KeyDown
          If e.KeyData = Keys.A Then
    
             'If user presses "a", move up!
             Me.PlayerMover.DestY = 0
             Me.PlayerMover.SpeedY = -2
    
          ElseIf e.KeyData = Keys.Z Then
    
             'If user presses "z", move down!
             Me.PlayerMover.DestY = SpriteSurface1.Height
             Me.PlayerMover.SpeedY = 2
    
          End If
    
          If (e.KeyData And Keys.ControlKey) = Keys.ControlKey Then
    
             'If user presses Control, fire!
             Dim Bullet As New SCG.TurboSprite.PolygonSprite(2, 0, -2, 1, -2, -1)
             Bullet.Position = New Point(Player.Position.X + 15, Player.Position.Y + 9)
             Bullet.Color = Color.Cyan
             SpriteEngineDestination1.AddSprite(Bullet)
             Dim BulletMover As SCG.TurboSprite.DestinationMover = _
    SpriteEngineDestination1.GetMover(Bullet)
             BulletMover.Destination = New Point(SpriteSurface1.Width + 5, _
    Bullet.Height)
             BulletMover.SpeedX = 4
    
          End If
       End Sub

    This is the new version of the KeyUp event:

       Private Sub Form1_KeyUp(ByVal sender As _
    Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles Me.KeyUp
    
          'Stop moving, but only if "a" or "z" is released.
          If e.KeyData = Keys.A Or e.KeyCode = Keys.Z Then
             Me.PlayerMover.SpeedY = 0
          End If
    
       End Sub

    Finally, when a bullet reaches its destination at the right end of the screen, I want it deleted. Check the SpriteReachedDestination event in the final code listing below.

    When this is all working, I want to add an enemy and use the collision detection to see if it was killed. I did not subclass the PolygonSprite, and this is really something you should do to be able to tag the sprites. The “ugly hack” of this post, must be that I use color to determine if the sprite is a bullet, or the enemy. This is the complete code:

    Public Class Form1
    
       'A reference to the player (created in the Shown event) and the mover.
       Private Player As SCG.TurboSprite.PolygonSprite
       Private PlayerMover As SCG.TurboSprite.DestinationMover
    
       Private Sub Form1_Shown(ByVal sender _
    As Object, ByVal e As System.EventArgs) Handles Me.Shown
    
          'Set the desired number of frames per second and activate the surface.
          SpriteSurface1.DesiredFPS = 40
          SpriteSurface1.Active = True
    
          'Create the player and save the reference.
          Me.Player = New SCG.TurboSprite.PolygonSprite(-20, -10, 20, 10, -20, 10)
    
          'Set player original position.
          Me.Player.Position = New Point(100, 100)
    
          'Set player color.
          Me.Player.Color = Color.Yellow
    
          'Add the player to the sprite engine.
          SpriteEngineDestination1.AddSprite(Me.Player)
    
          'Save a reference to the mover.
          Me.PlayerMover = SpriteEngineDestination1.GetMover(Me.Player)
    
          'Now, add an ENEMY!
          Dim Enemy As New SCG.TurboSprite.PolygonSprite(-30, 20, 0, -20, 30, 20)
          Enemy.Position = New Point(SpriteSurface1.Width, SpriteSurface1.Height)
          Enemy.Color = Color.Red
          SpriteEngineDestination1.AddSprite(Enemy)
          Dim EnenyMover As SCG.TurboSprite.DestinationMover = _
    SpriteEngineDestination1.GetMover(Enemy)
          EnenyMover.Speed = 1
          EnenyMover.Destination = New Point(-50, 100)
    
       End Sub
    
       Private Sub Form1_KeyDown(ByVal sender As _
    Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles Me.KeyDown
          If e.KeyData = Keys.A Then
    
             'If user presses "a", move up!
             Me.PlayerMover.DestY = 0
             Me.PlayerMover.SpeedY = -2
    
          ElseIf e.KeyData = Keys.Z Then
    
             'If user presses "z", move down!
             Me.PlayerMover.DestY = SpriteSurface1.Height
             Me.PlayerMover.SpeedY = 2
    
          End If
    
          If (e.KeyData And Keys.ControlKey) = Keys.ControlKey Then
    
             'If user presses Control, fire!
             Dim Bullet As New SCG.TurboSprite.PolygonSprite(2, 0, -2, 1, -2, -1)
             Bullet.Position = New Point(Player.Position.X + 15, Player.Position.Y + 9)
             Bullet.Color = Color.Cyan
             SpriteEngineDestination1.AddSprite(Bullet)
             Dim BulletMover As SCG.TurboSprite.DestinationMover = _
    SpriteEngineDestination1.GetMover(Bullet)
             BulletMover.Destination = New Point(SpriteSurface1.Width + 5, _
    Bullet.Height)
             BulletMover.SpeedX = 4
    
          End If
       End Sub
    
       Private Sub Form1_KeyUp(ByVal sender As Object, ByVal _
    e As System.Windows.Forms.KeyEventArgs) Handles Me.KeyUp
    
          'Stop moving, but only if "a" or "z" is released.
          If e.KeyData = Keys.A Or e.KeyCode = Keys.Z Then
             Me.PlayerMover.SpeedY = 0
          End If
    
       End Sub
    
       Private Sub SpriteEngineDestination1_SpriteReachedDestination(ByVal sender As _
    Object, ByVal e As SCG.TurboSprite.SpriteEventArgs) Handles SpriteEngineDestination1.SpriteReachedDestination
          'You really should subclass the bullet to be able to
          'tag it as a bullet. I use color. Hack!!!
          Dim P As SCG.TurboSprite.PolygonSprite = CType(e.Sprite, SCG.TurboSprite.PolygonSprite)
          If P.Color = Color.Cyan Then
             P.Kill()
             SpriteEngineDestination1.RemoveSprite(P)
          End If
       End Sub
    
       Private Sub SpriteSurface1_SpriteCollision(ByVal sender As _
    Object, ByVal e As SCG.TurboSprite.SpriteCollisionEventArgs) Handles SpriteSurface1.SpriteCollision
          'Did the player shoot the enemy? Is one a bullet and one the enemy?
          'Again, I use color. Hack!!!
          Dim FirstSprite As SCG.TurboSprite.PolygonSprite = CType(e.Sprite1, _
    SCG.TurboSprite.PolygonSprite)
          Dim SecondSprite As SCG.TurboSprite.PolygonSprite = CType(e.Sprite2, _
    SCG.TurboSprite.PolygonSprite)
          If FirstSprite.Color = Color.Cyan Then
             'We have a bullet.
             If SecondSprite.Color = Color.Red Then
                'And the enemy.
                SecondSprite.Kill()
                SpriteEngineDestination1.RemoveSprite(SecondSprite)
             End If
          ElseIf FirstSprite.Color = Color.Red Then
             'We have the enemy.
             If SecondSprite.Color = Color.Cyan Then
                'And a bullet.
                FirstSprite.Kill()
                SpriteEngineDestination1.RemoveSprite(FirstSprite)
             End If
          End If
       End Sub
    
    End Class
    

    Again, subclass and add your own properties! Do not use color to determine what sprite you are dealing with. This is the result:

    Thank you, TurboSprite!

  • Writing a game using TurboSprite (1/2)

    There are two things to take away from this post. The ease of TurboSprite and the power and speed of GDI+. Of course, you are still supposed to write games using hardware acceleration, but you can do decent desktop games without DirectX, XNA or OpenGL.

    In this first part, I will create a player (a spaceship) that can respond to keyboard control. In the second part, the player will be able to shoot and kill enemies.

    To start off, I create a project, I add a sprite surface and an sprite engine destination. I connect them to each other by setting the Surface property of the engine. Also, I intend to use collision detection, so I set the DetectCollisionSelf property to True.

    On the surface, I set the AutoBlank property to True and the AutoBlankColor property to Black. On the form, I set KeyPreview to True.

    Note that so far, all the magic is happening in KeyDown, KeyUp (input feedback) and Shown (initialization).

    Public Class Form1
    
       'A reference to the player (created in the Shown event) and the mover.
       Private Player As SCG.TurboSprite.PolygonSprite
       Private PlayerMover As SCG.TurboSprite.DestinationMover
    
       Private Sub Form1_Shown(ByVal sender As Object, ByVal e As _
    System.EventArgs) Handles Me.Shown
    
          'Set the desired number of frames per second and activate the surface.
          SpriteSurface1.DesiredFPS = 40
          SpriteSurface1.Active = True
    
          'Create the player and save the reference.
          Me.Player = New SCG.TurboSprite.PolygonSprite(-20, -10, 20, 10, -20, 10)
    
          'Set player original position.
          Me.Player.Position = New Point(100, 100)
    
          'Set player color.
          Me.Player.Color = Color.Yellow
    
          'Add the player to the sprite engine.
          SpriteEngineDestination1.AddSprite(Me.Player)
    
          'Save a reference to the mover.
          Me.PlayerMover = SpriteEngineDestination1.GetMover(Me.Player)
    
       End Sub
    
       Private Sub Form1_KeyDown(ByVal sender As Object, ByVal _
    e As System.Windows.Forms.KeyEventArgs) Handles Me.KeyDown
          If e.KeyData = Keys.A Then
    
             'If user presses "a", move up!
             Me.PlayerMover.DestY = 0
             Me.PlayerMover.SpeedY = -2
    
          ElseIf e.KeyData = Keys.Z Then
    
             'If user presses "z", move down!
             Me.PlayerMover.DestY = SpriteSurface1.Height
             Me.PlayerMover.SpeedY = 2
    
          End If
       End Sub
    
       Private Sub Form1_KeyUp(ByVal sender As Object, ByVal _
    e As System.Windows.Forms.KeyEventArgs) Handles Me.KeyUp
    
          'Stop moving!
          Me.PlayerMover.SpeedY = 0
    
       End Sub
    
    End Class
    

    Continued here.

  • TurboSprite

    TurboSprite is a software driven (GDI+) sprite engine written by Dion Kurczek in C#. The reason that I’m picking this up, is that it shows (like I have mentioned before) the amazing capabilities and performance of the GDI+ library in .NET. TurboSprite provides a sprite container, bitmap sprites, vector sprites and collision detection.

    To be able to use TurboSprite, download and compile it, add the components to your toolbox. Then, add a surface and an engine to a form. Note that you have two engines. One is called SpriteEngine and another is called SpriteEngineDestination. Use the SpriteEngineDestination object, because it extends the SpriteEngine class with the ability to move sprites. You might want to set a few properties to connect the engine to the surface, to tell the engine if you want collision detection and so on. Collision detection is a reasonable cause for using a sprite engine. I use the AutoBlank feature of the surface.

    About the moving of the sprites, you can acquire the sprite mover using the GetMover function for the engine (if you use the SpriteEngineDestination), and set the X and Y speed of a sprite. Or you can do as I do in this example below. That is, just set a speed and a destination position. The destination position determines the sprite movement direction.

    This code does two thinks (written in the Show event of a regular form). The first line activates the sprite engine so that sprites will move. The rest of the code initializes one vector sprite.

    'When the form is loaded, activate the surface
    SpriteSurface1.Active = True
    
    'Create a space ship. These points makes a ship.
    Dim S As New SCG.TurboSprite.PolygonSprite(0, -10, 5, 10, 0, 5, -5, 10)
    
    'Tell the sprite to rotate.
    S.Spin = SCG.TurboSprite.SpinType.Clockwise
    S.SpinSpeed = 3
    
    'Start position.
    S.Position = New Point(30, 30)
    
    'Add the sprite to the engine, and acquire the sprite mover from the engine.
    SpriteEngineDestination1.AddSprite(S)
    Dim Mover As SCG.TurboSprite.DestinationMover = SpriteEngineDestination1.GetMover(S)
    
    'Tell the mover about speed and direction.
    Mover.Speed = 5
    Mover.Destination = New Point(50, 40)
    
    'Tell the mover that the destination really isn't a destination,
    'it's just used as a direction.
    Mover.StopAtDestination = False
    

    This is the sprite:

    Download the engine from the Code Project web site.

  • Tuples

    Tuples in F# is a list of objects with different types, and the tuple itself is strongly typed. You can imagine a simple class or a structure without having to declare the type. This code creates a tuple called myTuple that contains a string, and integer, another string and finally a boolean.

    let myTuple=("A", 10, "B", true)

    The string representation of a tuple is a string representation of the individual values within parenthesis. This code…

    let myTuple=("A", 10, "B", true)
    System.Console.WriteLine(myTuple)

    …gives you…

    (A, 10, B, True)

    This code will extract the individual values from the tuple. The output from this code will be 10.

    let myTuple=("A", 10, "B", true)
    let v1, v2, v3, v4 = myTuple
    System.Console.WriteLine(v2)

    The types of the values will be the .NET types from the original values in the tuple, v1 is a string, v2 is a 32 bit integer, v3 is also a string and v4 is a boolean. Tuples can be used in many ways, as allowing a single function to return multiple values.

  • Decompressing text

    This post shows how to compress a String to reduce the amount memory it consumes, and this post shows how to use the CompressText function. To be able to read the content of the string, it must be decompressed (or inflated) again. The DecompressText function is one way to do this.

    Private Function DecompressText(ByVal B() As Byte) As String
       Dim Result As New System.Text.StringBuilder()
       Using MemStream As New System.IO.MemoryStream(B)
          Using GZStream As New System.IO.Compression.GZipStream(MemStream, _
             IO.Compression.CompressionMode.Decompress)
          Do
             'Note that this makes 1024 bytes in VB.
             Dim Buffer(1023) As Byte
             Dim BytesRead As Integer = GZStream.Read(Buffer, 0, 1024)
             If BytesRead > 0 Then
                Result.Append( _
                   System.Text.Encoding.UTF8.GetString(Buffer, 0, BytesRead))
             End If
             If BytesRead < 1024 Then
                Exit Do
             End If
          Loop
          GZStream.Close()
          Return Result.ToString()
          End Using
       End Using
    End Function

    Now, imagine that B is a byte array returned from the CompressText function. B holds the bytes of a compressed text string. B is passed to the DecompressText function and the function returns the inflated string again. Example:

    'Create some text.
    Dim S As String = "This is some text that I want to compress. Preferably it's " & _
    "a long string loaded from a text file or some XML document."
    
    'Assign the compressed version to the variable B.
    Dim B() As Byte = CompressText(S.ToString())
    
    'Decompress it, and display the result.
    Dim Decompressed As String = DecompressText(B)
    Console.WriteLine(Decompressed)

    Have you seen a more elegant way to handle strings in memory than what the .NET Framework offers?

  • Inserting a value in an identity column

    In SQL Server 2008, when a column is set to auto increment (Identity Specification), you are normally not allowed to give that column a value. If you are copying data from one database to another in Visual Basic, perhaps by loading a DataSet object using one connection, and inserting it’s data using another, this can be a problem.

    The table option you must set, to be allowed to insert a value in an identity column is called IDENTITY_INSERT. So add this line to your command object to make it work:

    SET IDENTITY_INSERT dbo.Products ON;

    The following INSERT statement can give a value to the identity column, if the value complies with the rules for that column. The line of code could look something like this:

    Using X As New SqlClient.SqlCommand( _
        "SET IDENTITY_INSERT dbo.Products ON; INSERT...
  • .NET controls in Microsoft Access

    Creating ActiveX objects in Visual Basic .NET is easy from Visual Studio 2008. There are a few checkboxes to tick, and a class attribute to add. But if you are doing an ActiveX control for use in let’s say an Microsoft Access application, there are some requirements that must be met, otherwise Access will not list your control. Of course, Microsoft gives you a template for this, and then you´re off. Thanks to Håkan Ståhl for pointing out this template to me.

    Create a VB6 Interop UserControl project. The project that is shown on the screenshot below uses the standard name InteropUserControlLibrary1. I already hold a control. To rename the control, rename all three files (the vb file, the manifest and the bitmap). When the vb file is renamed, you will be asked if you want to rename the references too. Do that. Finally, fix the broken references in the manifest file (enter the new name in the progid attribute and the name attribute). Now you´re on your way. You can add a test project to the solution and start coding. The control is registered when you compile the project.

  • Easy handeling of command line arguments

    The CommandLineArguments class is a useful tool when you are building an application that accepts different arguments from the command line, and argument with parameters. The class lets you check if the program was started using a specific argument, and also read the argument to the right, as if it was a parameter.

    The ArgumentExists function checks for the presence of an argument and the GetIndexOfArgument function gives you the index of an argument, or negative one if not present. The GetArgumentParameter returns the argument next to a given argument.

    Let’s say that you are writing an application called test.exe, and it is started like this:

    test.exe -f hello -qq "hello again"

    If you pass “-qq” to the GetArgumentParameter function, it will return “hello again“. If you pass “-f” to the ArgumentExists function, it returns true. And if you pass “yeah” to the GetIndexOfArgument function, it returns -1.

    Example:

    Dim Args As New CommandLineArguments()
    Console.WriteLine("Param: " & Args.ArgumentExists("-f").ToString())
    Console.ReadLine()

    This is the source code for the class:

    Public Class CommandLineArguments
        Inherits CollectionBase
    
        Private mIgnoreCase As Boolean
    
        Public Sub New()
            Me.New(True)
        End Sub
    
        Public Sub New(ByVal IgnoreCase As Boolean)
            Dim S() As String = System.Environment.GetCommandLineArgs()
            If S.Length > 1 Then
                For I As Integer = 1 To S.Length - 1
                    List.Add(S(I))
                Next
            End If
            Me.mIgnoreCase = IgnoreCase
        End Sub
    
        Default Public ReadOnly Property Item(ByVal Index As Integer) As String
            Get
                Return CType(List(Index), String)
            End Get
        End Property
    
        Public Function ArgumentExists(ByVal Arg As String) As Boolean
            For Each S As String In Me
                If String.Compare(S, Arg, Me.mIgnoreCase) = 0 Then
                    Return True
                End If
            Next
            Return False
        End Function
    
        Public Function GetIndexOfArgument(ByVal Arg As String) As Integer
            If Me.Count > 0 Then
                For I As Integer = 0 To Me.Count - 1
                    If String.Compare(Me(I), Arg, Me.mIgnoreCase) = 0 Then
                        Return I
                    End If
                Next
                Return -1
            Else
                Return -1
            End If
        End Function
    
        Public Function GetArgumentParameter(ByVal Arg As String) As String
            Dim Index As Integer = Me.GetIndexOfArgument(Arg)
            If Index > -1 Then
                If Index < (Me.Count - 1) Then
                    Return Me(Index + 1)
                Else
                    Return ""
                End If
            Else
                Return ""
            End If
        End Function
    
    End Class
    
  • Monkeybone: The Bar instruction

    The Bar instruction, as it appears in a Monkeybone Image (a text file with .mob ending) is a line with at least five parameters. The color of the bar, the X and Y position of the bar, the width and height of the bar. The following lines in a .mob file creates a green rectangular image with a centered yellow box in it:

    Clear 200x200 #337733
    Bar #ffff00 X:50 Y:50 W:100 H:100

    Optionally, you can set the percentage of the fill in either horizontal or vertical direction using HFill or VFill, followed by a percent value. The following code will give a 50 pixel high box. The specified height is 100 (pixels) but VFill:50% tells Monkeybone Viewer to only display half height of the box:

    Clear 200x200 #337733
    Bar #ffff00 X:50 Y:50 W:100 H:100 VFill:50%

    One way of producing an image like this, is to use Notepad to create a text file that ends with .mob instead of .txt. Using Notepad is not the easiest way, and rather impossible if you want to generate dynamic images. For dynamically generate Monkeybone Images, the Monkeybone .NET library or the Monkeybone .NET control can be used.

    The Monkeybone .NET library is a class library that contains a writer with the capability of streaming Monkeybone instructions to a file. The following Visual Basic code requires a reference to Monkeybone.dll, and produces a file called “Bars.mob” that can be opened using the Monkeybone Viewer.

    Using Sw As New Monkeybone.MonkeyboneWriter("C:\Bars.mob", 200, 200, _
          System.Drawing.Color.FromArgb(51, 119, 51))
       Dim Bar As New Monkeybone.Instructions.Bar(50, 50, 100, 100)
       Bar.BarFillPercent = 50
       Bar.Color = System.Drawing.Color.FromArgb(255, 255, 0)
       Bar.Orientation = Monkeybone.Instructions.Bar.BarOrientation.Vertical
       Sw.WriteLine(Bar)
    End Using

    If you want your image to display on a form, you can use the Monkeybox control. The Monkeybox control displays your image directly on screen, with an option to save it as a .mob file that can be opened in Monkeybone Viewer. The following code is written in the Shown event of a form that has a Monkeybox control on it, called MBox1. Here, I do not actually save the image, just displays the source in a messagebox. The messagebox will contain exactly the same two instructions as the last example produces. Also, on the screen, you will see a green Monkeybone image with a yellow box in it.

    Public Class Form1
    
        Private Sub Form1_Shown(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Shown
            'Size is normaly set in the designer, but here I set it manually.
            MBox1.Width = 200
            MBox1.Height = 200
    
            'Set the background color.
            MBox1.BackColor = System.Drawing.Color.FromArgb(51, 119, 51)
    
            'Add a bar.
            MBox1.AddBar(Color.FromArgb(255, 255, 0), 50, 50, 100, 100, 50, _
               Monkeybox.Bar.BarOrientation.Vertical)
    
            'Redraw is not trigged by adding and instruction.
            MBox1.Invalidate()
    
            MessageBox.Show(MBox1.GetSource())
        End Sub
    
    End Class

  • Filtersearching a Data Grid View

    Some applications have that cool search feature that filters on what you search for, and displays the result in real time. The data that you are searching in is loaded, and then the record(s) that matches your search from that set of data is display. Usually, you would do this if you are handling fairly little data, and you would do this on a separate thread from the GUI thread, to prevent that your application get poor responsiveness. This whole process works incredible well with the Data Grid View of the .NET Framework.

    The following example requires a form with a textbox (TextBox1) and a data grid view (DataGridView1). To use the application, just type something in the textbox, and watch the grid filtering its records. The Load event of the form populates the grid. The TextChanged of the textbox filters the grid.

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    
        'Configure the data grid view.
        DataGridView1.ReadOnly = True
        DataGridView1.Columns.Add("ColA", "Some column")
        DataGridView1.Columns.Add("ColB", "Some other column")
        DataGridView1.AllowUserToAddRows = False
        DataGridView1.SelectionMode = DataGridViewSelectionMode.FullRowSelect
        DataGridView1.Rows.Clear()
    
        'Add lots of rows.
        For A As Integer = 500 To 999
            Dim Index As Integer = DataGridView1.Rows.Add()
            DataGridView1.Rows(Index).Cells(0).Value = A.ToString("000")
            DataGridView1.Rows(Index).Cells(1).Value = "Hello"
        Next
    
        'Add two rows with some names in them.
        Dim Temp As Integer = DataGridView1.Rows.Add()
        DataGridView1.Rows(Temp).Cells(0).Value = "Anders"
        DataGridView1.Rows(Temp).Cells(1).Value = "Bengt"
    
        Temp = DataGridView1.Rows.Add()
        DataGridView1.Rows(Temp).Cells(0).Value = "Calle"
        DataGridView1.Rows(Temp).Cells(1).Value = "David"
    
        'Again, add lots of rows.
        For A As Integer = 300 To 999
            Dim Index As Integer = DataGridView1.Rows.Add()
            DataGridView1.Rows(Index).Cells(0).Value = A.ToString("000")
            DataGridView1.Rows(Index).Cells(1).Value = "Good bye"
        Next
    
        'Now we have 1.202 rows in the grid. Do some resizing of the columns.
        DataGridView1.AutoResizeColumns()
    
    End Sub
    
    Private Sub TextBox1_TextChanged(ByVal _
         sender As System.Object, ByVal e As System.EventArgs) Handles TextBox1.TextChanged
        If DataGridView1.RowCount > 0 Then
    
            'What is the user searching for? Remove case information.
            Dim SearchFor As String = TextBox1.Text.ToLower().Trim()
    
            'If the user has cleared the search box, show all rows.
            If SearchFor = "" Then
                For I As Integer = 0 To DataGridView1.Rows.Count - 1
                    DataGridView1.Rows(I).Visible = True
                Next
            Else
    
                'When the user types something in the textbox, search for
                'rows with cells that holds that value.
                For I As Integer = 0 To DataGridView1.Rows.Count - 1
    
                    'Extract the values from the grid. Remove case information.
                    Dim ColA As String = CType(DataGridView1.Rows(I).Cells(0).Value, _
    String).ToLower()
                    Dim ColB As String = CType(DataGridView1.Rows(I).Cells(1).Value, _
    String).ToLower()
    
                    'Show only matching rows.
                    If ColA.IndexOf(SearchFor) > -1 OrElse ColB.IndexOf(SearchFor) > -1 Then
                        DataGridView1.Rows(I).Visible = True
                    Else
                        DataGridView1.Rows(I).Visible = False
                    End If
    
                Next
            End If
    
            'Select the first visible row.
            For I As Integer = 0 To DataGridView1.Rows.Count - 1
                If DataGridView1.Rows(I).Visible Then
                    DataGridView1.CurrentCell = DataGridView1.Rows(I).Cells(0)
                    Exit For
                End If
            Next
    
        End If
    End Sub
    
  • Connecting to MySQL from Visual Basic

    If it is in your control, stay with SQL Server! If it isn’t, this is how you can do it.

    When you install the .NET Connector for MySQL, a class library called MySql.Data is installed. You can add a reference to it from the Add Reference dialog. This gives you a new set of classes for accessing a MySQL database. This is what a connection to a database can look like:

    Dim ConnectionString As String = "Server=XXX;Port=3306;Database=XXX;Uid=XXX;Pwd=XXX"
    Using Cn As New MySql.Data.MySqlClient.MySqlConnection(ConnectionString)
      Cn.Open()
    
      Console.WriteLine(Cn.State.ToString())
    
      Cn.Close()
    End Using

    If you know you ADO.NET, the rest should be a stroll in the park. This code lists keywords in MySQL:

    Dim ConnectionString As String = "Server=XXX;Port=3306;Database=mysql;Uid=XXX;Pwd=XXX"
    Using Cn As New MySql.Data.MySqlClient.MySqlConnection(ConnectionString)
      Cn.Open()
    
      Using Cmd As New MySql.Data.MySqlClient.MySqlCommand("SELECT * FROM help_keyword", Cn)
        Dim R As MySql.Data.MySqlClient.MySqlDataReader = Cmd.ExecuteReader()
        While R.Read()
          Console.WriteLine(R.GetString(1))
        End While
        R.Close()
      End Using
    
      Cn.Close()
    End Using
  • Automatic object duplication

    While working on my new Monkeybone control, I was on my way to create an abstract base class that declared a function called Copy for duplicating a drawing instruction. My plan was that each instruction (such as a Line or a Bar) had to provide an implementation of the Copy method, so that each instruction could be duplicated and modified as needed. A quick Google search made me change strategy. I found this function for C# by James Crowley that I quickly rewrote for VB:

    Public Function Copy() As Instruction
        Using memStream As New System.IO.MemoryStream()
            Dim C As New System.Runtime.Serialization.StreamingContext( _
                System.Runtime.Serialization.StreamingContextStates.Clone)
            Dim Bf _
               As New System.Runtime.Serialization.Formatters.Binary.BinaryFormatter(Nothing, C)
            Bf.Serialize(memStream, Me)
            memStream.Seek(0, IO.SeekOrigin.Begin)
            Return CType(Bf.Deserialize(memStream), Instruction)
        End Using
    End Function
    

    With this function completely implemented in the in the abstract base class, any serializable object that inherits from the base class, has a function called Copy that creates a new instance if the object and initializes it in the same way as the object that the Copy function is called on. Really cool. Now check this: The Line class inherits from my abstract base class. The base does not contain any data (the line coordinates are stored in the Line class), but the Line class does not contain any hints on how copying is done. But still:

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) _
        Handles MyBase.Load
        Dim L1 As New Monkeybox.Line(10, 20, 30, 40)
        Dim L2 As Monkeybox.Line = CType(L1.Copy(), Monkeybox.Line)
        L1.X1 += 1
        MessageBox.Show(L2.X1.ToString())
    End Sub

    Yep! L1.X1 is 11 but L2.X1 is still 10. Woow!

  • Deboxing undercover

    This just don’t look right to me:

    For Each X As SomeType In ComboBox1.Items
       ...some code...
    Next

    Items in a combo box is an ObjectCollection, so I usually do the extra step of using an Object as interator in my For Each iterators to avoid the feeling of implisive unboxing, because implisive unboxing is something we should avoid.

  • Checking bits in Visual Basic

    There are several times that you need to master bitwise operations in Visual Basic. Imagine the following code in a form. Whenever you move the mouse, it checks if the right mouse button is held down.

    Private Sub M(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) _
    Handles Me.MouseDown, Me.MouseMove, Me.MouseUp
    	If e.Button = Windows.Forms.MouseButtons.Right Then
    		Me.Text = "Yes"
    	Else
    		Me.Text = "No"
    	End If
    End Sub

    Hold down the right mouse button, and move the mouse around on the form, and see that the text of the form title says “Yes”. But this code fails when you hold down the right button at the same time as another button. Checking the state of the mouse buttons is one situation you need to know bitwise operations. Checking file attributes is another. Also, you might want to develop a function that takes one or more options in one argument. This is the basics:

    Imagine a bit pattern. The value 3 has a pattern that ends with 0011. Let’s say that I want to test the last bit in this pattern, then I need a number with the pattern 0001, that is, a bit pattern with zeros on all position except for the position I want to test. The value 1 has a pattern that ends with 0001. The bitwise operator And returns 1 if we have a hit. So 0011 And 0001 equals 0001 (3 And 1 = 1) and 0011 And 0010 equals 0010 (3 and 2 = 2) but 0011 And 0100 equals 0000 (3 And 4 = 0) because the one in 0100 does not hit a one in 0011. So the bug free version of my program could look like this:

    Private Sub M(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) _
    Handles Me.MouseDown, Me.MouseMove, Me.MouseUp
    	If (e.Button And Windows.Forms.MouseButtons.Right) = _
    Windows.Forms.MouseButtons.Right Then
    		Me.Text = "Yes"
    	Else
    		Me.Text = "No"
    	End If
    End Sub

    Or is a bitwise operator that can be used to set bits in a pattern. 0011 Or 0001 equals 0011 because the last bit in the pattern was already set. 0011 Or 1000 equals 1011 (3 Or 8 = 11) because we tell the first bit to become 1.

    For this example (also in a form), I have created an enumeration with 8 flags. All values has a bit pattern with one 1 and 0 at all other positions.

    Public Enum Flags
    	Flag1 = 1
    	Flag2 = 2
    	Flag3 = 4
    	Flag4 = 8
    	Flag5 = 16
    	Flag6 = 32
    	Flag7 = 64
    	Flag8 = 128
    End Enum

    This function checks what flags has been passed in.

    Private Sub CheckFlags(ByVal Arg As Flags)
    	If (Arg And Flags.Flag1) = Flags.Flag1 Then
    		MessageBox.Show("Flag 1 is set")
    	End If
    	If (Arg And Flags.Flag2) = Flags.Flag2 Then
    		MessageBox.Show("Flag 2 is set")
    	End If
    	If (Arg And Flags.Flag3) = Flags.Flag3 Then
    		MessageBox.Show("Flag 3 is set")
    	End If
    	If (Arg And Flags.Flag4) = Flags.Flag4 Then
    		MessageBox.Show("Flag 4 is set")
    	End If
    	If (Arg And Flags.Flag5) = Flags.Flag5 Then
    		MessageBox.Show("Flag 5 is set")
    	End If
    	If (Arg And Flags.Flag6) = Flags.Flag6 Then
    		MessageBox.Show("Flag 6 is set")
    	End If
    	If (Arg And Flags.Flag7) = Flags.Flag7 Then
    		MessageBox.Show("Flag 7 is set")
    	End If
    	If (Arg And Flags.Flag8) = Flags.Flag8 Then
    		MessageBox.Show("Flag 8 is set")
    	End If
    End Sub

    When called like this, the fourth, fifth and eighth message box will be shown:

    Me.CheckFlags(Flags.Flag4 Or Flags.Flag5 Or Flags.Flag8)
  • Query tool for XML

    Today I had to be able to query XML files using XPath and view the result clean and structured. Doing this from within Visual Basic is very easy, so making a tool was an easy option. This is the user interface:

    The top pane is used for writing XPath queries. Below, there are three panes. One displays the result as a tree structure, the next displays the attributes of the selected node in the tree view and the last display the source of the selected node.

    This is the Click event of the query button:

    Private Sub DoExecute(ByVal XPath As String)
    
        'Store the last executed query in case the user wants to refresh the query.
        Me.LastExecutedQuery = XPath
    
        'Clear the output textbox.
        txtOutput.Text = ""
    
        'Clear the elements tree view.
        tvElements.Nodes.Clear()
    
        'Clear the attribute list.
        lvAttributes.Items.Clear()
    
        If XPath.Trim() = "" Then
    
            'If no query is sent in, display the root element.
    
            'Display it in the tree (using a custom function not shown here).
            Me.AddNode(Dom.DocumentElement, tvElements.Nodes)
    
            'This is the status bar of the window.
            lblResult.Text = "Elements in result: 1"
    
        Else
    
            'The query might fail.
            Try
    
                Dim Result As Xml.XmlNodeList = Dom.DocumentElement.SelectNodes(XPath)
                If Result Is Nothing Then
                    lblResult.Text = "Elements in result: 0"
                Else
                    If Result.Count = 0 Then
                        lblResult.Text = "Elements in result: 0"
                    Else
                        Me.ResultList = Result
                        lblResult.Text = "Elements in result: " & Result.Count.ToString()
    
                        Dim ResultNode As TreeNode = tvElements.Nodes.Add(XPath.Trim())
                        ResultNode.Tag = "Query"
                        ResultNode.ImageIndex = 3
                        ResultNode.SelectedImageIndex = 3
    
                        'Populate the tree structure (using a custom function not shown here).
                        tvElements.BeginUpdate()
                        For Each Xn As Xml.XmlNode In Result
                            Me.AddNode(Xn, ResultNode.Nodes)
                        Next
                        tvElements.EndUpdate()
    
                        'Expand the root node that contains the result.
                        ResultNode.Expand()
    
                    End If
                End If
    
            Catch ex As Exception
    
                'If the query failed, extract the reason from the exception and display it.
                lblResult.Text = "Elements in result: [Error]"
                txtOutput.Text = "XPath failed." & ControlChars.CrLf & ControlChars.CrLf & ex.Message
    
            End Try
        End If
    
        'Select the first node. Other panes will be updated in the AfterSelect event of the treeview.
        If tvElements.Nodes.Count > 0 Then
            tvElements.SelectedNode = tvElements.Nodes(0)
            tvElements.SelectedNode.EnsureVisible()
        End If
    
    End Sub

    To use this, just open an XML file and click away in the tree view. You can also write XPath queries to browse a subset of the data. If you want to download this early version, the exe file (.NET Framework 3.5) is located here Since 17/1 2010, the program is can be downloaded from here.

  • Big integers in .NET 4.0

    The BigInteger structure becomes available if you add a reference to the System.Numerics namespace. BigInteger represents a positive or negative integer of any size.  This is great for doing arithmetic calculations with very large numbers, and is one of the problems you had to solve on your own in previous versions of .NET Framework.

    After the reference is added, you can create a BigInteger using the New keyword, and an initial value can be passed to the constructor, like so:

    Dim X As New System.Numerics.BigInteger(Long.MaxValue)
    Console.WriteLine(X.ToString())

    To do arithmetic operations, create the BigIntegers you need for the operation, and then call the static (shared) functions of the BigInteger structure to do the calculations. In this case, I call the static function Multiply.

    Dim X As New System.Numerics.BigInteger(Long.MaxValue)
    Dim Y As New System.Numerics.BigInteger(Long.MaxValue)
    Dim Z As System.Numerics.BigInteger = _
         System.Numerics.BigInteger.Multiply(X, Y)
    Console.WriteLine(Z.ToString())

    Just by adding a few of these lines to the above code, will give you one insanely large number.

    Z = System.Numerics.BigInteger.Multiply(Z, Z)
    Z = System.Numerics.BigInteger.Multiply(Z, Z)
    Z = System.Numerics.BigInteger.Multiply(Z, Z)
    Z = System.Numerics.BigInteger.Multiply(Z, Z)

    One way to serialize this number in SQL Server could be to store the underlying bytes of the number that the BigInteger instance represents. The BigInteger structure has a member function that returns these bytes as a byte array called GetByteArray. An existing byte array can be passed to the constructor of the BigInteger to reconstruct the number.

  • Getting the meta data for a table from Visual Basic

    The last time I did this, I needed to build a custom Visual Basic entity generator. After two hours of coding, I had a tiny Windows Forms application that took some connection information and a table name, and returned an entity class with some properties and methods, and a collection class. With initialization, database write-back and all.

    From the Management Studio, a call to the sp_help procedure and pass the name of the table you want to receive meta data about, like this:

    EXEC sp_help 'dbo.spt_values'

    (I still haven’t created any databases on the computer that I am writing this from, so I am grabbing the meta data from the spt_values table in the master database.

    The procedure returns a few sets, and the second one contains a list of the table columns.

    To call this from Visual Basic, you should know that the procedure is located in the sys namespace, and the parameter that it expects is called @objname. So, if you are using a dataset, the table with index 1 contains the column information. If you are using a data reader, you can call the NextResult function, like so (in a console application):

    Using Cn As New SqlClient.SqlConnection("Data Source=.;Initial Catalog=master;Integrated Security=True")
        Cn.Open()
        Using Cmd As New SqlClient.SqlCommand("[sys].[sp_help]", Cn)
            Cmd.CommandType = CommandType.StoredProcedure
            Cmd.Parameters.AddWithValue("@objname", "dbo.spt_values")
            Dim R As SqlClient.SqlDataReader = Cmd.ExecuteReader()
            R.NextResult()
            Dim ColumnNameColumn As Integer = R.GetOrdinal("Column_name")
            Dim ColumnTypeColumn As Integer = R.GetOrdinal("Type")
            Dim ColumnLength As Integer = R.GetOrdinal("Length")
            While R.Read()
                Console.WriteLine(R.GetString(ColumnNameColumn))
                Console.WriteLine(R.GetString(ColumnTypeColumn))
                Console.WriteLine(R.GetInt32(ColumnLength).ToString())
            End While
            R.Close()
        End Using
        Cn.Close()
    End Using

    If you are using this to create something like a code generator, remember that Length column holds the column size in bytes. This means that a nvarchar (Unicode string columns) with the length set to 10, only can hold 5 characters.

    The above code targets .NET Framework 3.5, but it would look exactly the same in the version above and below. It is written in Visual Basic 10 (VBx).

  • Hardware accelerated graphics through XNA: Getting started

    There are some features of the XNA Framework that is unavailable from Visual Basic, but this should not stop you from writing descent games in Visual Basic. On my machine, I have installed XNA Game Studio 3.1 (a game developing environment from Microsoft) and I also have a beta of Visual Studio 2010 that I am going to use. This example will just contain the code necessary to get something on the screen, a sprite floating across.

    From VS2010, I am using a regular console application and the target platform for the project is .NET Framework 3.5.

    Now I must add two references: Microsoft.Xna.Framework and Microsoft.Xna.Framework.Game. I use version 3.1, the version that got installed when I installed XNA Game Studio 3.1.

    The next step is to create the game class. I call my class TestGame. TestGame should inherit from the Microsoft.Xna.Framework.Game class. In here I create a Main method to get the program started, and I select that method to be the starting point for the program in the Project Settings window. This is the code so far:

    Public Class TestGame
        Inherits Microsoft.Xna.Framework.Game
    
        Public Shared Sub Main()
    
        End Sub
    
    End Class

    In the Main method, I create my game (the TestGame class) and from the constructor, a graphics device manager for the game. I use the graphics device manager to set my preferred resolution (800×600) and to switch to fullscreen mode. Note that I want to keep the reference to the graphics device manager as a member of my game class.

    Public Class TestGame
        Inherits Microsoft.Xna.Framework.Game
    
        Private Gfx As Microsoft.Xna.Framework.GraphicsDeviceManager
    
        Public Shared Sub Main()
            Dim Game As New TestGame()
            Game.Run()
        End Sub
    
        Public Sub New()
            Me.Gfx = New Microsoft.Xna.Framework.GraphicsDeviceManager(Me)
            Me.Gfx.PreferredBackBufferWidth = 800
            Me.Gfx.PreferredBackBufferHeight = 600
            If Not Me.Gfx.IsFullScreen Then
                Me.Gfx.ToggleFullScreen()
            End If
        End Sub
    
    End Class

    The next thing to do is some overrides from the base class. These methods will be overloaded:

    Protected Overrides Sub Initialize()
        MyBase.Initialize()
    End Sub
    
    Protected Overrides Sub LoadContent()
        MyBase.LoadContent()
    End Sub
    
    Protected Overrides Sub UnloadContent()
        MyBase.UnloadContent()
    End Sub
    
    Protected Overrides Sub Update(ByVal gameTime As Microsoft.Xna.Framework.GameTime)
        MyBase.Update(gameTime)
    End Sub
    
    Protected Overrides Sub Draw(ByVal gameTime As Microsoft.Xna.Framework.GameTime)
        MyBase.Draw(gameTime)
    End Sub

    Just to make something happen on the screen, I am adding these members:

    Private Sb As Microsoft.Xna.Framework.Graphics.SpriteBatch
    Private SpriteTexture As Microsoft.Xna.Framework.Graphics.Texture2D
    Private SpriteX As Integer = 0
    Private SpriteY As Integer = 0

    The SpriteBatch will manage my sprites and the Texture2D is the sprite graphics. In the LoadContent function, I will load a sprite from my hard drive.

    Protected Overrides Sub LoadContent()
        Me.Sb = New Microsoft.Xna.Framework.Graphics.SpriteBatch(Me.Gfx.GraphicsDevice)
        Me.SpriteTexture = Microsoft.Xna.Framework.Graphics.Texture2D.FromFile(Me.Gfx.GraphicsDevice, _
             "mysprite.png")
        MyBase.LoadContent()
    End Sub

    The Update function is for changing the game scenery.

    Protected Overrides Sub Update(ByVal gameTime As Microsoft.Xna.Framework.GameTime)
        SpriteX += 1
        SpriteY += 1
        MyBase.Update(gameTime)
    End Sub

    And the Draw function is for screen rendering.

    Protected Overrides Sub Draw(ByVal gameTime As Microsoft.Xna.Framework.GameTime)
        Me.Gfx.GraphicsDevice.Clear(Microsoft.Xna.Framework.Graphics.Color.Black)
        Me.Sb.Begin(Microsoft.Xna.Framework.Graphics.SpriteBlendMode.AlphaBlend)
        Me.Sb.Draw(Me.SpriteTexture, New Microsoft.Xna.Framework.Rectangle(Me.SpriteX, Me.SpriteY, 32, 32), _
             Microsoft.Xna.Framework.Graphics.Color.Red)
        Me.Sb.End()
        MyBase.Draw(gameTime)
    End Sub

    This is the complete code that produces a sprite that floats over the screen in Visual Basic using XNA:

    Public Class TestGame
        Inherits Microsoft.Xna.Framework.Game
    
        Private Gfx As Microsoft.Xna.Framework.GraphicsDeviceManager
    
        Private Sb As Microsoft.Xna.Framework.Graphics.SpriteBatch
        Private SpriteTexture As Microsoft.Xna.Framework.Graphics.Texture2D
        Private SpriteX As Integer = 0
        Private SpriteY As Integer = 0
    
        Public Shared Sub Main()
            Dim Game As New TestGame()
            Game.Run()
        End Sub
    
        Public Sub New()
            Me.Gfx = New Microsoft.Xna.Framework.GraphicsDeviceManager(Me)
            Me.Gfx.PreferredBackBufferWidth = 800
            Me.Gfx.PreferredBackBufferHeight = 600
            If Not Me.Gfx.IsFullScreen Then
                Me.Gfx.ToggleFullScreen()
            End If
        End Sub
    
        Protected Overrides Sub Initialize()
            MyBase.Initialize()
        End Sub
    
        Protected Overrides Sub LoadContent()
            Me.Sb = New Microsoft.Xna.Framework.Graphics.SpriteBatch(Me.Gfx.GraphicsDevice)
            Me.SpriteTexture = Microsoft.Xna.Framework.Graphics.Texture2D.FromFile(Me.Gfx.GraphicsDevice, _
                  "mysprite.png")
            MyBase.LoadContent()
        End Sub
    
        Protected Overrides Sub UnloadContent()
            MyBase.UnloadContent()
        End Sub
    
        Protected Overrides Sub Update(ByVal gameTime As Microsoft.Xna.Framework.GameTime)
            SpriteX += 1
            SpriteY += 1
            MyBase.Update(gameTime)
        End Sub
    
        Protected Overrides Sub Draw(ByVal gameTime As Microsoft.Xna.Framework.GameTime)
            Me.Gfx.GraphicsDevice.Clear(Microsoft.Xna.Framework.Graphics.Color.Black)
            Me.Sb.Begin(Microsoft.Xna.Framework.Graphics.SpriteBlendMode.AlphaBlend)
            Me.Sb.Draw(Me.SpriteTexture, New Microsoft.Xna.Framework.Rectangle(Me.SpriteX, Me.SpriteY, 32, 32), _
                    Microsoft.Xna.Framework.Graphics.Color.Red)
            Me.Sb.End()
            MyBase.Draw(gameTime)
        End Sub
    
    End Class
    
  • The ups and downs of Visual Studio 2010: Auto list members

    In Visual Studio 2010, the auto list members feature is much more intelligent than in previous versions. For example, assuming that X is an object with a visible function called DoSomeWork, in earlier versions of Visual Studio, you would have to know that the method started with Do to find it in the list. If you didn’t know that, you would have to scroll through the list of members and try to recall what you are looking for, or search in the object browser. Now, if you type X.Work, Visual Studio lists DoSomeWork as a suggestion, because matching is done within the name, not only from the beginning of the name. Also, you type an acronym of the function name. DSW would match DoSomeWork.

    Previous versions of Visual Studio applied a “suggest and complete” policy, which is the default in Visual Studio 2010. This is usually the most effected mode. If you are aiming to call the DoSomeWork function, you can type something like X.DoSo and then what ever character you was going to type thereafter, likely an opening parenthesis. The problem with the “suggest and complete” policy shows up when you’re trying to call a function that isn’t implemented yet. The text editor will force your typing to be a call to something other than you are aiming at, something that already exists, at least if the not-yet-existing member has a name that is a subset of an existing name. I always end up grabbing my computer mouse when this happens. This is one example where the “suggest only” policy can be useful. This mode lets you type whatever you want, because it will not force you to choose from something in the list.

    To toggle completion mode, press Ctrl+Alt+Space or look at the IntelliSense sub menu under the Edit menu. Just as the call hierarchy feature, this feature is available no matter what language you’re using, but (at least in the Beta) it only works in the C# editor, not the Visual Basic editor.

    Now, there is no reason to have a mouse connected to the computer anymore. Thank you, Microsoft!

  • The stamping program

    To start this year and decennium, I have dug up my old Windows Forms control for command line interfacing with a user in a Windows environment, a control that I still think allows the programmer to accomplish complex interfacing with hardly any coding at all.

    This program consist of one form only, and the only added control is the CLI control. The name of the CLI control instance is simply Cli1. I have loaded four images as project resources; a background image and three different colored icons. One is red, one is blue and one is green.

    Click on the image to view it in full size.

    This is how the program works: Type Red, Green or Blue to select which color you want to “draw” with. Click on an empty space on the CLI control to place a red, green or blue symbol. Click on an existing symbol to remove it. The complete source code for this:

    Public Class Form1
    
        Private Enum Colors
            None
            Red
            Green
            Blue
        End Enum
    
        Private CurrentColor As Colors = Colors.None
    
        Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            Cli1.BackgroundImage = My.Resources.Background
            Cli1.WriteLine("Type Red, Green or Blue. Then click!")
        End Sub
    
        Private Sub Cli1_Click(ByVal Source As Object, _
        ByVal PixelX As Integer, ByVal PixelY As Integer, ByVal CharX As Integer, ByVal CharY As Integer) _
        Handles Cli1.Click
            'What symbol did the user click on?
            Dim S As CLIControl.GraphicalElement = Cli1.GraphicalElements.GetElement(PixelX, PixelY)
            'If any, remove it. Else add a new one.
            If S Is Nothing Then
                'Add a symbol.
                Select Case Me.CurrentColor
                    Case Colors.Red
                        Cli1.GraphicalElements.Add(New CLIControl.Picture("", _
                        My.Resources.Circle_Red, PixelX - 16, PixelY - 16))
                    Case Colors.Green
                        Cli1.GraphicalElements.Add(New CLIControl.Picture("", _
                        My.Resources.Circle_Green, PixelX - 16, PixelY - 16))
                    Case Colors.Blue
                        Cli1.GraphicalElements.Add(New CLIControl.Picture("", _
                        My.Resources.Circle_Blue, PixelX - 16, PixelY - 16))
                End Select
            Else
                'Remove a symbol.
                Cli1.GraphicalElements.Remove(S)
            End If
        End Sub
    
        Private Sub Cli1_UserTyped(ByVal Source As Object, ByVal Command As String) Handles Cli1.UserTyped
            If Not Command = "" Then
                Select Case Command.ToLower()
                    Case "red"
                        Me.CurrentColor = Colors.Red
                    Case "green"
                        Me.CurrentColor = Colors.Green
                    Case "blue"
                        Me.CurrentColor = Colors.Blue
                    Case Else
                        Cli1.WriteLine("Nah!")
                End Select
            End If
        End Sub
    
    End Class
    

    The CLI control can be downloaded from this page, and this program (compiled) is located here.

  • The simplest query tool ever

    A colleague wanted to do a database query from a computer without any database client. He needed a tool that allowed him to type in a SQL query, and receive a sortable grid with the result set. All of these features are built-in in the .NET Framework, and it didn’t take me more than 2 minutes to do an exe file with these features using Visual Studio 2010. I used .NET 2.0 because these basic features are available in that version, and he did not want to install a newer version of the .NET Framework.

    This is the user interface: A tab strip with three tabs. One for a connection string, one for the query and one for the result grid. The first two contains a textbox each, and the third contains a DataGridView control. Also, the program has a status bar with a label and a toolstrip with two buttons; one for testing the connectionstring that the user enters in the textbox of the first tab, and one for executing the query and presenting the result in the grid.

    The program consist one variable and four event handlers in one form. The variable holds the result set.

    Private Ds As DataSet

    The first function responds to the Load event of the form. This function restores the last values that from the textboxes. This is just for user convenience.

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) _
    Handles MyBase.Load
        txtCn.Text = CType(Application.UserAppDataRegistry.GetValue("Cn", ""), String)
        txtQuery.Text = CType(Application.UserAppDataRegistry.GetValue("Query", ""), String)
    End Sub

    The second function responds to the Close event of the form. This function saves the values from the textboxes so that they can be restored (in the Load event) in the next session. Also, if needed, it disposes the dataset variable.

    Private Sub Form1_FormClosed(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosedEventArgs) _
    Handles Me.FormClosed
        Application.UserAppDataRegistry.SetValue("Cn", txtCn.Text)
        Application.UserAppDataRegistry.SetValue("Query", txtQuery.Text)
        If Not Ds Is Nothing Then
            Ds.Dispose()
        End If
    End Sub

    This is the handler for the test button. It simply connects to the given data source, and tells if it succeeds or fails.

    Private Sub btnTestConnection_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
    Handles btnTestConnection.Click
        'Jump to the connection tab (the first one).
        TabControl1.SelectedTab = tabConnection
    
        'Do the test.
        Me.Cursor = Cursors.WaitCursor
        Dim Success As Boolean = False
        Try
            Using Cn As New SqlClient.SqlConnection(txtCn.Text)
                Cn.Open()
                Success = (Cn.State = ConnectionState.Open)
                Cn.Close()
            End Using
        Catch ex As Exception
        End Try
        Me.Cursor = Cursors.Default
        If Success Then
            lblStatus.Text = "Connection test succeeded."
            MessageBox.Show("Connection test succeeded.", Me.Text, _
                MessageBoxButtons.OK, MessageBoxIcon.Information)
        Else
            lblStatus.Text = "Connection test failed."
            MessageBox.Show("Connection test failed.", Me.Text, MessageBoxButtons.OK, _
                MessageBoxIcon.Error)
        End If
    End Sub

    Finally, this is the handler for the execute button.

    Private Sub btnExecute_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
    Handles btnExecute.Click
        'Remove the current data table as data source of the grid.
        DataGridView1.DataSource = Nothing
    
        If Not Me.Ds Is Nothing Then
            'If there is an old data set in memory, dispose that.
            Me.Ds.Dispose()
            'To remember that no data is present, set the variable to NULL.
            Me.Ds = Nothing
        End If
      
        'Jump to the result tab (the third one).
        TabControl1.SelectedTab = tabResult
    
        'Do the query and bind the result. Quick and dirty error "handling".
        Me.Cursor = Cursors.WaitCursor
        Try
            Using Cn As New SqlClient.SqlConnection(txtCn.Text)
                Cn.Open()
                Using Cmd As New SqlClient.SqlCommand(txtQuery.Text, Cn)
                    Using Da As New SqlClient.SqlDataAdapter(Cmd)
                        Ds = New DataSet()
                        Da.Fill(Ds)
                        If Ds.Tables.Count > 0 Then
                            DataGridView1.DataSource = Ds.Tables(0)
                            If Ds.Tables.Count > 1 Then
                                Me.Cursor = Cursors.Default
                                MessageBox.Show("More than one dataset was returned.", "Query", _
                                    MessageBoxButtons.OK, MessageBoxIcon.Information)
                            End If
                        Else
                            Me.Cursor = Cursors.Default
                            MessageBox.Show("No dataset was returned.", "Query", _
                                MessageBoxButtons.OK, MessageBoxIcon.Information)
                        End If
                    End Using
                End Using
                Cn.Close()
            End Using
            lblStatus.Text = "Success."
        Catch ex As Exception
            lblStatus.Text = "Failed. " & ex.Message
                Me.Cursor = Cursors.Default
            MessageBox.Show(ex.Message, "Failed", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try
        Me.Cursor = Cursors.Default
    End Sub

    So, making a personal query tool doesn’t have to take more than a couple of minutes in .NET.

  • ASP.NET 4.0: Diagrams

    To get your hands on this new and cool feature, create an ASP.NET 4.0 application or web site from within Visual Studio 2010. Check the Data section of the Toolbox window for a new control called Chart. Dragging out a Chart onto a web page creates the following code:

    <asp:Chart ID="Chart1" runat="server">
      <Series>
        <asp:Series Name="Series1">
      </asp:Series>
      </Series>
        <ChartAreas>
          <asp:ChartArea Name="ChartArea1">
        </asp:ChartArea>
      </ChartAreas>
    </asp:Chart>

    There is a huge amount of properties available for the chart. They control the look of the chart, the chart type among other things. I don’t have any databases installed on this computer, so to get some data to do a chart from; I connect the control to a data source that represents the system database master. I use the following query to get a bunch of large numbers:

    SELECT [name],[number] FROM dbo.spt_values WHERE [number]>17000

    I use number as Y value member.

    This is what I have to do to get the fully functional chart! Fooling around with chart types and visual properties is dangerously amusing.

    If you haven’t got a database server at all, you can quickly create an object data source in Visual Basic, and assign that to your chart. Connection this code…

    Public Class MyChartData
    
        Private mValue As Integer
    
        Public Sub New(ByVal Value As Integer)
            Me.mValue = Value
        End Sub
    
        Public ReadOnly Property Value() As Integer
            Get
                Return Me.mValue
            End Get
        End Property
    
        Public Shared Function GetItems() As MyChartData()
            Dim Ret As New List(Of MyChartData)()
            Ret.Add(New MyChartData(10))
            Ret.Add(New MyChartData(20))
            Ret.Add(New MyChartData(15))
            Ret.Add(New MyChartData(25))
            Return Ret.ToArray()
        End Function
    
    End Class

    …gives you this beautiful result:

    Ah, the simplicity! Aaaaah, the power!

  • The ups and downs of Visual Studio 2010: Fonts and scaling

    The first time I head of the zoom feature of VS2010 was in a talk by Dag König at Microsoft. The level of readability is a very important question for me, and the font rendering of Windows (Clear Type) is superb compared to the blurry font rendering that Macintosh has. The big question, does the zoom feature affect the font rendering of the text editor? To the left, Visual Studio 9 with Consolas 8. To the right, Visual Studio 2010 with Consolas 8.

    VS2010 still uses clear type, and the readability is still there. The hue is slightly reduced, if the anti aliasing is too gray, the text will appear blurry as it does on a Macintosh that only uses a gray scale for smoothing edges. The upper side of reducing the hue is that smoothing works better with text in different colors.  In VS2010, the default color for a class keyword in Visual Basic is cyan as opposed to black in VS9.

    And the zooming feature: Hold down Ctrl and use your mouse wheel. Not a feature I use every day – I use a font size that I can read without zooming, but really cool to use in presentations.

    The .NET Framework lets you control how text is rendered in your programs. The property of the Graphics object you use to control this is called TextRenderingHint. Examine this code:

    Private Sub Form1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) _
        Handles Me.Paint
        Using B As New System.Drawing.Bitmap(300, 300)
            Using G As System.Drawing.Graphics = System.Drawing.Graphics.FromImage(B)
                Using F As New System.Drawing.Font("Consolas", 10)
                    G.FillRectangle(Brushes.White, 0, 0, 300, 300)
    
                    'Regular smoothing
                    G.TextRenderingHint = Drawing.Text.TextRenderingHint.AntiAlias
                    G.DrawString("Hello", F, Brushes.Black, 10, 10)
    
                    'Regular smoothing with grid fit
                    G.TextRenderingHint = Drawing.Text.TextRenderingHint.AntiAliasGridFit
                    G.DrawString("Hello", F, Brushes.Black, 10, 25)
    
                    'Clear Type smoothing with grid fit
                    G.TextRenderingHint = Drawing.Text.TextRenderingHint.ClearTypeGridFit
                    G.DrawString("Hello", F, Brushes.Black, 10, 40)
    
                End Using
            End Using
            e.Graphics.DrawImage(B, 0, 0)
        End Using
    End Sub

    The option called AntiAlias renders text in a similar way to the Macintosh. The text appears blurry, but the outcome has true proportions, meaning that what you see on screen is a blurrier version of what you would see on a printed version. This option works best in high resolutions and for print previewing.

    The AntiAliasGridFit makes the text less blurry, because letters align to the pixel grid of the screen. The downside is that character spacing is incorrect, but readability is much higher. This option works best with CRT screens.

    The ClearTypeGridFit also aligns characters to the pixel grid, but it uses clear type. This option works best with a flat screen.

    The output from the above code is shown here:

  • The ups and downs of Visual Studio 2010: Call Hierarchy

    The function that finds all references to a function or a variable has been in Visual Studio for a few versions now. VS2010 has a similar feature called Call Hierarchy. Right click on any function definition or function call, and click View Call Hierarchy. This shows the Call Hierarchy window with a tree structure that displays what other functions are called from the function you clicked on, and who is calling it. This can help discover unused code and understanding the call stack of a program. In C#, not in Visual Basic. The View Call Hierarchy isn’t there if you right click on a Visual Basic function in VS2010 Beta 2. A quick look at Microsoft Connect tells me that the subject has been brought up, but nothing else has happened yet.

    One thing that does work, is the automated generation of sequence diagrams. VS2010 not only does this automatically, but the output is also editable. Objects on the diagram can be resized, moved or deleted, and new items can be added. All you have to do is click Generate Sequence Diagram.

  • PowerShell and Windows 7

    I should have posted this long ago, but here it is. I did not manage to install PowerShell 2.0 on Windows 7. Windows complained about a newer version that already was supposed to exist on the system. And yes, just open the Run dialog (Win+R) and type powershell, and there it is.

    To start the graphical version, type powershell_ise in the Run dialog.

    If you want to be able to start it without doing any typing, you can right click on it in the taskbar, and select Pin this program to taskbar.

  • Compressing Genesis

    From here, I have downloaded Genesis to see what the GZip stream is good for. GZip is suitable for compressing text, because the file format is totally clean (uncompressed) and the Deflate algorithm manages therefore to compress text to a high ratio. And I like the simile that deflating Genesis leaves very little left. It sort of works with my naturalistic worldview.

    The function, CompressText is unchanged, so I only show the Main subroutine.

    Sub Main()
    
        'Load genesis.
        Dim S As String
        Using Sr As New System.IO.StreamReader("genesis.txt", System.Text.Encoding.UTF8)
            S = Sr.ReadToEnd()
            Sr.Close()
        End Using
    
        Console.WriteLine("{0} characters, {1} bytes.", S.Length, S.Length * 2)
    
        'Compress it, and display the result.
        Dim B() As Byte = CompressText(S)
        Console.WriteLine("Compressed to {0} bytes.", B.Length.ToString())
    
        Console.WriteLine("Difference: {0}%", (((S.Length * 2) / B.Length) * 100).ToString("n0"))
    End Sub

    In this case, the uncompressed version is 588% of the size of the compressed version.

  • Compressing text

    I had a situation today when I had to fit about 12.000 bytes of text in 5.000 byte storage. In .NET, this is so easy to do. Just a few lines of code is required to convert a long String to a short Byte array. Examine the CompressText function. This particular example, compresses 252 characters to 287 bytes, but on larger text pieces, the effect is better. Enjoy!

    Module Module1
    
        Sub Main()
    
            'For the example, create some text!
            Dim S As New System.Text.StringBuilder()
            S.Append("This is some text that I want to compress. ")
            S.Append("Uncompressed, this text of 252 characters ")
            S.Append("consumes 504 bytes of memory with UTF-8 ")
            S.Append("encoding. The effect of the compression ")
            S.Append("is much better with a larger piece of text. ")
            S.Append("Compressing XML this way is very effective.")
    
            'Compress it, and display the result.
            Dim B() As Byte = CompressText(S.ToString())
            Console.WriteLine("Compressed to {0} bytes.", B.Length.ToString())
    
        End Sub
    
        Private Function CompressText(ByVal T As String) As Byte()
            Dim B() As Byte = System.Text.Encoding.UTF8.GetBytes(T)
            Using MemStream As New System.IO.MemoryStream()
                Using GZStream As New System.IO.Compression.GZipStream(MemStream, _
                 IO.Compression.CompressionMode.Compress)
                    GZStream.Write(B, 0, B.Length)
                    GZStream.Close()
                    Return MemStream.ToArray()
                End Using
            End Using
        End Function
    
    End Module
    
  • Collection initializers

    Now I have had the opportunity to try out the new collection initializers of Visual Basic 10. This is good stuff and I am very happy about being able to do line breaks when I use this (just as C programmers can do whenever they want). Examine this simple example that consist of a ContactPerson class, and a generic collection that I initialize using the collection initializer.

    Module Module1
    
        Public Class ContactPerson
            Public FirstName As String
            Public LastName As String
            Public EMail As String
    
            Public Overrides Function ToString() As String
                Return Me.FirstName & " " & Me.LastName & " " & Me.EMail
            End Function
        End Class
    
        Sub Main()
    
            Dim L As New List(Of ContactPerson) From {
             {New ContactPerson With {.FirstName = "Anders", .LastName = "Andersson", .EMail = "anders@some.thing"}},
             {New ContactPerson With {.FirstName = "Bertil", .LastName = "Bengtsson", .EMail = "bertil@some.thing"}},
             {New ContactPerson With {.FirstName = "Calle", .LastName = "Ceder", .EMail = "calle@some.thing"}}
             }
    
            For Each P As ContactPerson In L
                Console.WriteLine(P.ToString())
            Next
    
        End Sub
    
    End Module

    Note that the element type does not require any special constructor, I can provide a constructor and target that, but here I am using the object initializer that was introduced in Visual Basic 9.

    Instead of the parenthesis that I would use to call the List constructor, I use the From keyword with a curly bracket, and each element is surrounded by curly brackets, separated by a comma. Finally, I have to use another set of curly brackets because I use the object initializer for each element, instead of a regular constructor.

    If I adapt this code to use a constructor for each element, this is how it could look. This uses the new collection initializer and traditional constructors (and therefor less curly brackets).

    Module Module1
    
        Public Class ContactPerson
            Public Sub New(ByVal FirstName As String, ByVal LastName As String, ByVal EMail As String)
                Me.FirstName = FirstName
                Me.LastName = LastName
                Me.EMail = EMail
            End Sub
            Public FirstName As String
            Public LastName As String
            Public EMail As String
    
            Public Overrides Function ToString() As String
                Return Me.FirstName & " " & Me.LastName & " " & Me.EMail
            End Function
        End Class
    
        Sub Main()
    
            Dim L As New List(Of ContactPerson) From {
             {New ContactPerson("Anders", "Andersson", "anders@some.thing")},
             {New ContactPerson("Bertil", "Bengtsson", "bertil@some.thing")},
             {New ContactPerson("Calle", "Ceder", "calle@some.thing")}
             }
    
            For Each P As ContactPerson In L
                Console.WriteLine(P.ToString())
            Next
    
        End Sub
    
    End Module
  • How to download a file, the PowerShell way

    If you want to try this out, please read this first. There, I did an upload using FTP with network credentials (username and password). This time, I want to show how to download a file using HTTP. I am using PowerShell 2.0.

    #Load the System.Net namespace.
    [System.Reflection.Assembly]::Load
    ("System.Net, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")
    
    #Load the System.IO namespace.
    [System.Reflection.Assembly]::Load
    ("System.IO, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")
    
    #The target filename on the local system.
    $Target =  "C:\downloaded.wav"
    
    #Full source path.
    $RemoteSource = "http://www.mysite.com/myfile.wav"
    
    #Use the static method Create to create a web request.
    #Pass the destination as an argument, and cast it to a HttpWebRequest.
    $R=[System.Net.HttpWebRequest][System.Net.WebRequest]::Create($RemoteSource)
    
    #If not anonymous requests are allowed, you can
    #add a System.Net.NetworkCredential to the Credentials
    #property of the request object ($R).
    
    #What kind of method it will represent? A http request.
    $R.Method = "GET"
    
    #Execute and grab the response object (System.Net.WebResponse).
    $Resp = $R.GetResponse()
    
    #Get a reference to the response stream (System.IO.Stream).
    $RespStream = $Resp.GetResponseStream()
    
    #Create a stream to write to the file system.
    $Wrt = [System.IO.File]::Create($Target)
    
    #Create the buffer for copying data.
    $Buffer = New-Object Byte[] 1024
    
    #In an iteration...
    Do {
    
    #...attemt to read one kilobyte of data from the web response stream.
    $BytesRead = $RespStream.Read($Buffer, 0, $Buffer.Length)
    
    #Write the just-read bytes to the target file.
    $Wrt.Write($Buffer, 0, $BytesRead)
    
    #Iterate while there's still data on the web response stream.
    } While ($BytesRead -gt 0)
    
    #Close the stream.
    $RespStream.Close()
    $RespStream.Dispose()
    
    #Flush and close the writer.
    $Wrt.Flush()
    $Wrt.Close()
    $Wrt.Dispose()
    

    Happy coding!

  • Referring to a function

    Delegates are used to refer to a function. You define a delegate class (one row) using the keyword Delegate, and when it is created, or instantiated, the instance refers to a function. The code that reaches the delegate instance, can call the function it refers to, no matter if it reaches the function itself. This is a very simple example in a form:

    Public Class Form1
    
        Friend Delegate Sub MyDelegateClass()
    
        Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            Dim X As New MyDelegateClass(AddressOf Me.DoSomething)
            X()
            X()
        End Sub
    
        Private Sub DoSomething()
            MessageBox.Show("Hello!")
        End Sub
    
    End Class
    

    The result of this code is of course that the message box is shown twice. In this example, I don’t accomplish anything with the delegate, because I could have called the function DoSomething directly, but delegates can be used to pass functions as parameters or for thread shifting (se the InvokeRequired property).

    If I want, I can use the Function keyword to add a anonymous function to the delegate constructor instead of a the name of a existing function.

    Public Class Form1
    
        Friend Delegate Sub MyDelegateClass()
    
        Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            Dim X As New MyDelegateClass(Function() MessageBox.Show("Hello"))
            X()
            X()
        End Sub
    
    End Class
    

    The limitation of anonymous functions in Visual Basic 9 is that they only can contain one statement. It can still be used to do pretty good functional programming. Parameters are supported.

    If I was to pass a function as a parameter to another function, the type of the parameter would be the delegate class, like this:

    Public Class Form1
    
        Friend Delegate Sub MyDelegateClass()
    
        Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            Dim X As New MyDelegateClass(Function() MessageBox.Show("Hello"))
            Me.CallSomething(X)
        End Sub
    
        Private Sub CallSomething(ByVal X As MyDelegateClass)
            X()
            X()
        End Sub
    
    End Class
    

    Again, the result will be that two message boxes are shown.

  • Functions: Passing by value and by reference

    This is really one of the simplest concepts ever, but since this is something that you need to know as well as something you can benefit from knowing, I think it can be worth a post. Consider this this code:

    Class MyProgram
    
        Shared Sub Main()
            Dim X As Integer = 10
            DoSomething(X)
            Console.WriteLine(X)
        End Sub
    
        Private Shared Sub DoSomething(ByVal X As Integer)
            X += 1
        End Sub
    
    End Class
    

    The output you get here is of course 10. X in DoSomething is different from X is Main, and the variable X in DoSomething is just initialized with the value 10, and then it is increased by one to 11 and thereafter it is destroyed, leaving X in main with the value 10. This is because the parameter is passed by value (ByVal).

    If I was to change the parameter in DoSomething to be passed by reference instead, as in the following code, the output would be 11.

    Class MyProgram
    
        Shared Sub Main()
            Dim X As Integer = 10
            DoSomething(X)
            Console.WriteLine(X)
        End Sub
    
        Private Shared Sub DoSomething(ByRef X As Integer)
            X += 1
        End Sub
    
    End Class
    

    This is because DoSomething no longer holds an own integer variable, just a reference to the variable that is passed by the caller, Main. When X in Main is passed to DoSomething, and DoSomething is manipulating that value, the value is changed.

    When I work with objects, the rules are the same, but the effect is different. If I was to pass a bitmap to a function, and the function then is manipulated, the original bitmap will be affected no matter if it is passed by value or by reference (ByRef). This is because the value of the bitmap object variable is a reference to the actual object, and a reference to a object variable also is a reference to the same actual object.

    Consider this code:

    Class MyProgram
    
        Shared Sub Main()
            Dim B As New System.Drawing.Bitmap(100, 100)
            DoSomething(B)
            Console.WriteLine(B.Width.ToString())
        End Sub
    
        Private Shared Sub DoSomething(ByVal B As System.Drawing.Image)
            B = New System.Drawing.Bitmap(200, 200)
        End Sub
    
    End Class
    

    The output will be 100, because when you change the value of an object variable (the value of an object variable is the reference to the actual object) the passing variable is not affected, because the code holds two variables: B in Main and B in DoSomething. Changing the value of B in DoSomething will not affect B in Main.

    Changing the ByVal in DoSomething to ByRef, would give an output of 200, since the code then only would contain one variable: B in Main. DoSomething will simply refer to that variable.

  • Functions: Shadowing

    Over the years, functions has grown to become a quite complex and flexible feature in Visual Basic. The striking flexibility of the parameters, the modifiers that can apply a function and the function attributes, gives you great possibilities when you are coding. Some of the techniques include multiple return values and recursion and some of the features include passing by value, passing by reference, parameter arrays and shadowing. Shadowing is a feature that I find very useful when designing dialogs.

    The ShowDialog function, that is inherited from the Form class, is a common subject of shadowing for me. It holds two overloads, one parameterless and one that takes the owner form. Shadowing lets you create a new version of a function, no matter if it is overridable or not, and at the same time block all current overloads. So any form that I want to add a mandatory parameter to, I shadow the ShowDialog function. This is a typical function declaration in my Windows applications:

    Public Shadows Function ShowDialog(ByVal Owner As IWin32Window, _
    ByVal CustomerID As Integer) As DialogResult

    By automagic, the current versions of ShowDialog in my form disappears, and this function (the function that does the shadowing) is the one that can be called to display the form as a dialog. A implementation could look like this:

    Public Shadows Function ShowDialog(ByVal Owner As IWin32Window, _
    ByVal CustomerID As Integer) As DialogResult
       Me.mCustomerID = CustomerID
       Return MyBase.ShowDialog(Owner)
    End Function

    The initialization would then be done in the Load event.

    Shadowing is one of the killer features that from what I know is quite unique for Visual Basic.

  • Calling a function

    The parenthesis are important when you are calling a function in PowerShell. The parenthesis tells PowerShell that you intend to call the method, not acquire a reference to it. This code illustrates this.

    $random = New-Object System.Random
    $response1 = $random.next
    $response2 = $random.next()

    The $response1 variable will contain a reference to the function next, and the $response2 variable will contain an integer value, like 1611459187. The type of $response1 is System.Management.Automation.PSMethod and the type of $response2 is int32. If you want to use the reference to the function, use its Invoke method:

    Write-Output $response1.Invoke()

    To call static function, type the path to the function (namespaces and classes) followed by a double colon (::), and then the name of the function. Parenthesis are required, even if the function doesn’t take any parameters.

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

  • How to upload a file, the PowerShell way

    If you haven’t activated scripting in PowerShell, do that first.

    To access the System.Net namespace, I have to load it using the Load method (System.Reflection.Assembly.Load). To know what version and public key you must refer to, check the System.Net item in Explorer (C:\Windows\assembly).

    This is the code, directly converted from the Visual Basic version:

    #Load the System.Net namespace.
    [System.Reflection.Assembly]::Load
    ("System.Net, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")
    
    #The full path to the source file.
    $Source =  "C:\MyFiles\SourceFile.txt"
    
    #The full destination path (will be created).
    $Destination = "ftp://www.myserver.com/myfolder/destination.txt"
    
    #Use the static method Create to create a web request.
    #Pass the destination as an argument, and cast it to a FtpWebRequest.
    $R=[System.Net.FtpWebRequest][System.Net.WebRequest]::Create($Destination)
    
    #Tell the request how it will login (using a NetworkCredential object)
    $R.Credentials = New-Object System.Net.NetworkCredential("myUsername", "P@ssw0rd")
    
    #...and what kind of method it will represent. A file upload.
    $R.Method = "STOR"
    
    #Here I use the simplest method I can imagine to get the
    #bytes from the file to an byte array.
    $FileContens = [System.IO.File]::ReadAllBytes($Source)
    
    #Finaly, I put the bytes on the request stream.
    $S = $R.GetRequestStream()
    $S.Write($FileContens, 0, $FileContens.Length)
    $S.Close()
    $S.Dispose()

    This code gives a good example on PowerShell syntax and it clearly illustrates the power and versatility of the language.

    I used Graphical Windows with PowerShell 2.0 to do this example.

    This example shows how to download a file using PowerShell.

  • EnsureMaximumSize and GetThumbnail

    The WsImage class wraps a System.Drawing.Bitmap object. It has two methods to control size called EnsureMaximumSize and GetThumbnail. These are the differences:

    EnsureMaximumSize transforms the bitmap that is encapsulated in the WsImage object, GetThumbnail returns a bitmap and leaves the encapsulated bitmap unchanged.

    EnsureMaximumSize maintains the aspect ratio of the picture and the bitmap object, GetThumbnail returns a rectangular bitmap object with a the original picture drawn onto it. The picture still has maintained aspect radio. You can pass a brush object to control the background, or pass null (Nothing) if you want the background to be transparent.

    The similarity is that both EnsureMaximumSize and GetThumbnail only takes one integer parameter to control size. That integer represents the width if the width is larger than the height, otherwise it represents the height.

    If you load an image sized 800×600 and pass 700 to the EnsureMaximumSize function, it will return True and the image will be sized 700×525. If you load an image sized 300×400 and pass 350 to the EnsureMaximumSize function, it will return True and the Image will be sized 262×350 pixels. If you load an image sized 300×400 and pass 450 to the EnsureMaximumSize function, it will return False and the image will not be resized.

    Download WsImage.

  • My and Microsoft.VisualBasic namespaces

    I never use the Microsoft.VisualBasic namespace, and I don’t think that it is there for other purposes than backwards compatibility with Visual Basic 6, with the possible exception of flirting with people who think this (C#)…

    Interaction.MsgBox(Strings.Mid("Hello", 2, 2),MsgBoxStyle.OkOnly,"Extract [el]");

    …for some reason makes more sense than this:

    MessageBox.Show("Hello".Substring(1, 2), "Extract [el]");

    The Microsoft.VisualBasic namespace is a part of the .NET Framework, but perhaps not your main focus if you don’t have some old converted VB6 code that you are managing. The My namespace however, is made me throw away parts of my own code libraries, because the My namespace gives you functions to call in your application that does common tasks, like uploading a file or playing a sound. The My namespace is only available in Visual Basic, as apposed to the Microsoft.VisualBasic namespace that can be used from any .NET language.

    Extending the My namespace

    Like any namespace in your application (and your application is where My belongs), just encapsulate your class in a namespace with the same name as you want to append your class to. This code adds Class1 to the My namespace (vb.net).

    Namespace My
       Public Class Class1
    
       End Class
    End Namespace

    But what if you want to extend the existing classes, like My.Computer, with new functions? If you add a new class called Computer in the My namespace, you are actually shadowing the existing Computer class, making it unavailable. But there is a compiler trick here. Add a class called MyComputer to the My namespace. The prefix My of the class name, tells the compiler that you are extending the My.Computer class. Also, set the access level of the MyComputer class to Friend, like so:

    Namespace My
       Friend Class MyComputer
          Public Sub Hello()
    
          End Sub
       End Class
    End Namespace

    Now, the Hello method is added to the My.Computer class.

    If you like, you can create hidden modules instead of classes when you are extending the My namespace.

  • The splat operator

    I must admit that I am not completely up to date with PowerShell 2.0 (PS2), even though the CTP (community technology preview) has been out for a while. The first thing that you will notice, is that you are no longer bound to the old console window. PS2 comes with a graphical editor that separates runspaces in tabs, and each tab has three sections; a script editor, an output window and a direct window that executes what you type, in the same way that the console window did. Since this is a WPF application (as apposed to a console application), you can use the regular cut and paste features in Windows.

    Some of the other new features includes the splat operator, remoting, Add-Type and ScriptCmdlets.

    The splat operator allows you to pass multiple pairs of keys and values to one single parameter.

    This is the basic idea of hash tables in PowerShell:

    Here, I want a function that can take one parameter. That parameter will be a hash table. The only line in the function write outs the value that is assigned to the key “test”:

    function splatMe($arg) { write-output $arg["test"] }

    When that function is added to the runspace, I create a hash table using the splat operator (@):

    $hello = @{"test"="1"; "tjo"="2"}

    I can now call the splatMe function, passing $hello (my hash table) as a parameter like so:

    splatMe $hello

    The result will be “1”. I also have the option of creating the hash table on the fly:

    splatMe @{"x"="hello"; "test"="Mr. Bean"; "z"="yepp!"}

    The output will be “Mr. Bean”.

    Remoting allows execution of cmdlets and scripts on remote machines.

    Add-Type lets you compile and use fragments of code from any .NET language.

    ScriptCmdlets lets you build new cmdlets using PowerShell script, as regular cmdlets had to be written in Visual Basic or C# and had to be compiled.

  • PhotoName improvements, September 2009

    Two changes have been made.

    PhotoName does a more effective image caching to be able to display thumbnails faster, and a directory list is added.

    The directory list can be used to navigate to any child directory or to the parent directory, without having to open the folder browser. Also, the directory list tells you if any child directory has own child directories or images.

    Download PhotoName from this page, but remember to uninstall any previous version first.

  • How to upload a file

    First I must mention that this is my first ever blog post using Windows Live Writer. The topic was inspired by a question that was raised on the MSDN forums. How do I upload a file, and how can I control the remote filename? This is how it could be done:

    'The full path to the source file.
    Dim Source As String = "C:\MyFiles\SourceFile.txt"
    
    'The full destination path (will be created).
    Dim Destination As String = "ftp://www.myserver.com/myfolder/destination.txt"
    
    'Use the static (shared) method Create to create a web request.
    'Pass the destination as an argument, and cast it to a FtpWebRequest.
    Dim R As System.Net.FtpWebRequest = CType(System.Net.WebRequest.Create(Destination), _
    System.Net.FtpWebRequest)
    
    'Tell the request how it will login (using a NetworkCredential object)
    R.Credentials = New System.Net.NetworkCredential("myUsername", "P@ssw0rd")
    
    '...and what kind of method it will represent. A file upload.
    R.Method = System.Net.WebRequestMethods.Ftp.UploadFile
    
    'Here I use the simplest method I can imagine to get the
    'bytes from the file to an byte array.
    Dim FileContens() As Byte = System.IO.File.ReadAllBytes(Source)
    
    'Finaly, I put the bytes on the request stream.
    Using S As System.IO.Stream = R.GetRequestStream()
       S.Write(FileContens, 0, FileContens.Length)
       S.Close()
    End Using

    You could increase the level of control by replacing the ReadAllBytes call with some own code to read the bytes. This might be interesting if you’re for example are handling larger files, and want to show progress. To give away all control, you can use the already build function My.Computer.Network.UploadFile.

  • Using the BuildString class

    This might be a bit geeky, but I just love it. Do you have some old CRT screen lying around at home? That is your new debug window! The CodeProject user Tomzhu has made a class for easy message sending and receiving between Windows programs, the BuildString class. So, I did the simplest ever fullscreen application (ScreenOut.exe) that uses the BuildString class as it is, to display incoming messages. (Yes, it is the simplest fullscreen application ever – consider it a proof of concept, nothing more.)

    ScreenOut.exe asks for a screen to use at startup. To the left, I have my CRT running ScreenOut, and to the right I have Visual Studio (and some RSS reader). All I have to do, is make sure ScreenOut is running, if it isn’t nothing will happen.

    In the program that I want to send data from, I add the BuildString class, and I do some changes to adapt it to my ScreenOut. First, I change the scope of the existing PostString function from Public to Private. Then I add a new static (Shared in Visual Basic) function, SendString, that will use the PostString function.

    Public Shared Sub SendString(ByVal Text As String)
      Dim hwnd As Integer = FindWindow(vbNullString, "ScreenOut")
      If Not hwnd = 0 Then
        Dim Bs As New BuildString()
        Bs.PostString(hwnd, 1024, 0, Text)
      End If
    End Sub

    This function asks for the ScreenOut application, and will find it by its name if it’s running. And if so, it will use the original PostString function to send data to ScreenOut. Note that I have to declare the FindWindow function.

    Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" _
    (ByVal lpClassName As String, ByVal lpWindowName As String) _
    As Integer

    And now, as if by magic, I have my own CRT screen that I can dump any junk onto, from multiple instances of Visual Studio. Whenever I want to send a message, I just call the SendString function.

    #If DEBUG Then
       BuildString.SendString("Hello, external screen!")
    #End If

    Just for the fun of it, if you use the #err prefix, the text will come out in red color.

    #If DEBUG Then
       BuildString.SendString("#err Oh no!")
    #End If

    Have fun!

  • F# functions

    Functions are declared using the let keyword, followed by a name, a parameter list and a definition.

    This creates a function that adds to values and returns the result (first line). The two middle lines calls the function.

    let myFunction x y = x + y
    
    let result1 = myFunction 10 20
    let result2 = myFunction 15 25
    
    printfn "%d %d" result1 result2

    The last line prints the result to the screen. It should be 30 40.

    To specify the type of a parameter, you encapsulate it in parentheses, together with the type name. In this example, only the first parameter has a given type:

    let myFunction (x:int) y = x + y

    To specify the return type, add a colon followed by a type name. The following function divides a value in three. The first line is the function declaration, the second line is a call (note that I cast a int constant to a float), and the third line prints the result to the screen.

    let divInThree (t:float) = t / (float)3 : float
    let result = divInThree ((float)18)
    printfn "%f" result

    The result should be 6.

  • Conditions and iterations in F#

    Conditions
    This code will first assign a value to a and b, and print the values out. Thereafter, it will assign a value to c, that depends on the value of a. The value will be 20. Finally, it will print out both a, b and c.
    A programmer at NASA.

    let a=1
    let b=2
    printfn "%d %d" a b

    let c=
    if a=0 then 10
    elif a=1 then 20
    else 30

    printfn "%d %d %d" a b c

    Iterations
    This code will print eleven numbers on screen, from 10 to 20:

    for x in 10..20 do printfn "%d" x

    Unlike Visual Basic and C#, indentations actually means something in F#. Look at this iteration. The output is one two one two one two:

    for x in 1..3 do
    printfn "one"
    printfn "two"

    But just by changing the indentation (removing the indentation before the second prinfn), the output is changed to one one one two. The second printfn is no longer a part of the iteration.

    for x in 1..3 do
    printfn "one"
    printfn "two"

    You can also do while-iterations, that is, iterations that executes while a condition is true.

  • Using the framework from F#

    Just by typing the open statement, you can use the .NET Framework, or any other referenced libraries. To access the Console type, just add the following line to your source code:

    open System

    This program uses the built-in library function printfn, and then the WriteLine function to write “Hello world” to the screen.

    printfn "Hello world"
    open System
    Console.WriteLine("Hello world")

    So, displaying a message box, is just a matter of adding a reference to System.Windows.Forms, and this is how it could be done:

    let x=System.Windows.Forms.MessageBox.Show("Hello world")

    Or like so:

    open System.Windows
    let y=Forms.MessageBox.Show("Hello world")

    Or even:

    open System.Windows.Forms
    let z=MessageBox.Show("Hello world")

  • Things to know about F# before getting started and mutable variables

    F# is a .NET enabled functional programming language that has features that you would expect such a language to have (lists, tuples, pattern matching and so on), as well as the features you would expect from a .NET language such as preemptive multitasking, dynamic linking and Unicode strings. The program starts from the top of your source file instead of in a main function (as C# or Visual Basic), and the language is case sensitive, like C#. The editor support in Visual Studio 2008 slightly more limited than for C# or Visual Basic; you can still work with breakpoints and the locals window but perhaps not with code suggestions or code tips.
    This example creates an integer, initialized with the value 10, and prints it out:

    let x = 10
    printfn "x=%d" x

    If I wanted to assign a new value to x like below (complete source is shown, not just changes), a compile error will occur, telling me that x is not mutable – it can not change it’s value.

    let x=10
    printfn "x=%d" x
    x <- 11
    printfn "x=%d" x

    The keyword mutable at declaration, gives x the capability to chainge.

    let mutable x=10
    printfn "x=%d" x
    x <- 11
    printfn "x=%d" x

  • F# and PhotoName

    I have just decided to look in to F#, the new functional .NET language by Microsoft. It installs with Visual Studio 2010, and it can be installed for Visual Studio 9. I use Visual Studio 9 for my everyday work, so I installed it from here (click on the word MSI in the first paragraph under “F# Compiler versions”). After installation, a couple of new project templates are available, including a good tutorial. Thanks for that, Microsoft!

    And now for something less positive. I got a comment today on PhotoName on a never-do-this-thing in my source code. I was storing values in the registry under HKEY_LOCAL_MACHINE, something that you might want to do in an installation process, but never in an installed program. Back in the Windows 2000 days (or even XP), I thought of the Local Machine hive key as an alternative to the Current User hive key, with bigger scope. This is not good practice, and by default in Vista, Windows prevents programs from doing this. This is good, of course, and bringing this old mistake up to the surface, so that it could be fixed. I am a Vista user myself, but I actually use PhotoName on an old XP machine, so I am very thankful that this issue was brought up, so that I could update my code. If you have an older project, that you develop on a XP machine, you should make sure that you’re not using Application.CommonAppDataRegistry.SetValue but Application.UserAppDataRegistry.SetValue instead.

    If you have an older version of PhotoName installed, uninstall it from the Control Panel before installing the new version.

  • Execute a cmdlet or PS1 script from Visual Basic

    The cmdlets in PowerShell can easily be executed from within Visual Basic. I have done this in a few Visual Basic 8 projects, and the code for doing this from Visual Basic 8 can be somewhat ugly, but in Visual Basic 9 (and .NET Framework 3.5) it is very straight forward. You will need a reference to System.Management.Automation. If you don’t have it, you will get it when you install the Windows SDK for Windows Server 2008 and .NET Framework 3.5 from here. System.Management.Automation.dll installs to C:\Program\Reference Assemblies\Microsoft\WindowsPowerShell\v1.0.

    The Runspace object will host the Pipeline object, and the Pipeline object is used to execute cmdlets or PS1 scripts.

    Some preparations: I have activated script execution and I have created a script file (C:\script.ps1) that contains one simple line: Write-Output 10+2

    'Create the runspace.
    Using R As System.Management.Automation.Runspaces.Runspace = _
    System.Management.Automation.Runspaces.RunspaceFactory.CreateRunspace()
    
       'Create the pipeline
       Using P As System.Management.Automation.Runspaces.Pipeline = R.CreatePipeline()
    
          'Open the runspace.
          R.Open()
    
          'Create each command (in this case just one)...
          Dim Cmd As New System.Management.Automation.Runspaces.Command("C:\script.ps1", True)
    
          '...and add it to the pipeline.
          P.Commands.Add(Cmd)
    
          'Execute the commands and get the response.
          Dim Result As System.Collections.ObjectModel.Collection(Of _
          System.Management.Automation.PSObject) = P.Invoke()
    
          'Close the runspace.
          R.Close()
    
          'Display the result in the console window.
          For Each O As System.Management.Automation.PSObject In Result
             Console.WriteLine(O.ToString())
          Next
    
       End Using
    End Using

    Output: 12

  • Another moderate introduction to deep support for xml

    This post is more of a reminder to my self to start to deep xml support more seriously. I have mentioned it before, but not really examined it yet. For some reason, being free from work, leaves me with less time to just code for fun, compared to when I am working. Perhaps it’s good that my vacation soon is over.

    To start off this “reminder”, I want to show how to create and manipulate an element. This creates and initializes an System.Xml.Linq.XElement:

    Dim X = <myNode>MyValue</myNode>

    To access the child value, I can use the Value property of X. I can read it or change it.

    MessageBox.Show(X.Value)

    Children are added to (called X in my example) using the Add method. This code:

    X.Add(<child name=”child1″>Hello, mate!</child>)
    X.Add(<child name=”child2″>Hello again, mate!</child>)

    Results to this xml:

    <myNode>MyValue
     <child name="child1">Hello, mate!</child>
     <child name="child2">Hello again, mate!</child>
    </myNode>

    (It is not good practice to mix child elements with text values, but this is just an example.)

    I use the ToString method to see the xml source of the XElement. To access my new children, I could get a reference using the Element method. This give me the first child (I pass the element name as an argument):

    Dim Child = X.Element(“child”)

    And to step to the next element, I could use the NextNode property:

    Child = Child.NextNode

    I hope to be able to give a practical example of this soon, but for now, I am still impressed with the deep support (meaning that the compiler detects syntax error in the xml code).