Category: Microsoft .NET

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.