Some days ago I had to work on an .NET application that has been ported from C++. This application is using VBScript as scripting host using the IActiveScriptParse interface. While the C++ compile was working fine on x64 the .NET port didn’t work.
To understand why it is not working I had a look at the target platform settings in the .NET project. By default Visual Studio is using Any CPU. The .NET runtime then will have a look at the PE header to identify if the assembly has been compiled with Any CPU, x86 or x64.
The IActiveScriptParse interface on x86 is mapped to IActiveScriptParse32 with the ClassID BB1A2AE2-A4F9-11cf-8F20-00805F2CD064. The easiest way to get it working on x64 was to mark the assembly as x86. You can do this with the target platform property in your Visual Studio project or by using the corflags.exe:
corflags.exe ConsoleApplication1.exe /32BIT+
Well, the effect is that the the application is running in 32-bit mode on x64 what I don’t want to. There must be a better solution to do the trick and keep the Any CPU target platform.
Let’s have a more detailed look in the C++ source code. The interface IID_IActiveScriptParse is mapping to IID_IActiveScriptParse32. When reading the source code file ActivScp.h I found that there is a x64 version, too. When I had a look at the OLE-COM Viewer I didn’t find it there. Ok, I will take the new ClassID C7EF7658-E1EE-480E-97EA-D52CB4D76D17 from ActiveScp.h and use it on x64 platforms. To device if you’re running on x64 or x86 you can check the size of IntPtr:
if (IntPtr.Size == 4)
IActiveScriptParse32 x = (IActiveScriptParse32)Activator.CreateInstance(t);
IActiveScriptParse64 y = (IActiveScriptParse64)Activator.CreateInstance(t);
Hm, that’s working in my .NET application, but not really nice. I will create a wrapper around the both interfaces as the method arguments are the same (except the size of the IntPtr, of course).
While searching for the x64 interface description I found that Microsoft already created such a wrapper. You can find this in _comimports.cs, but all members are marked as internal and a define is set to not compile the code, why? I don’t understand this.
Using the wrapper couldn’t be easier:
Type t = Type.GetTypeFromProgID("VBScript");
ActiveScriptParseWrapper wrapper = new ActiveScriptParseWrapper(Activator.CreateInstance(t));
I’ve created a feedback at Microsoft Connect, maybe we’ll get this or find a common solution for this.
Just one note: using C++ the compiler will always use the x86 version (IActiveScriptParse32). You need to add a define #define _WIN64 to explicit use the x64 version. Oh, that means the x64 compiled version before could use the 32-bit one? That is the difference I still don’t understand why it is different using C++ or C#. Is this a bug or a feature by design?