Thursday, September 2, 2021

Working with WSC (Windows scripting component)

Often times an application require a certain functionality to be extended by users .For example a workflow engine can let users customize start or end steps. The .NET framework provides perfect mechanism to implement this but it comes with a steep leaning curve.

Windows scripting component or WSC provide an easier javascript or vscript based solution for creating COM components  using command line tools. WSC are essentially XML based  that can be used to generate COM based object that can even support events.
What's more interesting is it's possible to host these in COM+ applications for remote access and integrated as a WCF service.

Below is a simple example. This hosts a single component that has a single method Add.
<?xml version="1.0"?>
<component>

<?component error="true" debug="true"?>

<registration
 description="silly calculator"
 progid="SillyCalc.WSC"
 version="1"
 classid="{502B2117-D5AC-41B2-9441-B466932F613F}"
>
</registration>

<public>
 <method name="add" >
 <PARAMETER  name="op1" />
 <PARAMETER  name="op2" />
 </method >
</public>

<script language="VBScript">
<![CDATA[


Function add(op1, op2)
add=op1 + op2
End Function 


]]>
</script>

</component>

The window scripting component wizard can also be used for creating wscs. It can be installed by running wz10en.exe.

Registration
  1. Save the above text to file sillycalc.wsc
  2. open a WOW64 command window and run following command.
regsvr32 sillycalc.wsc

Scripting host Client
The component can be consumed by a scripting host client such as cscript or script as below. Save the following to sillycalc_client.vbs and execute it in a WOW64 command window. The message box should popup as shown below. 
       
        set calc = createobject("sillycalc.wsc")
	msgbox calc.add(40,6)
       
 


C# client with WSC unregistered
The wsc can be consumed directly by a c# client without even registering as below:
   dynamic remoteobj;
   remoteobj = (dynamic)Marshal.BindToMoniker(@"script:D:\Github\TechBlog\COM+\WSC\server\SillyCalc2.wsc");
   Console.WriteLine("40+6={0}", remoteobj.add(40,6));
       
 
However this requires hardcoding the method names and its parameters which can be problematic to maintain.

C# client with WSC registered
CLR uses Runtime callable wrapper to consume unmanaged COM components. 
The process involves generating an interop dll from the type library of  the unmanaged COM dll usng tlbimp.exe and adding it as a reference to the project. Alternatively this can be done by adding tlb as a reference.
However this method does not work for wsc tlb files as Visual studio does not interpret wsc tlb files.
The when wsc is registered, it can be consumed by a c# client  by hard coding method name as below. also this needs to be executed in WOW64 command window.
       
 dynamic remoteobj;
 remoteobj=(dynamic)Activator.CreateInstance(Type.GetTypeFromProgID("SillyCalc.WSC.1"));
 Console.WriteLine("40+6={0}", remoteobj.add(40, 6));
 
 

The output should like below:

Debugging scripting component
It's possible to debug WSCs at run time using Visual Studio as below.

CSCRIPT //X  calc_client.vbs

This will  launch JIT debugger and source code is loaded into it.
stepping into the wsc method will load the source code of the wsc as below

Note:- The wsc file should explicitly allow debugging as below.

<?component error="true" debug="true"?> 

Source and Binaries can be found here.


No comments:

Post a Comment