User input in JScript with data exchange between scripts

... or: how to exchange data between two scripts?

JScript doesn't provides a way for user input. I have shown a trick in the previous sample, which uses VBScript within a HTML document loaded in the Internet Explorer. But why shall we use this solution. Isn't it much more simple to call a VBScript program, which provides the InputBox function for us, from a JScript program? In this case we need no Internet Explorer and all the tricks to create the InputBox function I have shown in the previous example.

Oh yes, we can call a second script from a running script. We need only to execute the Run method from the parent script to launch a child script. But there is a small problem: How can we exchange data between the scripts? There is no "legal" way to pass more than a simple number between the scripts. If a script terminates using the Quit method, it can return a process exit code between 0 and 255. One solution can be to use a Registry key to exchange data between processes. But during writing the WSH book I came to a much more simple solution.

Passing data from the parent script to the child script is rather simple. The parent script can submit parameters as arguments within the Run method. This may be done in the following way:

WSHShell.Run ("WScript.exe C:\\Test\Child.vbs Hello Input Text Test", 1, true);

Here we execute the Script Child.vbs. The command contains the arguments Hello, Input, Text and Test. The value 1 defines the window style and the parameter true indicates that the parent script shall wait till the child script terminates.

Within the child script we can access the submitted parameters in a simple way using the Arguments collection:

Set objArgs = WScript.Arguments ' create Arguments object
If objArgs.Count >= 4 Then ' yes there are arguments
 Title = objArgs(0) ' fetch 1st argument
 Message = objArgs(1) ' fetch 2nd argument
 default = objArgs(2) ' fetch 3rd argument
 EnvName = objArgs(3) ' fetch 4th argument
End if

The first line creates an object variable with a reference to the Arguments property. This property returns a collection containing the submitted arguments. Then we can use the Count property of the collection object to determine whether we have enough arguments for the child script.

OK, the first problem is solved. We know now a technique to pass values from the parent to the child. But how can we return the values from the child to the parent script? My first idea was to create an environment variable within the process, write the value into this variable and use the other process to read this environment variable. Unfortunately there is one problem: If Windows creates a new process, the environment is filled with a copy of the master environment. If the process terminates, the environment address room is released. So there is no chance within a script to access the environment area of another process or script...

... realy no chance at all? Not at a regular base, but I have found an exeption. If a WSH script (the parent) uses the Run method to launch a second WSH script (the child), both scripts are executed in the same process address space. Whilst I was not successful to create an environment variable within the parent and access it from the child, the other direction works well. You can create an environment variable within a child script. If the child script terminates, the environment remains intact, and you can read the variable from the parent process. Hurry, that's all we need. Now we are ready to create a simple VBScript program which overtakes the parameters submitted from a second script. This parameters contain the data which must be shown in an user input dialog. After closing the user input box, the result is stored within an environment variable, and the name of this variable is submitted as a parameter. The calling script can read the environment variable. So it is easy to get a user input from JScript.

The following VBScript program implements the child process. The script scans the arguments submitted from the caller. Then an InputBox dialog is invoked. The data shown in this Input box dialog (title, other text, default value) are submitted as script arguments. If the arguments are missing, the child uses its default values. After retrieving the user input an environment variable is created and the result is stored within this variable. Then the VBScript program terminates. Details may be found within the listing.

'************************************************
' File:    Input.vbs (WSH sample in VBScript)
' Author:  (c) G. Born  
'
' This script creates an input dialog box. The result
' entered from the user is stored into an Environment
' variable. The values shown in the Input box must be
' submitted from the calling script. This modul may be 
' used to implement an InputBox dialog for JScript.
'
' In no way shall the author be liable for any
' losses or damages resulting from the use of this
' program. Use AS-IS at your own risk.
'
' The code is the property of the author. You may
' use the code and modify it, as far as this header
' remains intact. Further updates and other samples
' may be found on my site:
' http://www.borncity.de
'
' The basis of this script was developed during my WSH book project 
' "Inside Windows Script Host" I wrote for MS Press Germany.
'************************************************
Option Explicit

Dim Message, result, WshEnv, WSHShell, objArgs, EnvName
Dim Title, Text1, Text2, i, default

' initialize all internal variables for the input dialog
Message = "Input"           
Title = "WSH sample user input  - by G. Born"
Text1 = "User input canceled"
Text2 = "Your input was:" + vbCRLF
default = ""
EnvName = "WshEnv"              ' environment variable name 

' If there are arguments submitted from the caller, 
' overwrite the predefined variables with the arguments
' arg(0) = Title
' arg(1) = Message
' arg(2) = default value
' arg(3) = name environment variable
Set objArgs = WScript.Arguments    ' create Arguments object
If objArgs.Count >= 4 Then         ' yes there are arguments
 Title = objArgs(0)                ' fetch 1st argument
 Message = objArgs(1)              ' fetch 2nd argument
 default = objArgs(2)              ' fetch 3rd argument
 EnvName = objArgs(3)              ' fetch 4th argument
End if

' We are ready to use the InputBox function
' InputBox (prompt, title, default, xpos, ypos)
' prompt:    text shown in the dialog box
' title:     input box title text
' default:   value shown in the input field
' xpos/xpos: upper left corner of the input dialog
' If a value is omitted, VBScript set it to default

result = InputBox(Message, Title, default, 100, 100)

' now set the environment variable to the input value
Set WshShell = Wscript.CreateObject("WScript.Shell")
Set WshEnv = WshShell.Environment ("Volatile")
WshEnv (EnvName) = result
'*** End

Are you ready to get the second part of the solution? It is a JScript program which uses the service of our previous VBScript program to invoke an InputBox dialog. This program is rather simple: It passes the requested parameters and the script files name to the Run method. The path to the child script is derived from the path of the current script using the following lines:

var path = WScript.ScriptFullName;
path = path.substr(0,path.lastIndexOf("\\")+1);
path = path + "\Input.vbs"; // the path + name to the child

The variable path contains the executeable script files name. But me must pass also the parameters for our InputBox dialog as arguments. To avoid many trouble within the child script, we must assure that each argument can be determined exactly within the child. A blank is used in normal case as a separator for arguments. So we must set each argument which contain a blank into quotes. Have a look at the following statements:

var title = " \"Born's InputBox function for JScript\" ";
var prompt = " \"Please enter your name:\" ";

The characters \" defines in JScript the quote. Therefore the strings defined above contains quotes. If the child examines the submitted arguments, the whole string included in quotes is passed as one argument (and not each word of the string).

Then the program waits till the child script terminates. The result obtained from the user will be read back from the environment variable.

var wshEnv = WSHShell.Environment("Volatile");
var test = wshEnv(EnvName);

Then the result is shown, that's all. The details (even for parameter passing, getting the path to the script and so on) may be obtained from the listing shown below.

//************************************************
// File:    Input.js  (WSH sample in JScript) 
// Author:  (c) G. Born 
//
// This script demonstrates how to get a user input in
// JScript. I use a rather tricky solution. Because JScript
// doesn't support the InputBox function, I call a 2nd VBscript
// program which handle this task. The problem: there is no
// (official) way to return the user input to the caller.
// But I found a trick: If a child script writes the result
// into an environment variable, the parent script may read
// this value. THIS IS THE ONLY CASE WHERE scripts can exchange
// data using the environment. In all other cases the environment
// is separated in a different address space.
//
// In no way shall the author be liable for any
// losses or damages resulting from the use of this
// program. Use AS-IS at your own risk.
//
// The code is the property of the author. You may
// use the code and modify it, as far as this header
// remains intact. Further updates and other samples
// may be found on my site:
// http://www.borncity.de
//
// The basis of this script was developed during my WSH book project 
// "Inside Windows Script Host" I wrote for MS Press Germany.
//************************************************
// set a few variables

var title = " \"Born's InputBox function for JScript\" ";
var prompt = " \"Please enter your name:\" ";
var WSHShell;
var vbOKCancel = 1;       // helpers 
var vbOKOnly = 0
var vbInformation = 64;
var vbCancel = 2;

var EnvName = "WshEnv";    // The name of the environment variable

// Create the Shell object, required for the Popup method.
WSHShell = WScript.CreateObject("WScript.Shell");

// Get a reference to the Environment collection
var wshEnv = WSHShell.Environment("Volatile");

// retrieve the script's path (needed to call the child script)
var path = WScript.ScriptFullName;
path = path.substr(0,path.lastIndexOf("\\")+1);
path = path + "\Input.vbs";    // the path + name to the child

// execute child script, submit some parameters
WSHShell.Run ("WScript.exe " 
               + path + title + prompt + " \"Hello World\" " + 
                 EnvName,1, true);

// Get the user input from the Environment
var test = wshEnv(EnvName);
if (test != "")
 {
   WScript.Echo ("Your input was: ", test);
 }
 else
 {
   WScript.Echo ("InputBox canceled"); 
 }
                
//*** End

... the simple solution in WSH 2

Using WSH 2 .wsf files allows you combining several script languages within one file. In this case the JScript InputBox function can be implemented as a simple VBScript function located in an own <script> element. This solution is shown below.

<?xml version="1.0" encoding="ISO-8859-1" ?>
<job id="IncludeExample">
<script language="VBScript">
<![CDATA[
 Function WSHInputBox (Message, Title, Value)
 ' Provides an InputBox-Funktion for JScript
 ' may be called from JScript as:
 ' var result = WSHInputBox("Enter a name","Input",test);
   WSHInputBox = InputBox(Message,Title,Value)
 End Function
]]>
</script>

<script language="JScript">
<![CDATA[
// This is the JScript script, which reads a user input
// and displays the input within a dialog box window.
// We use a VBScript function WSHInputBox to create
// the input box. 
var vbOKOnly = 0;                // constants for Popup
var vbInformation = 64;

var title = "InputBox function for JScript";
var prompt = "Enter a name:";

// Create the Shell object (needed to use Popup).
var WSHShell = WScript.CreateObject("WScript.Shell");

// open Input dialog, using a function within the .wsf file
var result = WSHInputBox (prompt,title,"New York");

if (result != null)   // Test, whether Cancel clicked or not
 {  // No, get input
   var intDoIt =  WSHShell.Popup("You entered: " + result,
                                  0,
                                  "Result",
                                  vbOKOnly + vbInformation );
 }
 else
 { // Cancel button was clicked
    var intDoIt =  WSHShell.Popup("Sorry, no input",
                                  0,
                                  "Result",
                                  vbOKOnly + vbInformation );
 }                           
// End
]]>
</script>
</job>

WSHInputBox is a simple VBScript procedure that wraps the internal VBScript InputBox function. The result obtained from the user will be returned to the calling procedure.

Additional information about WSH samples may be found in my WSH books, published by Microsoft Press.

Back

(c) Günter Born