Skip to content

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)

Categories: Microsoft .NET.

Tags:

Jämförelseoperatörer och logiska operatörer

Vill du följa med i detta dokument, starta XQT och anslut dig till exempeldokumentet genom att växla till Direct mode och skriv

ConnectExample RecordCollection

För att välja element i XPath, skriver du sökvägen till elementen du vill ska ingå i resultatet. Genom att bara skriva Record, så får du alla skivor i XML-filen. Filter skrivs inom hakparenteser. Är du endast intresserad av skivor som släpptes ett visst år, använd jämförelseoperatören “lika med” =. Detta ger skivor släppta 1975.

Record[Year="1975"]

Frågan ger två skivor som svar. Vill du filtrera ytterligare, kan du använda logiska operatörer. Logiskt “och” heter and i XPath. Tänk på att XPath är skiftlägeskänsligt (And är inte samma sak som and). Denna fråga ger skivorna med Journey släppte 1975, skriv:

Record[Year="1975" and Artist="Journey"]

Vill du istället se skivorna släppta antingen år 1975 eller av artisten Roger Waters, använd logiskt “eller”. I XPath heter det or.

Record[Year="1975" or Artist="Roger Waters"]

De jämförelseoperatörer du kan använda är “lika med” (=), “inte lika med” (!=), “större än” (>), “mindre än” (<), “större än eller lika med” och “mindre än eller lika med” (>= resp. <=).

Denna fråga visar skivor som inte är släppta år 1975.

Record[Year!="1975"]

XQT finns att ladda hem från denna sida.

Categories: General.

Tags: ,

Testa XPath-frågor med XQT

Verktyget XQT (XPath Query Tool) kan användas för att analysera innehållet i en XML-fil, och att ställa frågor mot dokumentet och analysera svaret. Programmet innehåller ett inbyggt XML-dokument om du vill testa att formulera några enkla XPath-frågor. För att ladda det inbyggda XML-dokumentet, växla till direct mode genom att klicka på fliken märkt Direct eller genom att trycka Ctrl+D. Där, skriv:

ConnectExample RecordCollection

Tryck Enter och konstatera att resultatträdet nu visar texten Records (3 children). Expandera gärna noden i resultatträdet och undersök exempelfilen.

(Läget Edit mode låter dig skriva en fråga och trycka F5 för att exekvera den, medan Direct mode låter dig skriva en fråga och exekvera den genom att trycka Enter.)

XPath fungerar så att du anger sökvägen till de element du vill ha i ditt resultat. För att se vilka titlar som finns, skriv

Record/Title

…och tryck Enter.

När som helst, tryck F6 för att visa hela XML-dokumentet istället för svaret på den senaste frågan.

Två av de tre skivorna (Journey och A Night at the Opera) är släppta 1975. För att se dessa två, skriv:

Record[Year="1975"]/Title

Alla skivor har ett identitetsnummer som attribut till Record-element. För att se listan över låtar för den skiva vars attribut är 7575, skriv:

Record[@ID="7575"]/Tracks/Track

Som sista exempel, vill du bara titta på det första spåret, notera att spårens sekvensnummer ligger lagrade i ett attribut som heter Sequence, och skriv:

Record[@ID="7575"]/Tracks/Track[@Sequence="1"]

En bra guide till XPath finns här: http://www.w3schools.com/Xpath/

XQT kan du ladda hem från denna sida (direktlänk).

Categories: General.

Tags: ,

XQT is taking off after all

I still haven’t made the installation program for XQT, but it is getting close to a useful application now. This is how version 0.9 looks (click on it for full size):

In edit mode, you can type XPath queries in the editor and press F5 to execute them. The result shows up below. If text is selected when you hit F5, only the selected text will be executed. You can switch between edit mode and direct mode by clicking on the tabs or pressing Ctrl+E for edit and Ctrl+D for direct mode.

In direct mode, the query gets executed as you type it in and press Return. If you hold down Shift, a line break is created without the typed text being executed.

After querying, F6 takes you back to the root node of the XML document you are connected to. XQT.exe is located here. Since 17/1 2010, the program is available from the Programs page.

Categories: General.

Tags:

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.

Categories: Microsoft .NET.

Tags:

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.

Categories: Visual Basic 10.

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).

Categories: Visual Studio 10.

Tags:

Grafikstacken kraschar ibland

Idag drabbades jag av lite igenkänning mitt i spelprogrammeringen, som fick mig att skriva ett kort inlägg.

Det händer nästan aldrig i XP, och väldigt sällan i Vista och 7, men ibland kraschar grafikstacken, troligen för att man har gjort något fel. När det väl händer i Windows, så blinkar skärmen till i ett par sekunder, och sedan är allt återställt. Nästan. Jag klagar inte, av XWindows i Linux blir det bara skit kvar om detta händer, men Windows Vista och Windows 7 hackar till och återställer systemet utan någon förlorad data.

Men under mitt kodande på ninjaspelet på en Vista-dator har jag märkt att nätverket följer med ibland. I två situationer har jag noterat detta. Det ena var när jag klantade till det i XNA, och det andra är när Voddler klantar till det. Det kanske bara är på mitt system det blir så, men det är bra konstigt.

Men i alla fall, här vill jag säga att jag är imponerad av Windows, som klarar att återgå efter att detta har hänt, vilket jag inte tror att något annat x86-operativ klarar.

Categories: General.

Tags:

Ninjaspelet lyfter snart

Det har runnit en del vatten under broarna när det gäller ninjaspelet. Nu är jag äntligen igång och kodar. Istället för .NET 2.0/Allegro blev plattformen XNA Framework 3.1. Spelet skrivs i Visual Basic och brorsan bistår med grafik. Kvällens aktivitet har varit en sprite-klass.

Categories: General.

Tags:

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

Categories: Visual Basic 10, Visual Studio 10.

Tags: