// Sometimes, it's necessary to run a program via JavaScript instead of directly via an MSI CA. // For example, it might be easier to locate the program or construct the command line in JavaScript than by // trying to craft some set of SetProperty CA's to do the same thing. Or, for example, InstallShield LE just // won't let you. This script demonstrates how to run a program and is designed to be run as a Deferred mode CA. var ClassName_ScriptingRuntimeShell = "WScript.Shell"; var argumentString = ""; var installDir = ""; var programToRunPathname = ""; var commandLineToRun = ""; // CustomActionData format: [INSTALLDIR]<?> // If running in MSI, use arguments via standard CustomActionData interface, otherwise assume running outside MSI in debugger if (DetectRunningInMSI()) argumentString = Session.Property("CustomActionData"); else argumentString = "c:\\program files\\MyProgramDir\\"; arguments = argumentString.split("<?>"); if (arguments.length == 1) { installDir = arguments[0]; } else { LogMessage("Argument string invalid (" +arguments.length+ "): " +argumentString); throw 3; } installDir = EnsureEndsInBackslash(installDir); programToRunPathname= installDir +"ProgramToRun.exe"; commandLineToRun = "\""+ programToRunPathname+"\" somecommand"; if (RunCommand(commandLineToRun) != 0) { // Critical error, fail install throw 3; } function RunCommand( commandLine ) // Runs the specified command line and returns the process exit code or failure code { var returnVal = -1; var shellUtil = null; // Validate parameters if (commandLine == "") return -1; shellUtil = SafeGetActiveXObject(ClassName_ScriptingRuntimeShell); if (shellUtil != null) { try { LogMessage("RunCommand: Running "+commandLine); returnVal = shellUtil.Run(commandLine, 0, true); if (returnVal != 0) LogMessage("RunCommand: Error " +returnVal+ " returned by command line "+commandLine); } catch (runException) { // 0x80070002 if (runException.number == -2147024894) LogMessage("RunCommand: File not found error running command " +commandLine+ ": " +runException.message); else LogMessage("RunCommand: Error " +runException.number+ " running command " +commandLine+ ": " +runException.message); returnVal = runException.number; } shellUtil = null; } return returnVal; } function LogMessage( messageString ) // Writes a line to the MSI log, or the console if running outside MSI. { var customActionName = "RunProgram"; if (DetectRunningInMSI()) { var msiMessageTypeInfo = 0x04000000 var logRecord = null; var currTime = new Date(); logRecord = Installer.CreateRecord(1); logRecord.StringData(0) = currTime.toTimeString() +" "+ customActionName +": [1]"; logRecord.StringData(1) = messageString; Session.Message(msiMessageTypeInfo, logRecord); logRecord = null; } else { var currTime = new Date(); messageString = currTime.toTimeString() +" "+ customActionName +": "+ messageString; WScript.Echo(messageString); } } function DetectRunningInMSI() // Returns TRUE if running in MSI, else FALSE { var returnVal = true; var stringVal = ""; try { // Try to reference the Session object, which is only provided by the MSI runtime engine stringVal = Session.Property("ProductCode"); } catch (thisException) { // An exception is only thrown if the runtime couldn't resolve Session, which means // this script is not running under MSI returnVal = false; } return returnVal; } function SafeGetActiveXObject( className ) // Creates an instance of className and returns it, or null if an error occurs, and logs the error { var returnVal = null; try { returnVal = new ActiveXObject(className); } catch (createException) { LogMessage("SafeGetActiveXObject: Error " +createException.number+ " creating object of class " +className+ ": " +createException.message); } return returnVal; } function EnsureEndsInBackslash( directoryPath ) // Returns directoryPath ending in a backslash if it does not already end in one. { var returnVal = directoryPath; if (returnVal.substring(returnVal.length, returnVal.length-1) != "\\") returnVal = returnVal + "\\"; return returnVal; } |