I'm new to JScript scripting, and I've encountered a problem when calling Windows Management Instrumentation (WMI) methods that use output parameters to return values. When I call these methods in JScript, the output values aren't set. Is there any way to call these methods in JScript?
I ran into this problem when I started writing JScript code, and this question is frequently asked in newsgroups. To understand the problem, it helps to have some background information about JScript's design. So first, I'll explain how and why the problem occurs. Then, I'll show you how to solve the problem.
Explaining the Problem
Data in JScript variables fall into two categories: primitive types and reference types. Numbers and booleans (true/false values) are primitive types because their data values are stored directly in the variable. All other data are reference types; that is, the variable contains a reference to the data, but not the data itself. (Strings are an exception because they're stored like reference types but behave like primitive types.)
The script in Listing 1 uses a primitive type. The script declares a global variable that contains a number (a primitive type) and passes it as a parameter to a function. The function changes the value of the parameter and exits, but the change isn't visible outside of the function. JScript copies the value for use in the function. The changed value is available inside the function, but when the function exits, the changed value is lost.
In contrast, the script in Listing 2 uses a reference type. This script creates an object and adds a property to the object. The script then calls the function, using the object as a parameter. The function modifies the object's property and exits. The new value for the property is visible outside of the function because the script passes a copy of the variable (which contains a reference to the object) to the function. The code inside the function uses the copy of the reference to update the object's property.
You might already be familiar with other languages that support passing parameters by reference, but JScript doesn't support this technique, even with reference types. For example, the script in Listing 3 creates an object and a property. The script then passes the object's variable (which contains a reference to the object) as a parameter to the function. The function creates a new object and property, then assigns the function's parameter to the new object reference. However, the function's parameter is only a copy of the reference, not the original object reference, so the global object isn't changed to refer to the new object created inside the function.
In other words, JScript always passes parameters to methods (and functions, which are really methods in JScript) by value, even when you're using reference types. When you pass a reference type as a parameter to a function or a method, JScript passes a copy of the reference, not the reference itself. If the function reassigns the parameter's value, the new value won't be available outside of the function. This is the problem with WMI methods that use output parameters: A new value is assigned inside the method, but this value is lost when the method finishes executing.
Solving the Problem
The script in Listing 4 shows the problem you asked about. The script connects to WMI on the local machine and attempts to call the StdRegProv object's GetExpandedStringValue method. JScript can tell whether the method executed successfully, but because the GetExpandedStringValue method uses an output parameter to return its data, JScript can't access it.
Fortunately, WMI provides another way to call these problematic methods. This alternative uses an object to return the method's results and thus works perfectly with JScript. The general outline is as follows:
- Obtain a reference to the WMI object that contains the method you want to execute.
- Create an InParameters object for the method.
- Set the InParameters object's properties to correspond to the method's input parameters.
- Use the InParameters object to call ExecMethod_ and return an Out-Parameters object.
- Access the OutParameters object's properties to retrieve the method's results.
Listing 5, GetSystemPath.js, shows how to use these steps to successfully call the GetExpandedStringValue in JScript. The code at callout A in Listing 5 demonstrates the first step: The script connects to WMI and obtains a reference to the StdRegProv object on the local computer.
The first line of code at callout B shows how the script retrieves an instance of the GetExpandedStringValue method of the StdRegProv object. The Methods_ property of a WMI object returns an SWbemMethodSet object, which is a collection of SWbemMethod objects. (Note that the trailing underscore in the Methods_ property name is required.) The Item method of the SWbemMethod-Set object returns an SWbemMethod object (in this case, the GetExpandedStringValue method). The second line of code in callout B accesses the SWbemMethod object's InParameters property. The InParameters property returns an SWbemObject that defines the input parameters for a method. The SpawnInstance_ method (the trailing underscore is required) creates an InParameters object that the script can populate with the method's parameters.
Each property of the InParameters object corresponds to the method's parameters. The code at callout C shows how the script sets the InParameters object's properties for the method call: The property name is the input parameter's name, and the property's value is the value to use for the parameter. Next, Callout D shows how the script calls the WMI object's ExecMethod_ method (the trailing underscore is required) to execute the method. The ExecMethod_ method's first parameter is the name of the method to execute (this script uses the SWbemMethod object's Name property to get the method's name), and the second parameter is the InParameters object created in the code at callout B. The ExecMethod_ method returns an OutParameters object.
The code at callout E shows how the script uses the OutParameters object to determine whether the method call was successful. The ReturnValue property is common to all OutParameters objects, and contains the method's return value (usually zero if the method executed successfully). The OutParameters object's other properties depend on the method. Because this script executed the GetExpandedStringValue method, the OutParameters object has an sValue property that corresponds to the GetExpandedStringValue method's sValue parameter.