Posts filed under 'Code Examples'

3 More Useful VB.NET String Functions

3 string functions: String To Stream, Compare and Word CountA few weeks ago I wrote an article called 3 Handy VB.NET String Functions You Can Use and it’s been one of the more popular articles on this site. So, I thought I’d follow it up with another article on string functions. Hopefully, you will find this one helpful as well.

Converting a String To a Stream

There are a number of objects in .NET that require a Stream as a parameter and many of these won’t accept a string as a parameter. Many new-to-VB.NET programmers have run into this situation and been frustrated. The trick here is to place the string into a MemoryStream. This is simply a stream object that uses memory as a storage device rather than a disk.

However, you will also need to specify the type of encoding for your string. In most cases, an ordinary string will use ASCII encoding but you may also run into Unicode strings. Therefore it’s important for you to know the type of encoding you should use in your application. The encoding methods are in the System.Text namespace.

Once you know the encoding method, you will want to use the GetBytes function to convert the target string into a byte array.

OK, here’s the example function and it can be reduced down to only one line:



Dim MemStream As New IO.MemoryStream(System.Text.Encoding.ASCII.GetBytes(MyStringData))

Now that you have the string converted to the stream, perhaps you want to know how to get a string back from the MemoryStream. ToString only returns the name of the object, so what do you do? Remember we converted the string to an array of bytes for the stream so we will need to simply copy this array back to a string, like so:



MyStringData = System.Text.Encoding.ASCII.GetString(MemStream.ToArray))


Remember to use the same encoding method for both functions! Also, bear in mind when you’re using streams that you need to properly close and dispose of streams in order to release resources. MemoryStream misuse can result in your application having a memory leak so make sure you do this.

Using String.Compare

It’s common to compare strings using the classic equal (=) or not equal (<>) operators but often the case of the letters being inconsistant has caused programmers to resort to functions like this in VB6:



If UCase(txtHomeAddress.Text) = UCase(txtShippingAddress.Text) Then

However, in VB.NET, we can use the String.Compare function to handle this.



If String.Compare(txtHomeAddress.Text, txtShippingAddress.Text, True) = 0 Then

This built-in String class function takes two string arguments, either of which can be Nothing, and returns less than zero (-1) is the first string is less than the second, zero (0) if they’re equal, and greater than zero (1) if the first string is greater. Overloads allow you to ignore case, as in the example above. You can also use comparison methods outside of the default one as well using overloads.

Another powerful overload option on this function is the ability to compare parts of a string. In this example, we will see if the beginning 3 characters of our first string match the 3 ending characters of our second string:



If String.Compare(Puzzle1, 0, Puzzle2, Puzzle2.Length - 3, 3, True) = 0 Then

For those of you transitioning to VB.NET, remember, strings in VB.NET are zero based, not one based like they were in VB6.

Getting The Word Count

A common way to get the number of words in a string in VB is to use the Split command and then get the count of the resulting array. This is rather inefficient since it requires allocating an array and so forth. It is easier and faster to use a regular expression to do this, as seen in this example function:



Public Function WordCount(ByVal value As String) As Integer
    Return System.Text.RegularExpressions.Regex.Matches(value, “(((^s*)*S+s+)|(S+))”).Count()
End Function

This regular expression matches any white-space character and the function returns the number that were found. It will consider 2 white-space characters together as one. Regular expressions, while rather obtuse, are very powerful and you should consider them for string parsing or comparison functions not directly provided within the .NET Framework. I do recommend wrappering them in functions for easy correction, modification and reuse.

I hope you’ve found this article helpful. Let me know by leaving a comment with any thoughts or questions you might have.

Share This Article: These icons link to social bookmarking sites where readers can share and discover new web pages.
  • Digg
  • del.icio.us
  • Reddit
  • StumbleUpon
  • Technorati
  • DotNetKicks
  • DZone

2 comments September 7th, 2007

Introduction to the ErrorProvider Component

Use the ErrorProvider to assist your users' data entryIn my previous article, 5 Elements of Style For Error Messages, I mentioned you could use the ErrorProvider component to help the user solve a problem by providing an indicator icon and tooltip. In this article, we’ll go over how to use this component.

Why Use ErrorProvider?

It was typical in older applications for a programmer to use a message box to indicate an error condition. This had several problems. First, it interrupted the flow of the program with a modal dialog. Second, it wasn’t easy to indicate exactly which field needed to be corrected. Third, it was tricky to use for multiple entry errors.

What was needed was a better way to validate fields and provide instant feedback to the user as they worked. Some programmers coded this for themselves. Now, the ErrorProvider component does a lot, but not all, of this work for you.

The Basics

The ErrorProvider is simply an indicator for the user in the form of an icon that’s positioned next to a target control. The icon may flash, if desired, and when the user hovers over the icon a tooltip message that describes the problem should appear.

The component is usually found in the Components section of the Visual Studio toolbox. To use it, simply drag it anywhere onto the target form. Since it’s a component, it will reside in the component bar at the bottom of the form designer screen.

The error icon defaults to an exclamation point icon although you can change this if you wish. In the example below, I’ve replaced the default exclamation icon with a friendlier arrow icon. You can also set the icon to blink or not blink. My preference is to not blink.

You can use the SetIconAlignment property to position the error icon relative to the specified control. You can also set the padding value in pixels on a control-by-control basis. This is handy if you need some extra space.

To set an error for a control, you use the SetError method, passing in the control and the error message string. You can clear the error by sending in a blank string. Here’s an example of both.

erpMain.SetError(txtEntry, "This is an error!")

.....

erpMain.SetError(txtEntry, "") 'clear error

The matching GetError method allows you to get the specific error assigned to a control. You can use the Clear method to remove all of the currently set error conditions in the object. Unfortunately, this collection of controls and errors isn’t otherwise exposed for you to manipulate.

The ErrorProvider can be used with bound or unbound controls. In this example, I won’t be covering the databinding portion of this component.

The Sample Program

In this example, we’ll use a simple user login setup dialog that an administrative user might use to add a new user or edit an existing user. Our requirements for the form are:

      A user name field that must be between 8 and 25 characters
      A password field that is between 8 and 20 characters long, that contains at least one upper case letter, one lower case letters, and one numbers or special characters, that uses a password mask character, and that must be entered twice for verification.
      An Email address field that should be in a valid email address format but should not be more than 50 characters

Here is the basic design:

errorprovider example screenshot

To meet the maximum length requirements, we’ll simply set the MaxLength property of our textboxes to match. This eliminates the need to check this part of entry. Another trick I like to use is to disable the OK button until all of the entry fields contain valid data. We will see this in action later.

Now, we will need to code our form. To begin with, we will want to set the position of the error provider icon for each control that we want to validate and set the default state. We’ll do this in the Form Load event:

Private Sub frmLoginSetup_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    With erpLoginSetup
        .SetIconAlignment(txtUserName, ErrorIconAlignment.MiddleRight)
        .SetIconAlignment(txtPassword, ErrorIconAlignment.MiddleRight)
        .SetIconAlignment(txtRepeatPassword, ErrorIconAlignment.MiddleRight)
        .SetIconAlignment(txtEmail, ErrorIconAlignment.MiddleRight)
    End With
    'Set the initial state of the error provider
    txtUserName_TextChanged(txtUserName, New System.EventArgs)
    txtPassword_TextChanged(txtPassword, New System.EventArgs)
    txtPassword_TextChanged(txtRepeatPassword, New System.EventArgs)
    txtEmail_TextChanged(txtEmail, New System.EventArgs)
End Sub

Next, we will create our validation code. We will begin with the User Name textbox in its TextChanged event:

Private Sub txtUserName_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles txtUserName.TextChanged
    If txtUserName.Text.Length < 8 Then
        erpLoginSetup.SetError(txtUserName, "User Name must be at least 8 characters long")
    Else
        erpLoginSetup.SetError(txtUserName, "")
    End If
    EntriesOK()
End Sub

Now we’ll add code for the password checking. This code is more complex since we’re routing events from both password textboxes through this routine. Note that we’re using a regular expression to test for our strong password so we will want to include an Imports System.Text.RegularExpressions statement at the top of our form module.

Private Sub txtPassword_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles txtPassword.TextChanged, txtRepeatPassword.TextChanged
    Dim txtPwd As TextBox = DirectCast(sender, TextBox)
    If txtPwd.Text.Length < 8 Then
        erpLoginSetup.SetError(txtPwd, "Password must be at least 8 characters long")
    Else
        If Regex.IsMatch(txtPwd.Text, "(?=^.{8,}$)((?=.*d)|(?=.*W+))(?![.n])(?=.*[A-Z])(?=.*[a-z]).*$") Then
            If txtPassword.Text = txtRepeatPassword.Text Then
                erpLoginSetup.SetError(txtPassword, "")
                erpLoginSetup.SetError(txtRepeatPassword, "")
            Else
                If txtPwd.Name = "txtPassword" Then
                    erpLoginSetup.SetError(txtPassword, "")
                    erpLoginSetup.SetError(txtRepeatPassword, "Password fields must match.")
                Else
                    erpLoginSetup.SetError(txtPassword, "Password fields must match.")
                    erpLoginSetup.SetError(txtRepeatPassword, "")
                End If
            End If
        Else
            erpLoginSetup.SetError(txtPwd, "Password must contain at least 1 upper case and 1 lower case letter and at least one number or special character.")
        End If
    End If
    EntriesOK()
End Sub

Finally, we’ll add code for the email textbox. Once again, we’re using a regular expression to validate our email address.

Private Sub txtEmail_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles txtEmail.TextChanged
    If Regex.IsMatch(txtEmail.Text, "[a-z][a-z|0-9|]*([_][a-z|0-9]+)*([.][a-z|0-9]+([_][a-z|0-9]+)*)?@[a-z][a-z|0-9|]*.([a-z][a-z|0-9]*(.[a-z][a-z|0-9]*)?)$") Then
        erpLoginSetup.SetError(txtEmail, "")
    Else
        erpLoginSetup.SetError(txtEmail, "The provided email address is not a valid email address.")
    End If
    EntriesOK()
End Sub

Our last routine checks to see if any errors are outstanding. If there aren’t any, it enables the OK button, if there are errors, the button is disabled. This routine should be called from the Text_Changed events that set or clear the provider’s error.

Private Sub EntriesOK()
    If erpLoginSetup.GetError(txtUserName).Length = 0 AndAlso _
       erpLoginSetup.GetError(txtPassword).Length = 0 AndAlso _
       erpLoginSetup.GetError(txtRepeatPassword).Length = 0 AndAlso _
       erpLoginSetup.GetError(txtEmail).Length = 0 Then
        btnOK.Enabled = True
    Else
        btnOK.Enabled = False
    End If
End Sub

You can download the code for this project here: ErrorProviderDemo Code Example

That covers this example of using the ErrorProvider component. Let me know if you found this article and example helpful or if you have any questions about it by leaving a comment.

Share This Article: These icons link to social bookmarking sites where readers can share and discover new web pages.
  • Digg
  • del.icio.us
  • Reddit
  • StumbleUpon
  • Technorati
  • DotNetKicks
  • DZone

Add comment September 4th, 2007

Will the Real User Please Stand Up

Without wearing any mask we are conscious of, we have a special face for each friend. - Oliver Wendell HolmesIn my previous article, Impersonation Class, I had provided code that allowed you to impersonate a user for critical parts of your program. Another common use of impersonation is when an application needs to run under a different ID than the currently logged in user. This is usually done by the system administrator to allow a program to access resources that regular users are locked out of, for example, the registry or a remote network drive.

This can create a problem if your program needs to log the current user to the database or file or needs the real users name for other reasons while impersonation is active. If you use the My.User.Name property it will return the name of the current, impersonated, user, not the user who is logged into the computer. Related .NET Framework methods will do the same. Fortunately, we’re not limited to only looking at our own process to determine who the real user is.

The System.Management Namespace provides easy access to the Windows Management Instrumentation (WMI) infrastructure. This allows us to gather a lot of information about the system, including who the owner of a specified process is. In our case, we want to look for explorer.exe, the Windows shell program.

To begin with, we will need to add a reference to System.Management to our project. Next, to look for this process, we will use the ManagementObjectSearcher. This object retrieves a collection of management objects from a WMI query. These queries look very much like standard SQL queries. In our case, we’re going to return all of the running processes. Once we have this collection, we’re going to search through it for explorer.exe, extract the user name from the object, and return it.

The Code

Public Function GetActualUserName() As String
    Dim ActualUserName As String = ""
    Dim ProcessSearch As New Management.ManagementObjectSearcher("Select * from Win32_Process")
    Dim CurrentProcesses As Management.ManagementObjectCollection = ProcessSearch.Get
    For Each ProcessItem As Management.ManagementObject In CurrentProcesses
        Dim ProcessOwner(2) As String
        ProcessItem.InvokeMethod("GetOwner", ProcessOwner)
        If (ProcessItem("Name").ToString = "explorer.exe") Then
            ActualUserName = ProcessOwner(0).ToString
            Exit For
        End If
    Next
    Return ActualUserName
End Function

Limitations

Using the System.Management objects does require having fully trusted code and sufficient security on the target system. Usually this isn’t a problem because most of the time impersonated processes will be running at a higher level of security. However, you need to bear this in mind for your design.

Another limitation would be on terminal service systems or other situations where multiple users might be logged in and have a desktop session. This may require more WMI queries to narrow down the specific user you want to capture or it may not be doable in this manner and you’ll have to try something else.

I hope you’ve found this code example helpful. Let me know if you did or didn’t or if I left something important out or if you want more details on this subject area or whatever by leaving me a comment.

Share This Article: These icons link to social bookmarking sites where readers can share and discover new web pages.
  • Digg
  • del.icio.us
  • Reddit
  • StumbleUpon
  • Technorati
  • DotNetKicks
  • DZone

1 comment August 27th, 2007

How to Read a RSS Feed Into a Dataset

RSS Feed To DBRSS (Really Simple Syndication) feeds are the lifeblood of blogs and other frequently updated Internet content. At their core, they’re really just another XML file so reading one in VB.NET is quite easy when you take advantage of the built-in tools. In this example, we’ll be looking at how to download a RSS file and load it into a dataset.

First, let’s understand the structure of a RSS file. This Wikipedia article has the full layout for you to review. In our example, we will be looking primarily at the Item data in the section of the RSS file that looks like this:
.
.
.

<item>
  <title>Article Title goes here</title>
  <link>http://example.com/the-article-permalink-goes-here</link>
  <description>
      Article text goes here
  </description>
</item>

The Item element, at the very least, contains the title of the article, a link to the article, and a description that might be the full article or just an excerpt. There are other elements and attributes that can appear, such as the author’s name and a guid value that further identifies the article, but we’ll be keeping it simple for this demo.

At first glance, the task of downloading a file from the Internet and parsing it and loading it into a dataset might seem a bit daunting, particularly if you haven’t worked a lot with XML files in VB.NET. However, the reliable structure of a valid RSS file and built-in .NET Framework data functions make this task a one liner (two if you count initializing the dataset). Here it is:

Dim RssData As New DataSet
RssData.ReadXml(RssSourceLocation)

And that’s it. The ReadXml function of a dataset accepts a filename as input in one of its overloads. In this context a valid filename can also be a valid URL. For example, if we wanted to get the last 100 entries in the Google Blog Search on VB.NET, we would just send ReadXml a string like this:

"http://blogsearch.google.com/blogsearch_feeds?q=VB.NET&num=100&output=rss"

All you need is the address of the site’s feeds and you can load it into your dataset. But, how can you work with it once it’s there in the dataset?

When you load a XML document into a dataset using ReadXML without providing a schema, .NET uses inference to determine the structure to use. If it can’t figure out the structure, an exception is raised. This could be a problem for just any old XML file but the RSS structure is well known and has to be correct for it to work in a wide variety of readers. Each parent element type is placed in a datatable of the same name. For our RSS file, we’re primarily interested in the ‘item’ entries. So we would loop through the data like this:

For Each RssRow As DataRow In RssData.Tables("item").Rows
    ArticleTitle = RssRow.Item("title").ToString
    ArticleLink = RssRow.Item("link").ToString
    ArticleText = RssRow.Item("description").ToString
Next

Of course, you could get additional fields or read the header information if you wanted to at this point. You could take the values and save them to your own database for later analysis. You could generate your own aggregate feed for either a desktop app or a web page. There really are a lot of possibilities. Of course, this method could be used for bad, for example, creating a splog or scrapped site, so use it wisely and carefully.

I would like to know what you think. Please feel free to leave a comment or question if you have one.

Share This Article: These icons link to social bookmarking sites where readers can share and discover new web pages.
  • Digg
  • del.icio.us
  • Reddit
  • StumbleUpon
  • Technorati
  • DotNetKicks
  • DZone

Add comment August 3rd, 2007

3 Handy VB.NET String Functions You Can Use

3 Quick ExamplesWhile the .NET String object offers a lot of functionality, there are still some things that we can add to it. In this article, we’ll look at these 3 useful string functions:

  1. Shorten a string with an ellipsis in the middle
  2. Reverse the contents of a string
  3. Use XOR to do simple string encryption/decryption

1. Shorten a string that contains a file path with ellipsis

It is common to see file paths shortened by having an ellipsis in the middle, like so

c:\records\data\jon...\report_xyz.pdf

If you need to implement this kind of functionality it isn’t too hard to code it yourself but you can also use a built in
.NET function to do it as well as seen here:

Function ShortenPathString(ByVal pathString As String, ByVal targetWidth As Integer, _
                           ByVal targetFont As Drawing.Font) As String
    TextRenderer.MeasureText(pathString, targetFont, New Drawing.Size(targetWidth, 0), TextFormatFlags.PathEllipsis Or TextFormatFlags.ModifyString)
    Return pathString
End Function

In this example we use the MeasureText method of the TextRenderer object to build an appropriately sized string. The path, as a string, is passed in along with the width and font so that the correct sizing can be determined. The PathEllipsis tell the routine to place the ellipsis in the middle of a validly constructed path string.

The limitation of this routine and the underlying TextRenderer method is that it only works with a properly constructed path/filename and not with other strings.

Here is a method I came up with for doing this for any string.

Function ShortenStringWithEllipsis(ByVal targetString As String, ByVal targetWidth As Integer, _
                                   ByVal targetFont As Drawing.Font) As String
    Dim ReturnString As String
    Dim StringWidth As Integer = TextRenderer.MeasureText(targetString, targetFont).Width
    If StringWidth <= targetWidth OrElse targetString.Length <= 10 Then
        ReturnString = targetString
    Else
        ReturnString = String.Concat(targetString.Substring(0, (targetString.Length  2)), Chr(1), targetString.Substring((targetString.Length  2)))
        Dim StringParts() As String
        Do While TextRenderer.MeasureText(ReturnString, targetFont).Width > targetWidth
            StringParts = Split(ReturnString, Chr(1))
            StringParts(0) = StringParts(0).Substring(0, StringParts(0).Length - 1)
            StringParts(1) = StringParts(1).Substring(1)
            ReturnString = String.Concat(StringParts(0), Chr(1), StringParts(1))
        Loop
        If ReturnString.Contains(Chr(1)) Then
            ReturnString = ReturnString.Replace(Chr(1), “…”)
        End If
    End If
    Return ReturnString
End Function

In this code, we check the length of the string first and if it is OK we return the string unmodified but if it is longer we split the string in half and loop, removing 1 character from each end, until it fits. I used a ASCII character 1 to serve as a placekeeper for the ellipsis since it is unlikely to be in visible text. After the string is shortened enough the ellipsis is replaced and the short string is returned.

2. Reverse the contents of a string

This simple code example shows a quick way to reverse a string using the Array.Reverse method:

Function ReverseString(ByVal targetString As String) As String
    Dim Characters() As Char = targetString.ToCharArray
    Array.Reverse(Characters)
    Return Characters
End Function

3. Use XOR to do simple string encryption/decryption

In this example, XOR is used to do a simple encryption/decryption of a string. The string is encrypted by using the bitwise XOR operator on every character using the contents of a mask or key string. To decrypt it, the mask is applied the same way to the encrypted string.

Function XorString(ByVal targetString As String, ByVal maskValue As String) As String
    Dim Index As Integer = 0
    Dim ReturnValue As String = “”
    For Each CharValue As Char In targetString.ToCharArray
        ReturnValue = String.Concat(ReturnValue, Chr(Asc(CharValue) Xor Asc(maskValue.Substring(Index, 1))))
        Index = (Index + 1) Mod maskValue.Length
    Next
    Return ReturnValue
End Function

This encryption method is quite vulnerable to being broken so it should not be used for any non-trivial situation. It can be made more secure by using it in conjuction with a Vernam Cipher

You can download the sample code here: 3 String Functions Demo

If you have better or different ways of doing these functions or if you have any questions about them please feel free to leave me a comment.

Share This Article: These icons link to social bookmarking sites where readers can share and discover new web pages.
  • Digg
  • del.icio.us
  • Reddit
  • StumbleUpon
  • Technorati
  • DotNetKicks
  • DZone

3 comments July 19th, 2007

Next Posts Previous Posts


Most Popular Articles

Highest Rated Articles

Categories

Most Recent Articles

Feeds

 Subscribe in a reader

To subscribe by e-mail
Enter your address here

Delivered by FeedBurner

VB Opportunities

Archives