Archive for the ‘Visual Basic’ Category.

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

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

Sentinel.v3.5Client error in ClickOnce app install

We have had bad experiences in the past deploying desktop applications based on the .Net Framework version 3.5, largely due to the huge payload required on the end user’s system to run our relatively simple application.

When SP1 of Visual Studio 2008 was announced to have an option to trim down the bits to be downloaded, we were naturally excited to put it into place on our newest product. In a VB.NET application, this option is called “Client-only Framework subset”, it is on the Advanced Compiler Settings window shown by clicking Advance Compile Options… on the Compile tab of My Project, and in a C#.NET application, the Client-only Framework subset check box is right under Target Framework on the Application tab shown by right clicking on the project file and selecting Properties.

Excited until, of course, we tried for the very first time to run the ClickOnce installer for our product on a clean Windows XP SP3 virtual machine and received the following error:

Unable to install or run the application. The application requires that
assembly Sentinel.v3.5Client Version 3.5.0.0 be installed in the Global
Assembly Cache (GAC) first.

I did some quick investigating and found that, for the most part, the suggested solution was to turn off the client only subset option. Bugger!

This did not sit well with me, so I did a little more digging. I did not think that there were any kind of items added to the code that would require namespaces not included in the client only framework, so I went through all of the property pages for the project.

On the Publish tab, I clicked on Preqrequisites, and noticed that my application was including prerequisites for Windows Installer 3.1, .NET Framework 3.5, and SQL Server Compact 3.5. On a lark, I turned off the prerequisite for .NET Framework 3.5 and turned on the prerequisite for .NET Framework 3.5 SP1, built the ClickOnce installer, and voila! It is now working like a champ.

Friends don’t let friends reinvent System.Security.Cryptography

A fellow coworker is upgrading one of our long time customer’s ASP.NET web site that was originally created in 2003, and all is going swimmingly. Alas, this project could not go gently into that good night.

He makes the web page and code changes, modifies the database, pushes all the changes up to the web site, and the site is working well. Customers are placing orders on the web site, order e-mails are being sent to the site owners with encrypted credit card information, and all are happy.

But there is always a fly in the ointment. All of a sudden, an order is placed on the web site, but when the site owner tries to run a decrypt on the credit card information in the e-mail, the decryption routine is reporting a failure. So naturally, we assume that we broke the code somehow, so we started to dive into the project to see what we did to destabilize it.

He asked for my opinions on this problem, so I came over and we started to go through the VB.NET Framework v2.0 project. While investigating the area of the code containing the exact message that the customer was getting, my blood pressure started to go up right away as we started to see code that looked like this:

If intNumberLength = 16 Then
    'go through each of the 16 numbers and
    'add the code for them into the return string
    intNumber(0) = CType(Mid(strNumber, 1, 1), Integer)
    intNumber(1) = CType(Mid(strNumber, 2, 1), Integer)
    intNumber(2) = CType(Mid(strNumber, 3, 1), Integer)
    intNumber(3) = CType(Mid(strNumber, 4, 1), Integer)
    intNumber(4) = CType(Mid(strNumber, 5, 1), Integer)
    intNumber(5) = CType(Mid(strNumber, 6, 1), Integer)
    intNumber(6) = CType(Mid(strNumber, 7, 1), Integer)
    intNumber(7) = CType(Mid(strNumber, 8, 1), Integer)
    intNumber(8) = CType(Mid(strNumber, 9, 1), Integer)
    intNumber(9) = CType(Mid(strNumber, 10, 1), Integer)
    intNumber(10) = CType(Mid(strNumber, 11, 1), Integer)
    intNumber(11) = CType(Mid(strNumber, 12, 1), Integer)
    intNumber(12) = CType(Mid(strNumber, 13, 1), Integer)
    intNumber(13) = CType(Mid(strNumber, 14, 1), Integer)
    intNumber(14) = CType(Mid(strNumber, 15, 1), Integer)
    intNumber(15) = CType(Mid(strNumber, 16, 1), Integer)
 
    strCharCodes(0) = encrypt_Char1(intNumber(0), intIndexCode)
    strCharCodes(1) = encrypt_Char2(intNumber(1), intIndexCode)
    strCharCodes(2) = encrypt_Char3(intNumber(2), intIndexCode)
    strCharCodes(3) = encrypt_Char4(intNumber(3), intIndexCode)
    strCharCodes(4) = encrypt_Char5(intNumber(4), intIndexCode)
    strCharCodes(5) = encrypt_Char6(intNumber(5), intIndexCode)
    strCharCodes(6) = encrypt_Char7(intNumber(6), intIndexCode)
    strCharCodes(7) = encrypt_Char8(intNumber(7), intIndexCode)
    strCharCodes(8) = encrypt_Char9(intNumber(8), intIndexCode)
    strCharCodes(9) = encrypt_Char10(intNumber(9), intIndexCode)
    strCharCodes(10) = encrypt_Char11(intNumber(10), intIndexCode)
    strCharCodes(11) = encrypt_Char12(intNumber(11), intIndexCode)
    strCharCodes(12) = encrypt_Char13(intNumber(12), intIndexCode)
    strCharCodes(13) = encrypt_Char14(intNumber(13), intIndexCode)
    strCharCodes(14) = encrypt_Char15(intNumber(14), intIndexCode)
    strCharCodes(15) = encrypt_Char16(intNumber(15), intIndexCode)
 
    'strReturnValue = strCharCodes.ToString
ElseIf intNumberLength = 15 Then
    ' you get the idea

And this…

'first char
Select Case Left(strEncodeCard, 1)
    Case "X"    ' these character constants were originally all different
        strCardNumber(0) = "0"
    Case "X"    ' I have masked them out for this blog posting
        strCardNumber(0) = "1"
    Case "X"
        strCardNumber(0) = "2"
    Case "X"
        strCardNumber(0) = "3"
    Case "X"
        strCardNumber(0) = "4"
    Case "X"
        strCardNumber(0) = "5"
    Case "X"
        strCardNumber(0) = "6"
    Case "X"
        strCardNumber(0) = "7"
    Case "X"
        strCardNumber(0) = "8"
    Case "X"
        strCardNumber(0) = "9"
    Case Else
        blnSuccess = False
End Select

(The above code was repeated 32 times, once for each digit of a potential 16 digit credit card number, and there were two sets of these that were switched if the digit position was odd or even. There was definitely some thought put into this. I’m not saying it was good thought, just thought. Perhaps they were paid by the lines of code written?)

OK, I have done things like this from time to time, usually not to this extent, but the original designers and coders of this project at least had the good sense to encrypt the credit card information that was being e-mailed, so maybe it will get better.

Yeah, I was wrong about that, I should remember a tenet of code maintenance that I learned a long time ago: TWGW. (This stands for Things Will Get Worse.) As we stepped through the order that was confusing the system, we came upon this nugget.

'second, select the expiration year code
Select Case intExpYear
    Case 2003
        cryptoExp_Year = "X"    ' these character constants were originally all different
    Case 2004
        cryptoExp_Year = "X"    ' I have masked them out for this blog posting
    Case 2005
        cryptoExp_Year = "X"
    Case 2006
        cryptoExp_Year = "X"
    Case 2007
        cryptoExp_Year = "X"
    Case 2008
        cryptoExp_Year = "X"
    Case 2009
        cryptoExp_Year = "X"
    Case 2010
        cryptoExp_Year = "X"
    Case 2011
        cryptoExp_Year = "X"
    Case 2012
        cryptoExp_Year = "X"
End Select

Of course, the customer had a credit card that expired in 2013, and as such, no character was begin inserted into the encrypted string for the expiration year, and that was causing the problem.

I don’t even know where to begin, except to say that eventually this code was going to break, and that was the day. (System.Security.Cryptography was in .NET Framework v1.1, so they can’t use that as an excuse.) So the moral of the story is, if you are going to reinvent a Microsoft namespace, at least make it work more than six years.

System.MissingMethodException error in System.Data.SqlServerCe

After getting the new development machine up and running for the most part, I started once again to work on the web and client projects that we are going balls to the wall to get finished.

And of course, a roadblock was hit. On the Windows Mobile client, I got through most of the requisite re-referencing and compile errors that inevitably pop up when doing something like this. This client uses the Microsoft Synchronization Services to sync it’s local SQL Server Compact Edition database to our central SQL Server database.

When trying to create a new ServerSyncProviderProxy, the following error is being thrown:

System.MissingMethodException: File or assembly name 'System.Data.SqlServerCe,
Version=3.5.1.0, Culture=neutral, PublicKeyToken=3BE235DF1C8D2AD3', or one of
its dependencies, was not found.

After much headbanging, trial and error on both the 5.0 and 6.0 emulator and on an actual device, Google and Server Overflow searching, and staring at the code, we finally figured out what the problem was. As it turns out, I must have installed the SQL Server Compact Edition Service Pack 1 on my previous machine, and those references were saved and somehow survived in the project. On my new machine, there was a version of SQL Server Compact Edition that was installed by some component (Visual Studio 2008, Windows Mobile SDK, etc.), so to me everything looked OK. However, after installing the SQL Server Compact Edition SP1 on the computer, the error magically went away on the emulator.

As an aside, I tried to put the code on the handheld that it had not worked on previously, and it still did not work. After inspecting the error output, which was different, I found that I needed to redeploy the new SQL Server Compact Edition SP1 Windows Mobile sqlce.ppc.wce5.armv4i.CAB file on the device, unpack it (which overwrote the previous SQL Server CE files on the device), and then all was well.

NetCFSvcUtil and Windows 7

So I have, for the most part, got the new development machine all set up and running pretty well. But ah, there is always a fly in the ointment…

I have a Windows Mobile client application that talks to a WCF service to move data back and forth. I have been using a batch file that I created that ran the NetCFSvcUtil.exe program included in the Power Toys for .NET Compact Framework 3.5. This tool reads information from the provided URL of the web service and creates C# or VB.NET source files that can be included in your project.

And of course, this utility program does not work on my shiny new Windows 7 RC machine, it gives the following error:

Attempting to download metadata from 'http://www.site.net/Service.svc'
using WS-Metadata Exchange or DISCO.
Error: An error occurred in the tool.
Error: Error in the application.

Some searching for this problem yielded the following posts:

NetCFSvcUtil.exe and Windows 7

Ambiguous error message from NetCFSvcUtil.exe

These links appear to indicate that the NetCFSvcUtil does not work on Windows 7 and there is no workaround just yet. And now I have a nice shiny new VirtualBox Windows XP image that contains installs of the .NET Compact Framework 3.5 with the Power Toys, and a copy of my old batch files, along with a shared folder that I can grab the files when I need them. Thanks Microsoft!

However, it appears that Microsoft does not have the market cornered on “D’oh!” backwards compatibility moments. It appears that some users have had some issues with the load times of Firefox 3.5, and believe it or not, removing the cookies and temporary internet files associated with IE can actually help. I will give you a couple of links to look at while you ponder this interesting nugget.

The Firefox 3.5 fiasco

Firefox 3.5 slow to start troubleshooting & info

I guess you could say that Mozilla is a big believer in the More Randomer theory.

VB.NET ListBox does not scroll all the way to the bottom when setting SelectedIndex

I have a standard Windows list box that I am using in my Visual Basic .NET application. I am adding records into this list box by binding it to a data source that reads records from a local database and uses a display member in the class to chew on the record and spit out the text. Then, I logically want to see if there are records in this newly minted list box, and if so, set the selection to the last record in the list, which should scroll to the bottom of the list in the event that there are more records to display than lines in the list box. The code:

lstRecords.DataSource = DataLayer.GetRecords(theID)
If lstRecords.Items.Count > 0 Then
    lstRecords.SelectedIndex = lstRecords.Items.Count - 1
End If

Unfortunately, this code does not work 100% as expected. If there are more records than rows available in the list box, the final row does get selected, as the blue selection bar lands on that row. Once you scroll the list down one row to see it. For some reason, the scrolling down of the list box comes up one row short when done this way, no matter how many rows beyond the limit of the list box are added.

I tried everything I could think of, mostly manipulating the properties of the list box to see if some combination worked. I called the Update and Refresh methods, set the TopIndex and IntegralHeight properties, and lots of other things that did not have any effect.

I finally decided to try to set the SelectedIndex property in a timer event. The timer is initially disabled with an interval of 5 ms, and instead of setting the SelectedIndex property as shown in the line above, it enables the timer. And here is the code that executes when the timer fires:

tmrScrollToEnd.Enabled = False
lstRecords.SelectedIndex = lstRecords.Items.Count - 1

And of course, for some reason that escapes me, this now works. Perhaps it is because the setting of the SelectedIndex is moved outside of the Form Load code, which is where the code above was being executed. If anyone has any ideas, I would love to hear them, but I am glad that it is now working.

Yet another software development blog

One thing that the internet doesn’t really need is a zillion and one software development blogs, one zillion software development blogs is just the right number.

However, I stumbled upon this Visual Basic .NET nugget at work one day and just couldn’t resist…

Private Function getCustomers() As Array
 
    'do something here
 
End Function

This blog is in honor of my discovery. Please stay tuned for lots more nuggets o’ gold, random thoughts, and sometimes maybe even problems I have run across and how they were solved.