JScript.NET: A bit of a backwater these days. I'm told that Visual Studio 2005 was the last iteration of that IDE to have good support for it. Now one must jump through a couple of hoops to use VS2010 for JScript.NET debugging and otherwise one just has the commandline compiler, jsc. Interestingly, every iteration of the .NET framework has had a jsc compiler, so someone out there must still love it a little. In general, however, it's use is deprecated in favour of other .NET languages like IronPython, CS-Script and IronJS.
Still, I've been wanting to get something working in JScript.NET ...
A while back I wrote a tool in JScript to coordinate the Convert and Repair of Access databases. It works fine, albeit a little slowly being interpreted. It's short and, as it turned out, converted fairly easily once I began to get my head around the shift from Windows Scripting Host (WSH) to .NET.
In the original, I connected to the Scripting.FileSystemObject, using ActiveXObject(). I still do that in the JScript.NET version, simply because I haven't found out what the .NET equivalents are yet. var oFSO = new ActiveXObject("Scripting.FileSystemObject");
Next came parsing the command line. This is very easy in JScript and VBScript thanks to the WScript object's Arguments object, which even parses the command line into a dictionary, so that /name:<thing> is accessible as WScript.Arguments.Named("name") (as below):var sDatabaseName = WScript.Arguments.Named("name");
var sDataFolder = WScript.Arguments.Named("data");
var sTempFolder = WScript.Arguments.Named("temp");
var sBackupFolder = WScript.Arguments.Named("backup");
However, .NET's System.Environment.GetCommandLineArgs() is nowhere near as helpful, so I had to write something to parse the commandline that would at least come fairly close to the original in functionality. function argNamed( sname : String ) {
var result : String = "";
var aCmdline = System.Environment.GetCommandLineArgs();
var i : short = 1;
for ( ; i < aCmdline.length; i++ ) {
if (aCmdline[i].toLowerCase().slice(0, sname.length + 2) == ( "/" + sname.toLowerCase() + ":" )) {
var inner : String = aCmdline[i].slice( sname.length + 2 )
result = (inner.charAt(0) == '"' ? inner.slice(1,inner.length-1) : inner);
}
}
return result;
}
var sDatabaseName : String = argNamed("name");
var sDataFolder : String = argNamed("data");
var sTempFolder : String = argNamed("temp");
var sBackupFolder : String = argNamed("backup");
Note that I'm using type annotations in the code to give the compiler a few hints about how to handle the intent of the code.
Next, the handling the command line itself. Not a particularly good way of doing it in the original, but hey, it worked.var bWorking = true;
if ( undefined === sDatabaseName ) {
WScript.Echo( "Specify database name with /name:" );
bWorking = false;
}
if ( undefined === sDataFolder ) {
WScript.Echo( "Specify data path with /data:" );
bWorking = false;
}
if ( undefined === sTempFolder ) {
WScript.Echo( "Specify temp folder with /temp:" );
bWorking = false;
}
if ( undefined === sBackupFolder ) {
WScript.Echo( "Specify backup folder with /backup:" );
bWorking = false;
}
if ( ! bWorking ) {
WScript.Quit();
}
With WScript.Quit() unavailable, I had to find something that would work in JScript.NET. I tried return and break but the compiler complained. Finally, I stumbled over System.Environment.Exit();.if ( sDatabaseName == "" ) {
print( "Please specify database name on commandline with /name:" );
System.Environment.Exit(1);
}
if ( sDataFolder == "" ) {
print( "Please specify data path on commandline with /data:" );
System.Environment.Exit(2);
}
if ( sTempFolder == "" ) {
print( "Please specify temp folder on commandline with /temp:" );
System.Environment.Exit(3);
}
if ( sBackupFolder == "" ) {
print( "Please specify backup folder on commandline with /backup:" );
System.Environment.Exit(4);
}
(Having a more sensible help text is next on the agenda.)
Next I create the filenames that will be used later in the Access Compact and Repair process. These also appear in the JScript.NET version for the usual reasons (that is, I don't know yet how to do a BuildPath equivalent in .NET.)var sDatabaseFile = oFSO.BuildPath(sDataFolder, sDatabaseName);
var sBackupFile = oFSO.BuildPath(sBackupFolder, sDatabaseName);
var sTempFile = oFSO.BuildPath(sTempFolder, sDatabaseName);
Next, assorted deletes, moves and the setup and execution of the CompactRepair Access.Application's CompactRepair() method.try {
oFSO.DeleteFile( sTempFile );
} catch ( e ) {
//~ WScript.Echo( e.message + ': ' + sTempFile );
}
WScript.Echo("CompactRepair",sDatabaseFile,"to",sTempFile);
var oACC = new ActiveXObject('Access.Application');
oACC.CompactRepair( sDatabaseFile, sTempFile, true );
oACC.Quit();
try {
oFSO.DeleteFile( sBackupFile );
} catch( e ) {
//~ WScript.Echo( e.message + ': ' + sBackupFile );
}
WScript.Echo("Moving",sDatabaseFile,"to",sBackupFile);
oFSO.MoveFile( sDatabaseFile, sBackupFile );
// copy temp to source, overwriting
try {
oFSO.DeleteFile( sDatabaseFile );
} catch( e ) {
//~ WScript.Echo( e.message + ': ' + sDatabaseFile );
}
WScript.Echo("Moving",sTempFile,"to",sDatabaseFile);
oFSO.MoveFile( sTempFile, sDatabaseFile );
WScript.Quit();
The JScript.NET version is almost exactly the same:try {
oFSO.DeleteFile( sTempFile );
} catch ( e ) {
//~ print( e.message + ': ' + sTempFile );
}
print("CompactRepair ",sDatabaseFile," to ",sTempFile);
var oACC = new ActiveXObject("Access.Application");
oACC.CompactRepair( sDatabaseFile, sTempFile, true );
oACC.Quit();
// copy source to backup, overwriting
try {
oFSO.DeleteFile( sBackupFile );
} catch( e ) {
//~ print( e.message + ': ' + sBackupFile );
}
print("Moving ",sDatabaseFile," to ",sBackupFile);
oFSO.MoveFile( sDatabaseFile, sBackupFile );
// copy temp to source, overwriting
try {
oFSO.DeleteFile( sDatabaseFile );
} catch( e ) {
//~ print( e.message + ': ' + sDatabaseFile );
}
print("Moving ",sTempFile," to ",sDatabaseFile);
oFSO.MoveFile( sTempFile, sDatabaseFile );
System.Environment.Exit(4);
Notice the change from WScript.Quit() to System.Environment.Exit(). Notice also the change from WScript.Echo() to print(). One weird thing about the latter is that the arguments in a WScript.Echo() are output separated by a space, but are not separated at all in a print(), thus the extra spaces in the quoted strings.
Sample invocation:acarNET.exe /name:database.mdb /data:c:\acartest\data /temp:c:\temp /backup:c:\acartest\backup
Compiled, the JScript.NET version runs very quickly in comparison to the original JScript version. It almost makes me wish JScript.NET had a future. As it stands, I'm going to have to redo this in something else. Sigh.
© Copyright Bruce M. Axtens, 2012