Posts filed under 'Code Examples'
In this article we’ll be creating a class to generate CAPTCHA graphics that you can use on web sites to help authenticate users as being human and not an automated process.
What Is CAPTCHA
CAPTCHA is an abbreviation for Completely Automated Public Turing test to tell Computers and Humans Apart. This method uses images of words or numbers that are, in theory, distorted and jumbled enough so that an optical character recognition program can’t read them but a human should be able to do so easily.
I’m not a big fan of this method myself since I think it interferes with the user experience. However, there is plenty of demand for them to be placed into systems that interact with the public on the Internet.
The CAPTCHA Class
You can download the CAPTCHA class source code here.
This class is a simple one that builds a 5 character numeric string and places it on a grid background with random ‘noise’. Our properties include the height, width, and font along with the randomly generated value between 10000 and 99999 and the matching bitmap. The new method is available as a parameterless version for subclassing and one that allows you to pass in the height, width, and font.
The core routine is the GenerateNewCaptcha shown here:
Public Sub GenerateNewCaptcha()
If _captchaFont Is Nothing OrElse _captchaHeight = 0 OrElse _captchaWidth = 0 Then
_captchaCode = RandomValue.Next(10000, 100000).ToString
_captchaImage = New Bitmap(_captchaWidth, _captchaHeight)
Using CaptchaGraphics As Graphics = Graphics.FromImage(CaptchaImage)
Using BackgroundBrush As New Drawing2D.HatchBrush(Drawing2D.HatchStyle.SmallGrid, Color.DimGray, Color.WhiteSmoke)
CaptchaGraphics.FillRectangle(BackgroundBrush, 0, 0, _captchaWidth, _captchaHeight)
Dim CharacterSpacing As Integer = (_captchaWidth \ 5) - 1
Dim HorizontalPosition As Integer
Dim MaxVerticalPosition As Integer
For Each CharValue As Char In _captchaCode.ToCharArray
MaxVerticalPosition = _captchaHeight - Convert.ToInt32(CaptchaGraphics.MeasureString(CharValue, _captchaFont).Height)
CaptchaGraphics.DrawString(CharValue, _captchaFont, Brushes.DimGray, HorizontalPosition, RandomValue.Next(0, MaxVerticalPosition))
HorizontalPosition += CharacterSpacing + RandomValue.Next(-1, 1)
For Counter As Integer = 0 To 24
CaptchaGraphics.FillEllipse(Brushes.DimGray, RandomValue.Next(1, _captchaWidth), RandomValue.Next(1, _captchaHeight), RandomValue.Next(1, 4), RandomValue.Next(1, 4))
For Counter As Integer = 0 To 24
CaptchaGraphics.FillEllipse(Brushes.WhiteSmoke, RandomValue.Next(1, _captchaWidth), RandomValue.Next(1, _captchaHeight), RandomValue.Next(1, 4), RandomValue.Next(1, 4))
Let’s look at some of the details of this routine.
First, notice that we’re generating random numbers in several places, most notably to generate the main code value. We also use random numbers to place the numbers and the noise bits.
The HatchBrush object is used to draw the grid background. This style could be changed to a different pattern. There are several variations you could try to get a unique effect. You could even randomize the background.
The characters from the randomly generated number are drawn onto the graphic one character at a time and are randomly placed along the vertical axis and slightly off kilter on the horizontal one.
The FillEllipse method of the Graphics object is used to create the noise at 50 different random points on the graphic. These little marks help obscure the actual characters from OCR’s and sometimes from humans as well.
Using the Class
Using the class is simple. You just create the class, display the graphic from it and verify user input against the value stored in the class. You can also regenerate the value if the user requests it. Remember that you will need to save the generated bitmap to disk in order to display it to a web user in an ASP.NET application.
More You Can Add
There are several things you could add to this class to enhance it. You could:
- Add the ability to accept strings
- Add the ability to dynamically size the strings and the resulting bitmap
- Add more distortion by using Graphics method to twist the output
- Add more background noise options
That’s all for this example. Let me know if you have any questions or observations by this example by leaving me a comment.
November 6th, 2007
As a follow-up to my previous article, How To Create Application Plug-ins In VB.NET, Karl Stoney asked for a more complete example. Hopefully this update will help.
Tips and Tricks
One trick you can use to make your development of these plugins easier is to have multiple projects in your solution. In the case of the demo app I added the main demo project, the interface project, and the two plugin projects to the solution. If I wanted to have another plugin, I would just add it to this solution. This makes debugging easier and saves system memory somewhat vs. running separate instances of Visual Studio
Another trick is to change the compile output folder to a common folder. This puts all of the executable in the same folder, once again for easy debugging. Remember that your plugins when deployed must be in the same folder as the calling application.
In this code example, we have a PluginDemo application that can call various plugins that conform to the IMyPlugIn interface. We also have a PlugIn1 and a PlugIn2 projects that implement the interface in different ways. PlugIn1 uses a standard message box while PlugIn2 uses a custom form.
The core code itself isn’t any different from the code presented in the previous article. The LoadPlugIn routine is the key to using Reflection to load the plugin. To get a better understanding of how it all comes together I recommend stepping through the process as it runs.
The zip file contains the project code but I excluded the executables. After unzipping the project you will need to first build the PlugInInterface project by itself. This will create the DLL that the other 3 projects need to reference. Once you’ve done this, do a Build Solution and it should be ready to run.
Here’s the demo zip file: VB.NET Application Plugin Demo
Let me know if you have any questions about this demo or application plug-ins in VB.NET.
November 5th, 2007
I’m sure you’ve seen blog badges around like this around the Internet. Perhaps you’ve also wondered how to create one in VB.NET. Here’s a simple class that you can use to create 80×15 pixel badges. You could even add this class to your own ASP.NET web site and, with a little fleshing out, make your own badge generator.
What we will be doing is creating a new 80×15 System.Drawing.Bitmap object. We will then create a Graphics object for the bitmap and drawing our rectangles and text on it. Then we’ll save the bitmap image out in PNG (Portable Network Graphics) format.
Here’s our code.
Public Class BlogButton
Public Shared Sub GenerateBlogButton(ByVal buttonSaveLocation As String, ByVal leftText As String, ByVal leftTextColor As Color, _
ByVal leftBackgroundColor As Color, ByVal rightText As String, ByVal rightTextColor As Color, _
ByVal rightBackgroundColor As Color, ByVal borderColor As Color, ByVal backgroundColor As Color)
Dim ButtonPicture As New Bitmap(80, 15)
Using ButtonGraphics As Graphics = Graphics.FromImage(ButtonPicture)
Dim ButtonFont As New Font("Verdana", 6, FontStyle.Regular)
Dim TextBrush As New SolidBrush(leftTextColor)
ButtonGraphics.DrawRectangle(New Pen(borderColor, 1), New Rectangle(0, 0, 79, 14))
ButtonGraphics.FillRectangle(New SolidBrush(leftBackgroundColor), New RectangleF(2, 2, 31, 11))
ButtonGraphics.FillRectangle(New SolidBrush(rightBackgroundColor), New RectangleF(34, 2, 44, 11))
ButtonGraphics.DrawString(Mid(leftText.ToUpper, 1, 4), ButtonFont, TextBrush, 3, 3)
ButtonGraphics.DrawString(Mid(rightText.ToUpper, 1, 8), ButtonFont, TextBrush, 34, 3)
A few of things to note about the code.
First of all, why am I using the Mid function? Isn’t it suppose to be ‘evil’? I’m using it here because it can be used to limit the length of text in a very simple and readable manner. SubString(0,4) would throw an exception if the length was shorter than that. To avoid the exception and be “.NET Pure” I would have to have more length checking code in the routine. I decided not to do that and instead make use of a handy VB function that does this for me.
Another thing to note is that I’m using hardcoded values in several places. Since I’m working with a fixed size I didn’t go to the trouble of using constants or variables for these values. However, if I were to expand this implementation I would want to replace any hardcodes.
I’m not using any overloads on this function although it probably could benefit from some if it was production code. For example, you might want to have overloads for the size of the graphic and the font object or you might want to have an overload with fewer parameters for a default version.
Lastly, I made it shared so that it could be called without having to worry about the state of an object. You could create a version that did not use shared if you wanted.
More You Can Do
In addition to making the size flexible you could also add dynamic sizing between the right and left columns by using MeasureString. Using it to calculate the size of the passed in strings you could determine where to draw the rectangles. Another thing you could do is make the font changeable.
You could also take this code and develop your own CAPTCHA or hit counter components. The basics would be the same. You could also take this same code and put it into a desktop app for graphic generation there although you might want to create a version that passes back a bitmap rather than writing it to disk.
Let me know if you have any questions or observations about this code sample by leaving me a comment.
October 16th, 2007
A common requirement that you may encounter is to have a way to validate a string to determine if it’s in the proper format for a path. While there are .NET functions that you can use that will tell you if a given path exists on the disk there is no built-in .NET function that will tell you if a path string has a valid format. This was the subject of a recent discussion on VBForums. In this article, we’ll look at the function I built and some other related ideas that were suggested.
For this example, we want to create a function that will tell us if the path entered by a user is a valid path string or not. We aren’t concerned about it already existing on the disk or if we have the rights to create the folder. We only want to make sure that the path string has a valid format.
What Won’t Work
We can’t use methods that check the disk for existence of the folder because we don’t need it to actually exist yet. This means we can’t use the Directory.Exists functions from the IO Namespace or the My.Computer.FileSystem Namespace. Some other IO.Path functions, such as IsPathRooted (which was my first suggestion) and GetDirectoryName weren’t well suited for validating path names.
We could use a folder browser or the textbox file system autocomplete feature. However, this wouldn’t fulfill our validation requirement.
Two other methods were thought of by forumites were to create the directory temporarily and capture exceptions. The folder would be deleted if it wasn’t used. The problem here are the performance killing exceptions and the risk of leaving junk on a user’s drive. The second was to use System.IO.Path.GetFullPath. This method worked OK in some cases but had its own formatting quirks plus it required exception trapping to deal with incorrectly formatted paths.
Solving the Problem With Regular Expressions
The way I ended up suggesting to deal with the problem was to use regular expressions. Here is the function:
Private Function IsValidPath(ByVal pathString As String) As Boolean
Const PathPattern As String = "^(([a-zA-Z]:|\\)\\)?(((\.)|(\.\.)|([^\\/:\*\?""\|<>\. ](([^\\/:\*\?""\|<>\. ])|([^\\/:\*\?""\|<>]*[^\\/:\*\?""\|<>\. ]))?))\\)*[^\\/:\*\?""\|<>\. ](([^\\/:\*\?""\|<>\. ])|([^\\/:\*\?""\|<>]*[^\\/:\*\?""\|<>\. ]))?$"
Dim Results As Boolean
If System.Text.RegularExpressions.Regex.IsMatch(pathString , PathPattern) Then
If IO.Path.GetPathRoot(pathString).Length >= 248 Then
Results = False
'additional checks could go here if desired
Results = True
Results = False
Catch ex As Exception
Results = False
In this function you’ll notice that I first define a string constant with the regular expression string. I’ve ran several tests with it and it seems to work right but if you throw something at it that it can’t handle correctly, please let me know. Next, we look for a match between the pattern and the passed in string.
After passing the first test there is a second one. We need to determine if the path is too long. Windows paths can’t be longer that 247 characters. If this value is exceeded, a False value is return. Notice that there is room to add additional checks if you need them. For example, you could add a check for a local hard drive vs. a network or removable drive.
To call this function, you would just need to call it from the TextChanged event of the target textbox.
That’s my solution. I want to thank VBForum members stimbo, techgnome TokersBall_CDXX, penguin5000, VBDT, and JuggaloBrotha who participated in this discussion and rjbudz who got the whole thing started. If you have an idea or question on this function, please leave a comment here or in the VBForum thread linked at the top of the article.
October 12th, 2007
Sooner or later you’ll find that you want to make your application extensible. Perhaps you want to add customer specific processing modules to your backend processes. Maybe you’ll want to offer customers the ability to add their own functionality to your base application. VB.NET and the .NET Framework make this relatively easy to do. Let’s walk through the steps.
Define an Interface
The way to load a .NET assembly dynamically is through reflection. To make this process easier and more controllable within the context of an application I’ve found it best to define a plug-in interface, such as this one:
Public Interface IMyPlugIn
Function TestFunction(ByVal value As String) As String
Property MySetting() As String
By using the interface this allows us to have a fixed definition for our plug-ins that our main application to work with. This means that we will need less main app code to support our plug-in.
Create A Class
Now we’re ready to create a plug-in class. Here’s the template that gets created:
Public Class CustomerXYZPlugin
Public Property MySetting() As String Implements MyPlugIn.IMyPlugIn.MySetting
Set(ByVal value As String)
Public Function TestFunction(ByVal value As String) As String Implements MyPlugIn.IMyPlugIn.TestFunction
Now, to complete the plug-in class we will need to add appropriate code it. You can’t define constructors in an interface so you’ll find it best to specify that you’ll either use a parameterless constructor or require that plug-in classes support a specific set of parameters. My preference has been to use parameterless ones and to supply ample properties for the plug-ins.
As for other code, as long as you define the interface you can do just about anything else you want.
Loading The Plug-In
Now we get to the heart of the matter, how to load the plug-in. There are several approaches you can take to this but here’s mine. First, let’s look at the code:
Private Function LoadPlugIn(ByVal LoadPath As String) As MyPlugIn.IMyPlugIn
Dim NewPlugIn As MyPlugIn.IMyPlugIn
Dim PlugInAssembly As Reflection.Assembly = Reflection.Assembly.LoadFrom(LoadPath)
Dim Types() As Type
Dim FoundInterface As Type
Types = PlugInAssembly.GetTypes
For Each PlugInType As Type In Types
FoundInterface = PlugInType.GetInterface("MyPlugIn.IMyPlugIn")
If FoundInterface IsNot Nothing Then
NewPlugIn = DirectCast(PlugInAssembly.CreateInstance(PlugInType.FullName), MyPlugIn.IMyPlugIn)
Catch ex As Exception
'handle exceptions here
As you can see, we’re passing in the path to our plug-in and returning a plug-in interface object from the call. After declaring our return value we enter a try block. I recommend putting this loader logic in an exception handling block since you may be dealing with code that’s outside your direct control.
Next, we create a new Reflection.Assembly object from the file location that was passed into our function and extract the types from it. This allows a plug-in to have functionality beyond just the interface. We search for our interface and, when we find it, create a new instance and exit our search loop. Then we pass back the newly created plug-in object back to our main code.
Here’s a simple example of what the main code might look like:
Private Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim NewPlugIn As MyPlugIn.IMyPlugIn = LoadPlugIn(TextBox1.Text)
NewPlugIn.MySetting = "Hello World"
Dim OurTestPlugInValue As String = NewPlugIn.TestFunction("Try It!")
Those are the steps to adding a simple plug-in to your application. Of course, there are more things you can do with Reflection and I suggest that you investigate them if you’re thinking about implementing this in one of your apps. Remember that there is a performance penalty for using Reflection and there are security considerations as well so make sure you factor them into your design.
If you have any questions or observations about using Reflection to create plug-ins, let me know by leaving a comment.
October 9th, 2007