Category Archives: Languages

VBScript in VB.Net

1
Filed under .NET, ActiveX, Languages, VB Feng Shui

A long (long) time ago, if you wanted your users to be able to enhance your product by add coding logic, you pretty much had two choices:

  • Dig into Lex and Yacc or….
  • Roll your own parser and scripting execution engine.

Then, around the time VB 6 was released, Microsoft introduced VBA. It worked, but it was expensive and a god awful complicated mess to integrate with your app, so outside of Microsoft Office (which even as of Office 2010, still supports it!), very few applications actually made use of it.

Around the same time, the Microsoft Scripting Control was released. This was an ActiveX control you could use from any COM compatible language to embed VBScript. Now, of course, this is VBScript, not a “real” language like C or even VB. But, it was free, easy to obtain, and very easy to use.

As the years have rolled by, .NET has steadily grown in capability and while the Windows Scripting Host exe is still shipped with Windows, the old VBScript and JScript scripting has largely been supplanted by either:

  • ASP and more recently ASP.NET
  • Powershell
  • Dynamically compiled .NET code
  • and likely lots more options I’m not familiar with

Now, all these options are good, and each definitely has it’s place, but, for many purposes, good ol’ VBscript still fits the bit quite nicely.

But can you use it from .NET? And if so, how?

The Tempest in the Teapot

Before I continue, I should point out that any time you start talking about allowing users to add their own code into your application, you’re opening up a huge can of worms that you’ll need to deal with. Things like properly catching exceptions from badly written user code (yeah, that never happens), adding watchdog timers to deal with hung and infinitely looping user code, security concerns, and the like all will have to factor into the decision. You have been warned <g>.

So Simple It Hurts

I had a plugin project recently where I wanted to give the user the ability to write some very simple logic to expand the functionality of the application.

Of course, I wanted to build a full plugin API, but I also wanted to provide a lighter-weight option for those users that didn’t want to dive head-first into a full on .NET project. VBScript seemed like the obvious choice.

A few Google searches later and most everything I found was talking about how to dynamically compile .NET code, which is cool indeed, but not what I was really after. Other articles and posts insisted that users should convert their VBScript code to .NET (ok, yeah, but that’s not really the point now is it?).

Then I did a Google Desktop search of my own system and turned up some VB6 code I’d written ages ago to experiment with the Microsoft Scripting Control.

Now, I know that .NET languages support accessing ActiveX Controls and COM objects in general, but this was pretty old stuff. Would it actually still work?

I cobbled up a dirt simple VB.net project:

Public Sub Main()
    Dim Script = New MSScriptControl.ScriptControl
    Script.Language = "VBScript"
    Script.AddCode("sub Main" & vbCrLf & "MsgBox ""This is a Test"" " & vbCrLf & "End Sub")
    Script.Run("Main")
End Sub

Be sure to add a reference in the VB.net project to the COM object “Microsoft Scripting Control”.

Run it, and lo and behold, I get the “This is a Test” message box, straight from VBScript!

Obviously, there’s lots more to making use of the Scripting Control than just this, but, clearly, VBScript is still very much a choice for adding limited programmable logic to your application.

Internationalizing Applications

0
Filed under Languages, VB Feng Shui

image A recently posted article on CodeProject had this to say about Visual Studio’s support for multi-lingual applications:

Conclusion: Visual Studio .NET does not offer any multilanguage support which is worth thinking about it.
You will only waste your time with Microsoft’s approach!

Check the whole article/project out here.

I can’t verify the author’s credentials that would justify such a claim, but from the sound of it, he did at least start down the MS sanctioned path, and I have to agree with him.

Way back in the dark ages, pre-internet, around 1990 or so, I was managing development of a CRM system (customer relationship management software).

We’d picked up some resellers oversees and needed to get the product internationalized. This was really at the very beginning of Windows even (Win 3.1 and WFW, if you remember those!). Our internationalization efforts had to apply equally well to our DOS app and our Windows version.

Several of the developers and myself went to a conference, the precursor to VBits, (I don’t remember exactly what it was called back then) and I got a chance to talk with one of the MS internationalization engineers directly.

I’d played with the whole “separate resources for each language” technique and found it workable, but so labor intensive, that I couldn’t imagine anyone but the largest shops actually doing it that way.

The MS guy verified that suspicion. He said (and I’m paraphrasing), “The core team finishes up the project, and ships it, and then the whole project base is ‘thrown over the wall’ and each internationalization team then takes over and internationalized the project into their respective languages, re-tests, etc.”

Ouch.

Now, I’m sure times have changed at MS, but if the comment from Elmue in the article on CodeProject is any indication, they haven’t changed that much.

The internationalization functions I helped build way back then was based on 3 simple concepts:

  1. The original english strings had to remain in the code
  2. Those strings has to actually be used by the code
  3. Those strings had to be easily searchable (say, by a GREP or similar utility) for extraction and translation

Why those first two points?

Because if the english strings remain in the code, the code remained relatively easy to debug and maintain for the programmers.

Further, if the strings are actually used by the code, that meant that during dev and alpha/beta testing, we wouldn’t have any disconnect issues with resources not matching what was needed in the code itself. This is akin to the age old concept of eating your own dog food. The idea of socking strings away in resources and just having a comment in the code as to what the string contained just scared the hell out of me.

Also, it also meant that if the translatable resources are lost for whatever reason, the program would still be able to run based on the “compiled in” English strings. Not ideal, but better than simply throwing errors or displaying blanks.

We accomplished all these goals by embedding all translatable strings (including those in dialogs, etc), into a function call. Something like:

MyString$ = TX$(“This is the english version”, stringcode, groupcode)

Where stringcode and groupcode were optional arguments that indicated, basically, the resource ID of the string and an arbitrary group ID of the string.

Originally, when you were writing or working on code, you’d never even bother entering the stringcode or groupcode args, so your call would look like:

MyString$ = TX$(“This is the english version”)

But, because it was trivially easy to scan for TX$(), when our scanner was run on the code, it could

  1. Extract the strings
  2. Give then ID’s
  3. Rewrite the source code with the appropriate string and group codes as necessary.
  4. Generate a “translator’s file” that contained the string, ID’s and potentially developer comments that would indicate the context of the string and intention (for use by translators to assist with the translation).

Nowadays, with OO, extension methods, reflection, and all the other .NET goodies, seems like this whole process could be vastly more efficient than even what we did back then.

But in the end, we translated the product into 8 or more languages in just a few months with this technique, using no additional developers, and a few native speaker volunteer translators. And it didn’t require any code rewrites and was just as efficient to debug as if you’d left the strings in the code and did nothing about translation at all.

Now, granted, there’s a lot more to internationalizing an app that translating text. You have to worry about icons, input method (when applicable), date, time, and number formats, and even subtle things like color choices, but it was a huge timesaver for an otherwise arduous task.

Closing comment: Why TX$() you might ask<g>? Basically, it was because we didn’t want a huge function name taking up tons of space in the code when it would be used as often as it was. That’s all. As I recall, it is about the only two letter function I’ve ever authored in code. I was never a big fan of the BASICA 2 letter name restriction!

Any translation war stories out there? How have you translated applications?

Fixing System.String

0
Filed under .NET, Languages, Rants, VB Feng Shui

String manipulation is a very different beast in VB.NET than in VB6. In fact, I’d wager that it’s the one area that trips up programmers new to VB.NET more than any other aspect of the language.

I’ve talked about some annoying aspects of System.String before, but this go round, I’m going to concentrate on shared methods.

Shared Methods are methods that are invoked via the class type itself, and not via an instance of the class.

For instance, with strings, you have a nicely named IsNullOrEmpty  function that you’d expect would return a true/false indicating whether the string in question is null or empty. Unfortunately, you’d be only half right.

Bring up the Object browser and find the String class, then highlight the IsNullOrEmpty method and you’ll see this:

image

Notice the Shared keyword. That indicates that this method IS NOT an instance method, thus you can’t invoke it via a specific instance of a string; rather, you must invoke it via the String class directly.

So, you can’t do this:

Dim s as string
If s.IsNullOrEmpty Then

But you can do this:

Dim s as string
If String.IsNullOrEmpty(s) Then

Now, it makes perfect sense, from a purely technical perspective, that invoking an instance method on an uninitialized object wouldn’t work anyway, so a method like IsNullOrEmpty wouldn’t make sense to be an instance method, since attempting to invoke it via a variable that hadn’t actually already been initialized would result in an “Object not Set” error.

However, this is VB, not some ivory tower exercise in theoretical language design. If I’m going to invoke a method like IsNullOrEmpty, I’m expect to be able to do so against an instance. Having to invoke it via the String class is just so utterly unintuitive, it defies all reason.

Oddly, the very argument that I note above in favor of using a shared method for IsNullOrEmpty is violated by another string property, Length. Here’s a property that is definitely an instance property, but causes VB code to fail (with the Object Not Set error) when invoked on a variable that hasn’t actually been set to value yet.

Is this just an arbitrary oversight, a design flaw, or an intentional “feature” of the language? I can’t answer that.

But, realistically speaking, I can say that it’s utterly frustrating to have elements of a language, such as these, behave so drastically different from one version to another. It doesn’t matter that the syntax is different (x.Length vs Len(x), for instance), there is an expectation there that simply is no longer met and does nothing but confuse.

Fortunately, with VB 2008, there is a relatively trivial way to correct these problems, and likely a host of other similar issues.

It’s called “extension methods”.

To create an IsNullOrEmpty that works like any reasonable person would expect it too, just put this in a Utility module somewhere in your project:

Imports System.Runtime.CompilerServices

Module StringExtensions

    ''' <summary>
    ''' Returns True if the current string instance is nothing or a null string
    ''' </summary>
    ''' <param name="aString"></param>
    ''' <returns></returns>
    <extension ()> _
    Public Function IsNullOrEmpty(ByVal aString As String) As Boolean
        Return String.IsNullOrEmpty(aString)
    End Function
End Module

The Imports System.Runtime.CompilerServices is only used during compilation. You can actually continue to target the .NET runtime v2.0, even if you use this code (however, you still have to compile the code from VS2008, it won’t work in VS2005).

You tag the new version of IsNullOrEmpty with the <extension()> attribute to  mark it as an extension method.

The first parameter of an extension method is required and is an argument of the type of class that you’re extending, in this case the String class.

You can have additional arguments if necessary, but you don’t need any for this method.

This trick takes advantage of the fact that even though the String class already has a method named IsNullOrEmpty, the function signature is not the same as this one (since ours has the implicit first argument). This is effectively an overload and it allows VB to know to call the new method if invoked against an instance, and the old one if invoked against the String class directly (which is exactly what’s being done within the method itself!).

There are several other “shared” methods on the string class that can similarly be extended to more intuitive instance methods in this way, for instance:

  • Compare
  • Concat
  • Format
  • Join

Length could also be added to this list but you can’t quite treat it the same, since it’s a property, and the Extension attribute can’t be applied to properties.

Finally, extension methods can be unbelievably useful for associating functionality with specific classes that you can’t extend in any other way, but, as always, you need to be careful with how much you extend a  class.

For example, it might be tempting to extend the String class with all sorts of path/file/folder manipulation and parsing logic, so that you could do something like this:

dim s as string = "c:\myFolder"
debug.print s.DriveLetter

but doing so could quickly clutter the String object and Intellisense.

As usual with these sorts of techniques, use judiciously.

Methinks it’s a new Programming Language

0
Filed under Languages, Misc

This project has been out a LONG time (looks like it was last messed with in 2001), but I hadn’t seen it before and the specs are definitely worth a read.

Essentially, as a project, these guys built a pretty simplistic programming language that ends up looking very similar to a Shakespearian play.

Like I said, you gotta read the specs to fully appreciate it.

Variables are declared in the Dramatis Personæ section. They enter scope not by virtue of functions but by Enter, Exit and Exeunt declarations.

Here’s a small sample:

Outputting Input Reversedly.

Othello, a stacky man.
Lady Macbeth, who pushes him around till he pops.


                    Act I: The one and only.

                    Scene I: In the beginning, there was nothing.

[Enter Othello and Lady Macbeth]

Othello:
 You are nothing!

                    Scene II: Pushing to the very end.

Lady Macbeth:
 Open your mind! Remember yourself.

Othello:
 You are as hard as the sum of yourself and a stone wall. Am I as
 horrid as a flirt-gill?

Lady Macbeth:
 If not, let us return to scene II. Recall your imminent death!

Othello:
 You are as small as the difference between yourself and a hair

Anyway, pretty clever, funny stuff, that is, as long as you’d find this pretty clever and funny (and if you haven’t been to http://xkcd.com, it’s worth the trip).