While working with a customer, we came across a change in .NET 4.5 around usability of .NET types/classes (e.g., System.Collections.ArrayList) in VBScript. I consider it as one of the major changes in .NET 4.5 (it might have been with .NET 4.0 itself as .NET 4.5 is just an in-place upgrade to .NET 4.0, but this change has become more visible on .NET 4.5 though). To understand it better, let’s take an example of invoking a VBScript which consumes the .NET ArrayList type exposed as a COM interface:
e.g., a sample.vbs script having just a single line as shown below -
Set arList = CreateObject("System.Collections.ArrayList")
This script works fine on older Windows operating systems prior to Windows Server 2012. On a fresh or newly installed Win2K12 machine, however, the above line of script might fail with an error as highlighted below -
C:\Temp>cscript.exe Sample.vbs Microsoft (R) Windows Script Host Version 5.8 Copyright (C) Microsoft Corporation. All rights reserved. C:\Temp\Sample.vbs(1, 1) (null): 0x80131700 C:\Temp>
And when this happens, a Windows Features popup gets displayed as below:
Now let me explain the reason of this failure. When “CreateObject()” is called, it internally invokes the COM call CoCreateInstance() to create an ArrayList object. The way CoCreateInstance() works is it first tries to look into the system registry to find the assembly which implements this ArrayList type identified by its ProgID i.e. “System.Collections.ArrayList” (in this case, the ProgID and the type name are same for ArrayList). As .NET 4.5 which is the only .NET Framework inbuilt with Win2K12 has stopped exposing .NET types as COM interfaces, the registry lookup by CoCreateInstance() just fails. However, Windows seems aware of this change, and thus tries to install .NET 3.5 which does expose .NET types as COM interfaces and shows the above popup message. Once .NET 3.5 is explicitly installed on these machines, the script starts working just fine as it works on the older operating systems.
Considering the complete Framework overhaul from .NET 2.0/3.0/3.5 (i.e. CLR v2) to .NET 4.0/4.5 (CLR v4), I think, it’s completely a design decision to stop exposing these types as COM interfaces to prevent breaking the older VBScript/native apps already in the market which are being targeted to .NET 3.5 and use these kind of .NET types. Had the .NET 4.5 exposed these types as COM interfaces, and in case the .NET 3.5 also gets installed on the machine side-by-side, the same COM interfaces (something like, “System.Collections.ArrayList”) exposed by two versions of the Framework would be conflicting to each other. And the fact that multiple versions of the .NET frameworks could/should get installed side-by-side on a machine, COM registration of the .NET types would be a bad idea, hence it has been stopped.
Having said that, there are some options as followed that might be helpful in these kinds of situations -
- Install .NET 3.5 (which is the recommended & the best option ever).
- Don’t use .NET types and rather implement your own types in VBScript/native languages (in this case, ArrayList).
- Create a managed COM object wrapper around the .NET type of interest and consume it from VBScript/native languages.
- Force cscript.exe to use .NET 4.5 by creating an activation config file as below (i.e., v4.0 for the inbuilt .NET 4.0/4.5 on Win2K12):
• Create an activation config file with name “cscript.exe.activation_config” having the below content:
<configuration> <startup useLegacyV2RuntimeActivationPolicy="true"> <supportedRuntime version='v4.0' /> </startup> </configuration>
• Keep this file in a folder (e.g., C:\CustomConfigs) and set the below environment variable and then execute your script:
Having suggested the above options, in my opinion, it’s better to use .NET types going forward only in .NET based managed applications. On a side note, I’ve only tested this behavior with collection types on a fresh Win2K12, but I think it should be applicable to any new Win8/Win2K12 machines and to all the .NET types which used to be exposed as COM interfaces prior to .NET 4.0/4.5.