Archive for the ‘Visual Basic’ Category.

VB.NET simpler Async Await example

Well, I couldn’t let this rest, so here is an even simpler example of doing Async Await in VB.NET.

For this example code, I created a simple forms application with two buttons named cmdSynchronous and cmdAsynchronous, a label called lblStatus, and just to demonstrate the UI locking up effect, a combo box with some entries in it. Here is the code behind this form:

Public Class Form1
    Sub LongOperation()
    End Sub
    Private Sub cmdSynchronous_Click(sender As Object, e As EventArgs) Handles cmdSynchronous.Click
        lblStatus.Text = "Running a long operation synchronously... (UI thread should lock up)"
        Application.DoEvents()  ' needed here so that the label will update
        lblStatus.Text = "Done running the long operation synchronously."
    End Sub
    Private Async Sub cmdAsynchronous_Click(sender As Object, e As EventArgs) Handles cmdAsynchronous.Click
        lblStatus.Text = "Running a long operation asynchronously... (UI thread should be fully responsive)"
        Await Task.Run(Sub()
                       End Sub)
        lblStatus.Text = "Done running the long operation asynchronously."
    End Sub
End Class

Notice that both button click events call the LongOperation method, which just sleeps for 5 seconds. However, the synchronous button click will lock up the UI (try to open the combo box, you will see that it waits until the sleep is done before displaying the choice list), whereas the asynchronous one will not.

Now in general, you would probably want to keep the tasks from piling up, as they would if you keep clicking the asynchronous button. I leave this as an exercise to the reader on preventing this problem.

BTW, Happy Birthday to Gary Hoey and Terje Rypdal, two of my favorite guitarists.

VB.NET simple Async Await example

I scoured the interwebs looking for a VB.NET simple Async Await example, and kind of came up empty. So, I decided to try to use bits and pieces of the examples I could find to roll my own.

The background here is that I am working on an application that accesses resources on the internet, and did not want to block the UI while the communications code was running.

Here is the code that I came up with:

Async Function GetDetails(theID As String) As Task
    Dim url As String
    url = GET_DETAILS_URL & "?theid=" & theID
    Dim request As WebRequest = WebRequest.Create(url)
    Dim response As WebResponse = Await request.GetResponseAsync()
    Dim dataStream As Stream = response.GetResponseStream()
    Dim reader As New StreamReader(dataStream)
    Dim responseFromServer As String = reader.ReadToEnd()
    ' do something here with responseFromServer
End Function
Async Sub lstItems_SelectedIndexChanged(sender As Object, e As EventArgs) Handles lstItems.SelectedIndexChanged
    Dim idx As Integer = lstItems.SelectedIndex
    ' get the selected item
    Dim theItem As Object = itemsList(idx)
    Dim theItemID As String = theItem.itemID.ToString()
    Await GetDetails(theItemID)
End Sub

BTW, Happy Bennington Battle Day to our Green Mountain friends.

HTTP post in VBA

I have some very nice C# .NET web services that I created and use from some web sites, .NET desktop applications, and iOS apps. But of course, this is not a wide enough range of technologies that I have to deal with, so I needed to figure out how I could call my web service from within an Access database using Visual Basic for Applications (VBA).

The web service just takes in a couple of form variables, chugs through the database looking for the matching records, and returns a string with the pertinent data. Here is the VBA code that I put together to accomplish this task:

Sub Method1()
    Set objHTTP = CreateObject("WinHttp.WinHttpRequest.5.1")
    URL = ""
    objHTTP.Open "POST", URL, False
    objHTTP.setRequestHeader "Content-type", "application/x-www-form-urlencoded"
    objHTTP.send "formVariable1=value1&formVariable2=value2"
    If objHTTP.Status = 200 Then
        MsgBox objHTTP.responseText
        MsgBox "Failed at getting response from web service:" & objHTTP.Status
    End If
End Sub

The response text is being sent to a message box, but you could just as easily return that string, or better yet, use an XML parser to dig into the data for just what you need. Perhaps I will save that code for another post later.

BTW, Happy Birthday to Julie Newmar, by far the best Catwoman from any Batman live action or animated TV show or movie.

Multiplicative persistence

I saw a story this morning in Gizmodo about hard logic puzzles, and one of them caught my attention for some brute force computational processing.

Martin Gardner was a famous mathematician, and in one of his books, he talks about the persistence of a number as the number of times it iteratively takes to multiply the individual digits of an integer together until you end up with a single digit number. As an example, if you consider the number 25, the persistence is 2 because 2×5 equals 10 (step 1), and then 1×0 equals 0 (step 2).

So here is a quick algorithm I threw together in VB.NET to find the smallest number that has a particular persistence:

Module Module1
    Function Persistence(num As Integer) As Integer
        Dim n As Integer = Math.Abs(num)
        Dim p As Integer = 0
        While n >= 10
            Dim nString = n.ToString()
            n = 1
            For i = 0 To nString.Length - 1
                n *= Convert.ToInt16(nString.Substring(i, 1))
            p = p + 1
        End While
        Return p
    End Function
    Sub Main()
        Dim persistenceList As List(Of Integer) = New List(Of Integer)()
        Dim p As Integer
        For i = 1 To 10000000
            p = Persistence(i)
            If persistenceList.Count < p Then
                Console.WriteLine("Just found a persistence of " + p.ToString() + " for " + i.ToString())
            End If
        Console.WriteLine("Press any key to exit...")
    End Sub
End Module

When you run this, you see something like this in the console:

Just found a persistence of 1 for 10
Just found a persistence of 2 for 25
Just found a persistence of 3 for 39
Just found a persistence of 4 for 77
Just found a persistence of 5 for 679
Just found a persistence of 6 for 6788
Just found a persistence of 7 for 68889
Just found a persistence of 8 for 2677889
Press any key to exit...

Above a persistence of 8, it can take a very very long time to brute force a solution.

BTW, Happy Birthday to Anton Fig, a fantastic drummer who has worked with one of my favorite artists, Joe Bonamassa.

OK, you may have had a tough coach at some point growing up, but you have to let it go…

A co-worker found this nice little nugget in one of our sports web site applications:

Dim isAssHeadCoach As Boolean = Session("IsAssHeadCoach")

I hope it is meant to check for an assistant or associate head coach.

Don’t try, don’t catch

Have you ever had a situation where all of those nested try/catch blocks just get in your way when trying to chase down a problem? I just hate that.

Luckily, in Visual Studio 2008 (and other versions, I am sure), there is a handy dandy way to disable all of the try/catch blocks when you run the application in debug mode from the IDE.  Just go to the Debug menu, select Exceptions, click the box under the Thrown column for Common Language Runtime Exceptions (or others if that is what you are looking for), and click OK.  Now when the code has a problem, you see it right away instead of trying to work backwards through nested try/catch blocks in different classes and modules.

Just don’t forget to put it back to the way it was when you are done. I am not a huge fan of try/catch blocks, but their normal use definitely has its place.

Is this string numeric?

This VB code was brought to my attention.  It is meant to look at a string variable (prefixText) and decide if the string is numeric or not, and return a data set (ds) by using a different method based on the result of the numeric test. (As always, this code is in a heavily used production environment.)

If Left(prefixText, 1) = "0" Or Left(prefixText, 1) = "1" Or Left(prefixText, 1) = "2" Or Left(prefixText, 1) = "3" Or Left(prefixText, 1) = "4" Or Left(prefixText, 1) = "5" Or Left(prefixText, 1) = "6" Or Left(prefixText, 1) = "8" Or Left(prefixText, 1) = "9" Then
    ds = New Users(_ConnStr).getUsersListByNumber(prefixText)
    ds = New Users(_ConnStr).getUsersListByLastName(prefixText)
End If

I have some great ideas on how to improve this code. The first thing I would have done was to use OrElse instead of Or, it would speed things up tremendously. And I would also have added in the test for the “7” character.

2010 Central Ohio Day of .NET

A co-worker and I attended the Central Ohio Day of .NET on June 5, 2010. There was quite a bit of good content at the conference, which is a real tribute to the organizers, volunteers, and presenters.

The highlights of my day were sitting in on Matt Casto’s regular expressions talk, Phil Japikse’s M-V-VM primer, discussing the etymology of the MongoDB project with Sam Corder (I still say it was named such after the character in Blazing Saddles), Michael Eaton’s talk on WPF, and Parag Joshi’s demonstration of XNA/Windows Phone 7 game development.

VB.NET Printing For Dummies

In order to send stuff to the printer in VB.NET, it is not quite as simple as dealing with the Printer object as in VB6. There are a couple of extra steps involved. Here is what I found, along with some helper methods that you might find useful.

On the form you want to print from, pull up the Toolbox and add a PrintDocument, a PrintDialog, and a Button, set the Document property of the PrintDialog to point to the PrintDocument you just created, and in the button’s Click event, insert the following code:

    Private Sub butPrint_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles butPrint.Click
        If PrintDialog1.ShowDialog() = Windows.Forms.DialogResult.OK Then
            PrintDocument1.DefaultPageSettings.Landscape = True
        End If
    End Sub
    Private Sub PrintDocument1_PrintPage(ByVal sender As System.Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs) Handles PrintDocument1.PrintPage
        PrintTestPage(e.Graphics, PrintDocument1)
    End Sub

The Print method call in the button click event then fires the PrintDocument PrintPage event. Notice that I have set the default page settings to landscape. Don’t forget to wire the PrintDialog Document property to your PrintDocument, otherwise if you change the printer to print to in the print dialog, the document will still go to the default printer.

The PrintTestPage method is just something simple that I put together to make sure that the coordinates and justifications are all working fine. Here is that code:

    Sub PrintTestPage(ByVal g As System.Drawing.Graphics, ByVal doc As PrintDocument)
        Dim x, y As Integer
        For x = 0 To 100 Step 10
            For y = 0 To 100 Step 10
                PrintAtLocationWithColor(g, doc, x.ToString + ", " + y.ToString, x, y, _
                                         If(x = 0, "L", If(x = 100, "R", "C")), If(y = 0, "T", If(y = 100, "B", "C")), _
                                         "Arial", 8, True, Brushes.Red)
        PrintRectangle(g, doc, 0, 0, 100, 100)
        PrintRectangle(g, doc, 10, 10, 80, 80)
        PrintRectangle(g, doc, 20, 20, 60, 60)
        PrintRectangle(g, doc, 30, 30, 40, 40)
        PrintRectangle(g, doc, 40, 40, 20, 20)
    End Sub

The two methods called here, PrintAtLocationWithColor and PrintRectangle, are shown here:

    Sub PrintAtLocationWithColor(ByVal pg As Graphics, ByVal pd As PrintDocument, ByVal s As String, _
                                ByVal xPosition As Single, ByVal yPosition As Single, _
                                ByVal justification As String, ByVal verticalJustification As String, _
                                ByVal fontFace As String, ByVal fontSize As Single, _
                                ByVal fontBold As Boolean, ByVal theColor As Brush)
        Dim w, h As Single
        Dim x, y As Single
        Dim f As Font
        Dim sty As FontStyle
        sty = FontStyle.Regular
        If fontBold Then sty = sty + FontStyle.Bold
        If fontSize < 1 Then fontSize = 8.0
        f = New Font(fontFace, fontSize, sty)
        If pd.DefaultPageSettings.Landscape Then
            x = xPosition / 100 * (pd.DefaultPageSettings.PrintableArea.Height)
            y = yPosition / 100 * (pd.DefaultPageSettings.PrintableArea.Width)
            x = xPosition / 100 * (pd.DefaultPageSettings.PrintableArea.Width)
            y = yPosition / 100 * (pd.DefaultPageSettings.PrintableArea.Height)
        End If
        w = pg.MeasureString(s, f).Width
        h = pg.MeasureString(s, f).Height
        If Left(UCase(justification), 1) = "C" Then
            x = x - w / 2
        End If
        If Left(UCase(justification), 1) = "R" Then
            x = x - w
        End If
        If Left(UCase(verticalJustification), 1) = "C" Then
            y = y - h / 2
        End If
        If Left(UCase(verticalJustification), 1) = "B" Then
            y = y - h
        End If
        pg.DrawString(s, f, theColor, x, y)
    End Sub
    Sub PrintRectangle(ByVal pg As Graphics, ByVal pd As PrintDocument, ByVal xPosition As Single, ByVal yPosition As Single, _
                                ByVal width As Single, ByVal height As Single)
        Dim w, h As Single
        Dim x, y As Single
        If pd.DefaultPageSettings.Landscape Then
            x = xPosition / 100 * (pd.DefaultPageSettings.PrintableArea.Height)
            y = yPosition / 100 * (pd.DefaultPageSettings.PrintableArea.Width)
            w = width / 100 * (pd.DefaultPageSettings.PrintableArea.Height)
            h = height / 100 * (pd.DefaultPageSettings.PrintableArea.Width)
            x = xPosition / 100 * (pd.DefaultPageSettings.PrintableArea.Width)
            y = yPosition / 100 * (pd.DefaultPageSettings.PrintableArea.Height)
            w = width / 100 * (pd.DefaultPageSettings.PrintableArea.Width)
            h = height / 100 * (pd.DefaultPageSettings.PrintableArea.Height)
        End If
        pg.DrawRectangle(Pens.Black, x, y, w, h)
    End Sub

All of the positioning and size parameters of these methods are percentages across and down the page, which I find much easier to deal with than absolute or printer specific positioning. This makes it dead simple to scale the reports to any page size I want to use.

.NET Kombat (Format vs. ToString)

In converting some legacy VB6 code to VB.NET, I noticed that there was a lot of use of the Format function in the code to convert numbers to strings. This makes sense as Format was pretty much the only game in town in VB6.

However, in .NET, they introduced a handy-dandy .ToString() method that, on the surface, seems to do much the same thing as the Format function. I have been able to use them pretty much interchangeably with the desired results coming out every time.

I started to wonder which way was faster. Since I am a big proponent of empirical knowledge instead of just trying to get the theoretical story behind the two ways to do this, I rolled together this quick VB.NET console application:

Imports System.Text
Module Module1
    Sub Main()
        Dim i As Integer
        Dim r As Random = New Random()
        Dim t As Double
        System.Console.WriteLine("10,000,000 Formats")
        Dim sb1 As New stringbuilder
        t = Timer
        For i = 1 To 10000000
            sb1.Append(Format(r.NextDouble * 100.0, "###0.00 "))
        System.Console.WriteLine("Seconds elapsed: " + (Timer - t).ToString("#######0.00"))
        System.Console.WriteLine("Length of string builder: " + sb1.Length.ToString())
        System.Console.WriteLine("10,000,000 ToStrings")
        Dim sb2 As New StringBuilder
        t = Timer
        For i = 1 To 10000000
            sb2.Append((r.NextDouble * 100.0).ToString("###0.00 "))
        System.Console.WriteLine("Seconds elapsed: " + (Timer - t).ToString("#######0.00"))
        System.Console.WriteLine("Length of string builder: " + sb2.Length.ToString())
        System.Console.WriteLine("Press any key to end the program ")
    End Sub
End Module

And here are the results:

As you can see, the ToString method is about 15% faster when doing 10 million calls with random numbers.

Oh, and by the way, Happy Pancake Day.