JScript – Using InputBox & MsgBox

Over the years, I have seen many different techniques for emulating the InputBox and MsgBox functions in JScript, but none of them were quite as elegant as the one I saw here. Once I dug into the code and realized that ScriptControl was making it so that JScript could run VBScript commands, I felt a whole new world of possibilities had been found. Therefore, my first test was to make a better functioning InputBox and MsgBox function available to JScript by using the following code:

(function(vbe) {
  vbe.Language = "VBScript";
  vbe.AllowUI = true;

  var constants = "OK,Cancel,Abort,Retry,Ignore,Yes,No,OKOnly,OKCancel,AbortRetryIgnore,YesNoCancel,YesNo,RetryCancel,Critical,Question,Exclamation,Information,DefaultButton1,DefaultButton2,DefaultButton3".split(",");
  for(var i = 0; constants[i]; i++) {
    this["vb" + constants[i]] = vbe.eval("vb" + constants[i]);
  }

  InputBox = function(prompt, title, msg, xpos, ypos) {
    return vbe.eval('InputBox(' + [
        toVBStringParam(prompt),
        toVBStringParam(title),
        toVBStringParam(msg),
        xpos != null ? xpos : "Empty",
        ypos != null ? ypos : "Empty"
      ].join(",") + ')');
  };

  MsgBox = function(prompt, buttons, title) {
    return vbe.eval('MsgBox(' + [
        toVBStringParam(prompt),
        buttons != null ? buttons : "Empty",
        toVBStringParam(title)
      ].join(",") + ')');
  };

  function toVBStringParam(str) {
    return str != null ? 'Unescape("' + escape(str + "") + '")' : "Empty";
  }
})(new ActiveXObject("ScriptControl"));

What makes this code better is the fact that it will accept any string (even those with special characters). It is also better because it allows for null parameters to be passed to the VBScript functions. Finally, this script makes all of the MsgBox constants such as vbRetryCancel and vbInformation available. The following are example calls made to the defined functions:

var name = InputBox('I am "Script-101".\nWhat is your name?', "Name");
var greetings = name
  ? 'Nice to meet you "' + name + '".'
  : "That's fine, you don't have to tell me who you are.";
MsgBox(greetings, name ? vbInformation : vbCritical, "Greetings");

You can download the JScript file that contains these two code blocks and then try to run it on your Windows PC.  If you are running a 32bit system, this script will work as expected. On the other hand, if you are running a 64bit version of Windows, this script will error out with the message “Automation server can’t create object”.  The reason for this is that “ScriptControl”, which is being used to allow JScript to call VBScript functions, isn’t available in the 64bit version of cscript or WScript.  Therefore, to run this script, you will have to do so using the 32bit version.  You can do this by doing the following:

  1. Go to the start menu
  2. If you are not using Windows Seven, click “Run”
  3. type %windir%\SysWoW64\cmd.exe
  4. Click OK
  5. Now type cscript /path/to/the/script.vbs (change the path to whatever the path to the script is)

JavaScript Snippet – Array.prototype.toVBArray()

I was writing two HTAs (HTML Applications) today and for the first one, I needed to create a VBArray with the number five in it. Fortunately, I remembered that I wrote a page about this prior to my blog. Therefore, here is the snippet which I plan on including in the next version of jPaq:

// Returns the array as a VBArray.
Array.prototype.toVBArray = function() {
  var dict = new ActiveXObject("Scripting.Dictionary");
  for(var i = 0, len = this.length; i < len; i++)
    dict.add(i, this[i]);
  return dict.Items();
};

Here is an example of how to use it:

var avbArray = ([1,4,5]).toVBArray();

Of course, this code is only useful in Internet Explorer (HTML or HTA) or in a standalone JScript file. For all of you who have to deal with VBArrays in JavaScript, have fun!!! 8)

VBScript – RegExp Replace Using A Callback Function

One of the nice things about JavaScript is its functional nature. This is especially nice when it comes to dealing with strings and regular expressions. For instance, in JavaScript, you can use the following code to capitalize every other letter in a string:

var str = "where in the world is carmen sandiego?";
var strWeird = str.replace(/(.)(.)/g, function(a,b,c) {
  return b.toUpperCase() + c;
});
alert(strWeird); // WhErE In tHe wOrLd iS CaRmEn sAnDiEgO?

Cool stuff, right? Wouldn’t it be nice to be able to use a similar approach in VBScript? Believe it or not, you can? Here is the definition for a function which will allow you to do something similar:

Function RegExpReplace(re, str, replacement)
	' If replacement is a string, use the native RegExp.Replace function.
	If TypeName(replacement) = "String" Then
		RegExpReplace = re.Replace(str, replacement)
	' Since replacement is not a string, call replacement with every match
	' object and replace the match with the return value.
	Else
		Dim mc, m, ret, offset
		offset = 0
		Set mc = re.Execute(str)
		For Each m In mc
			ret = replacement(m)
			str = Left(str, m.FirstIndex - offset) & ret _
				& Mid(str, m.FirstIndex + m.Length - offset + 1)
			offset = offset + m.Length - Len(ret)
		Next
		RegExpReplace = str
	End If
End Function

The above function takes three parameters: the regular expression, the string that may be changed and the replacement function (or string). Now the question is, how do we pass the function (or at least a reference to it)? We can do this by taking the name of the function and using the GetRef function to get a reference to it. The following is the equivalent of what was done in JavaScript at the onset of this post:

Function fnUp1(objMatch)
  fnUp1 = UCase(m.Submatches(0)) & m.Submatches(1)
End Function

Dim re: Set re = New RegExp
re.Pattern = "(.)(.)"
re.Global = True

Dim str: str = "where in the world is carmen sandiego?";
Dim strWeird: strWeird = RegExpReplace(re, str, GetRef("fnUp1"))
MsgBox strWeird ' WhErE In tHe wOrLd iS CaRmEn sAnDiEgO?

Okay, of course the code is not as short in JavaScript, because of the way that regular expressions must be created and the fact that anonymous functions don’t exist in the language, but this is just a simple example. You may need to use this function in many different places in your code.

The other thing that I briefly mentioned is that the third parameter may be a string instead of a reference to a function. This is basically a shortcut for the RegExp.Replace function which natively exists.

Now you see that it is possible to script in a functional way with VBScript. Still, as is evidenced by the examples, JavaScript (and JScript) can usually accomplish the same thing with less code. 😀