Search code examples
c#dllvbscriptcomwsh

In Need of simple and surely working demo of Registration-Free COM example with WSH (vbscript/javascript)


I have been trying to get Registration-Free COM technology to work with WSH scripting without success. I have read through so many replies to this issue and tried many thing without success. Now I would need help to fix what is not correctly in my code which I provide below with some further info.

Here is the C-com class library (compiled into C_Com_Demo.dll) for testing purposes I created with Visual Studio 2015 with "Make assembly com visible" checked and "Enable the Visual Studio hosting process" and "Register for COM interop" unchecked.

C_Com_Demo.dll is in path "C:\tools\com\C_Com_Demo.dll"

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace testClass
{
[ComVisible(true)]
public class StringOperations
{
    [ComVisible(true)]
    public string getValue1(string sParameter)
    {
        switch (sParameter)
        {
              case "a":
                return "A was chosen";

              case "b":
                 return "B was chosen";

              case "c":
                 return "C was chosen";

               default:
                   return "Other";
            }
       }
       public string getValue2()
       {
        return "From VBS String Function";
       }
    }
}

Here is the manifest file as simple as it can be:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!-- Minimalist Manifest -->
  <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
   <file name = "C_Com_Demo.dll">
      <comClass clsid="{9d3e378b-d20e-43bc-a49f-e7e002eee72e}"
      progid = "C_Com_Demo"/>
   </file>
</assembly>

New manifest file VERSION:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!-- Minimalist Manifest -->
  <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <file name = "C_Com_Demo.dll"/>
   <clrClass clsid="{9d3e378b-d20e-43bc-a49f-e7e002eee72e}"
   name="C_Com_Demo"/>
  </assembly>

"C_Com_Demo.manifest" is also in the same location as dll: "C:\tools\com\C_Com_Demo.manifest"

My OS is Windows 10 (64 bit). Therefore I set Platform target to x64. .Net Framework is set to 4.

And Here is the WSH/vbscript by which I have tried to call the methods of the com-object:

Set actCtx = WScript.CreateObject("Microsoft.Windows.ActCtx")
    actCtx.Manifest = "C:\Tools\com\C_Com_demo.manifest"
Set DX = actCtx.CreateObject("testClass.StringOperations")
MsgBox DX.getValue1("a")

vbscript locates also in the same path, i.e. "C:\Tools\com\"

If I register the Com-class either via RegAsm.exe or via VS's build option "Register for COM interop" then the WSH/vbscript indeed works but the the desired goal of attaining the com-class via registration free technology is not working yet. The error always comes on the 3th line (Set DX = actCtx.CreateObject("testClass.StringOperations")) and says

ActiveX-component cannot create the object, Code: 800A01AD.

Can anyone say what I should change in the code above to make it work - for I really am stuck with this?


Solution

  • A basic requirement to make a reg-free manifest pay off is that you can modify the manifest of the client program. That is a significant obstacle here, the scripting host (c:\windows\system32\wscript.exe in this case) already has a manifest and does not allow you to embed your own or use a .manifest file.

    At best you could write a component manifest, it needs to resemble this:

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
        <assemblyIdentity name="ClassLibrary166" version="1.0.0.0" publicKeyToken="6e06a399ac99f486" />
        <clrClass 
            clsid = "{9d3e378b-d20e-43bc-a49f-e7e002eee72e}"
            name = "testClass.StringOperations"
            progid = "testClass.StringOperations"
            runtimeVersion = "v4.0.30319">
        </clrClass>
    </assembly>
    

    Note the use of clrClass instead of comClass, required for a [ComVisible] .NET class. Note the progid, it was wrong in your original manifest. And note the assemblyIdentity, required to help the CLR find the relevant assembly. I called it ClassLibrary166 in my test program, adjust as necessary. And I gave a strong name, use sn.exe -T to see it.

    I strongly recommend you give the class the [Guid("9d3e378b-d20e-43bc-a49f-e7e002eee72e")] attribute so you don't have to second-guess the required clsid. Without the attribute it will change when you make any changes to the class, one more failure mode you don't need. Normally it is a bad idea to use the attribute because it causes DLL Hell but that's what a manifest is supposed to fix.

    Note how I intentionally omitted the file element. It cannot work in this specific case, the CLR looks only in two specific places for the DLL in this scenario. First in looks in the GAC, that's the best place for it. The reason I gave it a strong name by using the Project > Properties > Signing tab. But it requires you to install the assembly into the GAC with gacutil.exe -i so you still have an install requirement. Also very little joy when you develop the code, be sure to get it stable before you do this.

    The other place it looks is in the directory where the EXE resides. Unfortunately that is c:\windows\system32, never a great idea to tinker with that directory. All and all, a manifest just doesn't help that much.