Posts tagged ‘VB.NET’

Easy way to format the time difference between two dates

In converting my VB6 code over to VB.NET, I was looking for an easy way to take the different between two DateTime items and display in hours and minutes.  The TimeSpan gives a nice structure to dive into the difference and see exactly the interval, but I was hoping to find a way to output this in the same way that you can use the ToShortTimeString method of DateTime.

As it turns out, I found a posting by Jay Barlow that mentions converting the time different to a date time, and then using a custom format string to do the work so that I wouldn’t have to.  Here is my new VB.NET code, where rec is a class that includes the start and end date and duration is a string that holds the information to be displayed:

If rec.endDate IsNot Nothing Then
    Dim ts As TimeSpan = CDate(rec.endDate).Subtract(rec.startDate)
    Dim dt As DateTime = DateTime.MinValue.Add(ts)
    duration = "Event duration: " + dt.ToString("H:mm")
End If

Oh, and one more thing. Am I the only one in the world that thinks that iPad is the worst product name in history? Sure, it is so close to iPod so as to create brand recognition and draw comparisons, but I would just wonder what kind of names were shot down, and if any of them did not begin with the letter i.

By the way, Happy (Belated) Australia Day.

VB.NET radio button groups act differently than VB6 radio button groups

The few dozen remaining WinForms developers left on this planet may have noticed that, for some reason, a group box with radio buttons in it as designed in the Visual Studio 2008 environment will have the first radio button of the first group box automatically selected when the form comes up, even though all of the radio buttons have their Checked property set to false in the design environment.  It never used to do this in VB6, as when you ran the application, the group of radio buttons would have no members selected.

The problem manifests itself when you are trying to perform additional tasks in the CheckedChanged event of the radio buttons when the user selects one of the radio buttons, since the first radio button is being automatically selected.

I asked this question on Stack Overflow, and got a couple of replies. The one that I finally used to solve the problem was to set the Checked property of the radio buttons to false in the form’s Shown event, which I had never used before. By doing this, the first radio button was no longer automatically showing up checked.

One other thing that I had to do in addition was to cast the sender into a RadioButton and look at the Checked property of the clicked radio button in the CheckedChanged event, as that event is fired for radio buttons both being turned on and also turned off.

Oh, and happy National English Toffee Day!

Control arrays in VB.NET

One of the things that I really liked (and used quite a bit) in the VB6 IDE was the ability to use the design surface to create a form with a bunch of controls with the same name as a control array. You would create the controls on the design page, give it the same name as another control, and the Index property would automatically be incremented. This would then let me use a loop to manipulate and examine these controls.

This functionality is missing in VB.NET, as I discovered when I tried to do my first .NET Compact Framework application way back when Visual Studio 2003 was shiny and new, and has continued to be missing from the feature set in VS2005 and VS2008.

Microsoft is not much help on this front. Their solution is to create the forms in code, as described in this article:

Not so helpful link (link redacted)

But I like using the design surface to create forms. A co-worker suggested we try to do a test in C# and tamper with the designer.cs file to create an array of controls in there, which worked OK. The big problems there were that the controls showed up on the design surface, but they could not be clicked and modified. Also, when we added a control to the form and saved it, all of the customizations we made to the designer file disappeared. (Oops.)

So instead, what I am now doing is creating my forms in the designer as before, with each control of the set having a different name with a number after it (such as cboName0, cboName1, etc.), referring to the index of the control in the array. At the top of the form’s class I have the arrays defined:

Dim cboName(10) as ComboBox
Dim lblNumber(10) as Label

Then, in the form load event, I am calling this subroutine:

Sub SetUpControlArrays()
 
    For Each cb In Me.Controls.OfType(Of ComboBox)()
        If cb.Name.Contains("cboName") Then
            cboName(CInt(cb.Name.Replace("cboName", ""))) = cb
        End If
    Next
 
    For Each lbl In Me.Controls.OfType(Of Label)()
        If lbl.Name.Contains("lblNumber") Then
            lblNumber(CInt(lbl.Name.Replace("lblNumber", ""))) = lbl
        End If
    Next
 
End Sub

Now I have the ability to address the controls in the same way that I used to do in VB6. The fact that I lived with this missing feature for about 6 years and just now figuring out a decent way around the problem pretty much guarantees that VS2010 will put the control arrays back in.

EDIT: At the request of a Strong Bad fan who shall remain nameless, I changed up the code above to be a bit more friendly. The previous code only extracted the rightmost 1 character from the name of the control on the design surface, which would not work if you had a control name such as cboName10.

Demo days (CONDG meeting, December 14, 2009)

The Central Ohio .NET Developers Group held their final meeting of the year last night at the Microsoft office in Polaris. Four people gave short demos of Xbox, Zune HD, Windows Mobile, and iPhone, and talked about developing for each platform.

The highlight of the evening was my name being drawn as winning the year’s final and perhaps most craptastic door prize, which I then gave to my coworker who was attending the meeting with me. He is into free t-shirts.

2009-12-15 09.13.18

How to get the version number of a running process

I wanted to have my .NET based Palm OS conduit DLL be able to report the version of the HotSync Manager that the user has installed on their computer. Initially, I was going to try to read the version of the executable, but then I would first have to find the path to the executable, and hope that this would be a reliable enough method.

As it turns out, after I did a little investigation, I found out that it is not necessary to try and figure out where the HotSync Manager is installed by reading the appropriate registry key to get the HotSync Manager location and then trying to get the version number of the assembly at that path. Because the user is in the conduit code, the HotSync Manager (HOTSYNC.EXE) is already in the running processes list. It just so happens that in the System.Diagnostics namespace there is a handy dandy method that gets all of the running processes, along with a goodly amount of information about each process, including the version number.

So here is my VB.NET code that searches for the HotSync Manager process and returns the version number as a string.

Function GetHotSyncVersion() As String
 
    Dim versionString As String = "Unknown"
 
    Dim procList As List(Of Process) = Process.GetProcesses().ToList
    Dim hotSyncProcess As Process = Nothing
    For Each p In procList
        If p.ProcessName.ToUpper = "HOTSYNC" Then
            hotSyncProcess = p
        End If
    Next
 
    If hotSyncProcess IsNot Nothing Then
        versionString = hotSyncProcess.MainModule.FileVersionInfo.FileVersion
    End If
 
    Return versionString
 
End Function

Sorry I missed the CIDUG meeting tonight.

NetCFSvcUtil.exe error in Windows 7

I have been using Windows 7 for a while now, and always had to keep my Windows XP dev machine handy to help out with my Windows Mobile software development.

It turns out that the NetCFSvcUtil application included in the .NET CF Power Toys did not get along with Windows 7 (neither the RC or the RTM bits), as it gave a cryptic error message of “An error occurred in the tool”.

So just for giggles, I decided to see if there were any updates, and lo and behold, I found a blog post from Habib Heydarian with an updated application:

NetCFSvcUtil.exe and Windows 7

Now I can happily generate the client code on my Windows 7 machine.

Cannot enable networking in Windows Mobile emulator on Windows 7

So you are using a new Windows 7 installation and developing a Windows Mobile application, and you have been using it just fine on another dev box or in an earlier version of Windows. You deploy your application, and it needs to communicate over the internet, so you go into the Network tab of the Emulator Properties and enable the network adapter.

Only this time, it comes up with an error message about installing Virtual PC 2007.

And then you find out that Virtual PC 2007 does not play nicely with Windows 7.

Well it all has to do with Virtual Machine Network Services. Here is a blog post from Brian Peek on how to solve the problem:

Windows Virtual PC and the Microsoft Device Emulator

Monty Hall meets Monte Carlo

In honor of CBS canceling The Guiding Light after 72 years, and replacing it with a new incantation of Let’s Make A Deal, I decided to apply a little brute force computing to The Monty Hall problem.

Here is the VB.NET code to run the simulations. I decided to only apply a few different Monty Hall behaviors and a few different player behaviors, but it should be enough to drive home the paradox.

Module Module1
 
    Sub Main()
 
        Dim i, j, ctr As Integer
        Dim doorSwitch As String = "?"
        Dim smartMonty As String = "?"
        Dim prizeDoor(3) As Boolean
        Dim rand As Random = New Random()
        Dim doorMontyOpens As Integer
        Dim doorYouOpen As Integer
        Dim carsWon As Integer = 0
 
        Console.WriteLine("The Monty Hall Problem")
        Console.Write("How many times to run the simulation? ")
        ctr = Val(Console.ReadLine())
        If ctr < 1 Then End
 
        Console.Write("Are you going to switch doors? [Y/N/M] ")
        While Not "YNM".Contains(doorSwitch)
            doorSwitch = Console.ReadKey.KeyChar.ToString.ToUpper
        End While
        Console.WriteLine()
 
        Console.Write("Does Monty know where the car is? [Y/N/M] ")
        While Not "YNM".Contains(smartMonty)
            smartMonty = Console.ReadKey.KeyChar.ToString.ToUpper
        End While
        Console.WriteLine()
 
        For i = 1 To ctr
 
            ' set up the prize doors
            For j = 1 To 3
                prizeDoor(j) = False
            Next
            prizeDoor(rand.Next(1, 4)) = True
 
            Console.Write(i.ToString() + " (")
            For j = 1 To 3
                Console.Write(If(prizeDoor(j), "$", j.ToString))
            Next
            Console.Write(") -- ")
 
            ' Monty shows you a door
            If smartMonty = "Y" Or (smartMonty = "M" And _
                                    rand.NextDouble > 0.5) Then
                doorMontyOpens = If(prizeDoor(2), 3, 2)
            Else
                doorMontyOpens = rand.Next(2, 4)
                If prizeDoor(doorMontyOpens) Then
                    carsWon = carsWon + 1
                    Console.WriteLine("Monty revealed the car!!!!!")
                    Continue For
                End If
            End If
            Console.Write("Monty reveals a goat behind door #" + _
                          doorMontyOpens.ToString + " -- ")
 
            ' pick a door to open
            If doorSwitch = "Y" Or (doorSwitch = "M" And _
                                  rand.NextDouble > 0.5) Then
                doorYouOpen = If(doorMontyOpens = 2, 3, 2)
                Console.Write("You switched to door #" + _
                              doorYouOpen.ToString + " -- ")
            Else
                doorYouOpen = 1
                Console.Write("You stayed with door #1 -- ")
            End If
 
            ' did we win?
            If prizeDoor(doorYouOpen) Then
                Console.WriteLine("You won the car!!!!!")
                carsWon = carsWon + 1
            Else
                Console.WriteLine("You won the goat.")
            End If
 
        Next
 
        Console.WriteLine(" ")
        Console.WriteLine("You won the car " + carsWon.ToString + _
                          " times out of " + ctr.ToString)
        Console.WriteLine("Winning percentage: " + (carsWon * _
                            100.0 / ctr).ToString("##0.0"))
        Console.WriteLine(" ")
        Console.WriteLine("Strike any key to end...")
        Console.ReadKey()
 
    End Sub
 
End Module

Now if CBS ever decides to cancel The Young And The Restless, we are going to have a real problem on our hands.

My first foray into Code Golf

So I am poking around on Stack Overflow, trying to figure out a way for someone as stupid as me to actually move my reputation up, when I stumble on this post…

Code Golf: Duplicate Character Removal in String (EDIT: Sorry, I had to remove the link as the question was removed by Stack Overflow…)

This seemed simple enough, so here is my VB.NET console application code:

Module Module1
 
    Sub Main()
 
        Dim s As String = "nbHHkRvrXbvkn"
        Console.WriteLine("The original string is: " + s)
        For Each c In s : s = IIf(s.LastIndexOf(c) <> s.IndexOf(c), s.Replace(CStr(c), Nothing), s) : Next
        Console.WriteLine("The modified string is: " + s)
        Console.ReadKey()
 
    End Sub
 
End Module

The line that does all the work is 98 characters, including the spaces that the IDE automagically puts in there for me.

Anyone have any ideas on how to improve it in VB.NET?

Some more Monte Carlo experimentation

Disclaimer: I do not in any way, shape, or form condone gambling. This posting is for entertainment purposes only.

I saw this roulette story on The Daily WTF, and thought that it merited some good ole fashioned brute force computing:

Knocking Me Off The Perch

So here is the VB.NET console application code:

Module Module1
 
    Dim rand As Random
 
    Dim tableResults() As List(Of String)
    Dim theWheel() As String = {"G00", "B2", "R14", "B35", "R23", _
                                "B4", "R16", "B33", "R21", "B6", _
                                "R18", "B31", "R19", "B8", "R12", _
                                "B29", "R25", "B10", "R27", _
                                "G0", "R1", "B13", "R36", "B24", _
                                "R3", "B15", "R34", "B22", "R5", _
                                "B17", "R32", "B20", "R7", "B11", _
                                "R30", "B26", "R9", "B28"}
    Dim wheelCount As Integer
    Dim tableBetAmount() As Integer
    Dim tableBetColor() As String
    Dim tableLostLastTime() As String
 
    Dim tables, stake, bet, matches, goal, attempts As Integer
    Dim cancelBetAfterAWin As String
 
    Function GetASpin() As String
 
        Return theWheel(rand.Next(0, wheelCount))
 
    End Function
 
    Function GetABet(Optional ByVal bigBet As Boolean = False) As Integer
 
        Dim theBet As Integer
 
        If bigBet Then
            theBet = bet * 1.5
        Else
            theBet = bet
        End If
 
        If theBet > stake Then theBet = stake
 
        stake = stake - theBet
 
        Return theBet
 
    End Function
 
    Sub Main()
 
        Dim i, j As Integer
        Dim s As String
 
        rand = New Random
 
        Console.WriteLine("The Perch")
 
        Console.Write("How many tables to watch? (4) ")
        tables = Val(Console.ReadLine)
        If tables = 0 Then tables = 4
        ReDim tableResults(tables)
        ReDim tableBetAmount(tables)
        ReDim tableBetColor(tables)
        ReDim tableLostLastTime(tables)
 
        Dim stakeSave As Integer
 
        Console.Write("How many money to start with? (10) ")
        stakeSave = Val(Console.ReadLine)
        If stakeSave = 0 Then stakeSave = 10
 
        Console.Write("How many money to bet? (10) ")
        bet = Val(Console.ReadLine)
        If bet = 0 Then bet = 10
 
        Console.Write("How many times to hit a color before betting? (4) ")
        matches = Val(Console.ReadLine)
        If matches = 0 Then matches = 4
 
        Console.Write("What is your goal amount? (400) ")
        goal = Val(Console.ReadLine)
        If goal = 0 Then goal = 400
 
        Console.Write("How many times to run the simulation? (1000) ")
        attempts = Val(Console.ReadLine)
        If attempts = 0 Then attempts = 1000
 
        Console.Write("Cancel your bet after a win? (Y) ")
        s = Console.ReadLine.ToUpper.Trim
        If s = "" Then s = "Y"
        cancelBetAfterAWin = (s = "Y")
 
        Dim madeGoal As Integer = 0
 
        wheelCount = theWheel.Count
 
        Dim currAttempt As Integer
        Dim ctr As Integer
        Dim theSpin As String
        Dim spinsSeen As Integer
        Dim result As String
        For currAttempt = 1 To attempts
            ' initialize the table arrays
            stake = stakeSave
            For i = 0 To tables - 1
                tableResults(i) = New List(Of String)
                tableBetAmount(i) = 0
                tableLostLastTime(i) = ""
            Next
            ' initialize the lists
            For j = 1 To matches
                s = String.Format("{0,5}", j.ToString)
                For i = 0 To tables - 1
                    theSpin = GetASpin()
                    tableResults(i).Add(theSpin)
                    s = s + String.Format("{0,5}{1,-5}", "", theSpin)
                Next
                s = s + String.Format("{0,5}", stake.ToString)
                Console.WriteLine(s)
            Next
            spinsSeen = matches
            ' loop
            While (stake > 0 And stake < goal)
                ' place your bets
                For i = 0 To tables - 1
                    If tableLostLastTime(i) <> "" Then
                        ' see if this is the 1st time losing
                        If tableBetAmount(i) = bet Then
                            ' we lost last time out, automatically bet 1.5x
                            tableBetAmount(i) = GetABet(True)
                            tableBetColor(i) = tableLostLastTime(i)
                        Else
                            ' this is the 2nd time losing in a row, so stop betting
                            tableBetAmount(i) = 0
                            tableBetColor(i) = ""
                            tableLostLastTime(i) = ""
                        End If
                    Else
                        ' check to see if the colors match up
                        ctr = 0
                        For Each r In tableResults(i)
                            If Left(r, 1) = "B" Then ctr = ctr + 1
                        Next
                        If ctr = matches Then
                            ' it's coming up black, bet on red
                            tableBetAmount(i) = GetABet()
                            tableBetColor(i) = "R"
                            tableLostLastTime(i) = ""
                        End If
                        ctr = 0
                        For Each r In tableResults(i)
                            If Left(r, 1) = "R" Then ctr = ctr + 1
                        Next
                        If ctr = matches Then
                            ' it's coming up red, bet on black
                            tableBetAmount(i) = GetABet()
                            tableBetColor(i) = "B"
                            tableLostLastTime(i) = ""
                        End If
                    End If
                Next
                ' now spin for each of the tables
                spinsSeen = spinsSeen + 1
                s = String.Format("{0,5}", spinsSeen.ToString)
                For i = 0 To tables - 1
                    ' pop off the oldest spin for each table
                    tableResults(i).RemoveAt(0)
                    ' get a new spin for each table
                    theSpin = GetASpin()
                    tableResults(i).Add(theSpin)
                    If tableBetAmount(i) = 0 Then
                        s = s + String.Format("{0,5}{1,-5}", "", theSpin)
                    Else
                        s = s + String.Format("{0,5}{1,-5}", _
                                              tableBetAmount(i).ToString + _
                                              tableBetColor(i) + ">", theSpin)
                    End If
                    ' check for bets
                    If tableBetColor(i) <> "" Then
                        If Left(tableBetColor(i), 1) = Left(theSpin, 1) Then
                            ' winner
                            stake = stake + tableBetAmount(i) * 2
                            tableLostLastTime(i) = ""
                            If cancelBetAfterAWin Then
                                tableBetAmount(i) = 0
                                tableBetColor(i) = ""
                            End If
                        Else
                            tableLostLastTime(i) = tableBetColor(i)
                        End If
                    End If
                Next
                s = s + String.Format("{0,5}", stake.ToString)
                Console.WriteLine(s)
            End While
            If stake = 0 Then
                result = "Busted"
            Else
                madeGoal = madeGoal + 1
                result = "Won $" + stake.ToString
            End If
            Console.WriteLine("Spins seen: " + spinsSeen.ToString + _
                              "; Result: " + result)
        Next
 
        Console.WriteLine()
        Console.WriteLine("Total simulations: " + attempts.ToString)
        Console.WriteLine("Number of times goal was made: " + madeGoal.ToString)
 
        Console.WriteLine()
        Console.WriteLine("Strike any key to end the program")
        Console.ReadKey()
 
    End Sub
 
End Module

I kind of stumbled into something interesting here. I thought I had coded the application with the rules as described in the posting on The Daily WTF, but the results that I was seeing seemed out of whack to me.  I was running 1,000 simulations and coming up with about 300 times successfully reaching the goal. After I put in the code that breaks down the wheel, bet, and stake status on a spin-by-spin basis, I noticed that I was not cancelling the bet after a win. After fixing it up by adding the code to return to the perch after a winning bet (see the section above with the comment winner), all of a sudden the number of times reaching the goal went from 300 per thousand to 0 to 5 per thousand.

So that you can try it for yourself, I put in an option to control this parameter. From the results, it would appear that if you want to play this way, you should let the bets ride. (But notice that if your bets are riding and you get the required number red or black spins in a row, the bet that is riding could switch colors.)