3

I've recently been looking for a way to use an unregistered DLL in VBScript. This accepted answer says that it can be accomplished using GetObject provided that (mentioned in the comments by the person who gave the answer) the DLL exposes a COM interface. I've never coded in C# before but I wanted to try it since the answer was for that language. After some searching, I found the following code example on this site:

using System;
using System.Runtime.InteropServices;

namespace Tester
{
    [Guid("D6F88E95-8A27-4ae6-B6DE-0542A0FC7039")]
    [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
    public interface _Numbers
    {
        [DispId(1)]
        int GetDay();

        [DispId(2)]
        int GetMonth();

        [DispId(3)]
        int GetYear();

        [DispId(4)]
        int DayOfYear();
    }

    [Guid("13FE32AD-4BF8-495f-AB4D-6C61BD463EA4")]
    [ClassInterface(ClassInterfaceType.None)]
    [ProgId("Tester.Numbers")]
    public class Numbers : _Numbers
    {
        public Numbers() { }

        public int GetDay()
        {
            return (DateTime.Today.Day);
        }

        public int GetMonth()
        {
            return (DateTime.Today.Month);
        }

        public int GetYear()
        {
            return (DateTime.Today.Year);
        }

        public int DayOfYear()
        {
            return (DateTime.Now.DayOfYear);
        }
    }
}

Using Visual Studio 2010 Professional, I created a new C# class library and named it Tester. I copied the above code into the default Class1.cs file and compiled it. Then, I made a .vbs file with the following code:

Option Explicit

Dim Obj

' This part gives the following error message:
'   ActiveX component can't create object: 'GetObject'
Set Obj = GetObject("C:\MyFolderPath\Tester.dll", "Tester.Numbers")
MsgBox Obj.GetDay

However, the code threw an error and would not instantiate the object. I tried running the .vbs file on the 32 and 64 bit version of wscript.exe because I'm on windows 7 64 bit. But, the error was the same both times. So, is there something I need to change in the C# code and/or some other option(s) I need to change in Visual Studio, or is the person's claim in the linked answer simply incorrect?

EDIT 1

My question is not a duplicate of this one. I realize the request there is of a similar nature. However, my question has to do with burden of proof. Nilpo has stated that GetObject will allow VBScript to instantiate an object using an unregistered C# DLL so long as it exposes a COM interface and even defended his position in that same question. I did the best I could to utilize the method he described and was unsuccessful. So, if it is possible, I would like to see a simple working example. And, if not, I was hoping to see some kind of documentation showing why not.

Furthermore, I will gladly use another programming language if that is truly the only way to allow the functionality I'm seeking. As such, I've removed C# from my question title and taken out the C# tag.

EDIT 2

I fixed the syntax highlighting for the original C# code I posted. It broke after I removed the C# tag from the question in my first edit.

Chris D
  • 351
  • 1
  • 13
  • 1
    In the project properties of the C# project check "Register for COM interop" in the "Build" tab. – Olivier Jacot-Descombes Oct 23 '17 at 20:09
  • @OlivierJacot-Descombes Unfortunately, we don't have admin access to our PC's at work so registering the DLL is not an option. – Chris D Oct 23 '17 at 20:23
  • 1
    First I've seen it. This would be technically possible if it were a normal COM dll, one with a DllGetClassObject() export and an embedded type library. Neither is the case for a DLL created with C#. Doing this kind of development without having admin access to the dev machine is not practical. I suppose you could limp along by using Regasm.exe's /regfile option and edit the generated .reg file, replacing HKLM with HKCU, but that gets to be painful busywork in a hurry. A custom [ComRegisterFunction] that registers in HKCU is more practical but hard to get right. – Hans Passant Oct 23 '17 at 20:37
  • Why not do the whole stuff in VB.NET? If you google for "C# to VB converter" you will find several online converters. – Olivier Jacot-Descombes Oct 23 '17 at 20:40
  • @OlivierJacot-Descombes I would happily attempt to code the DLL in another language so long as it would work in VBScript without needing to be registered. However, I do not have the option of avoiding VBScript entirely. – Chris D Oct 23 '17 at 20:53
  • @ChrisD That should work, but you still need to tell .Net to compile the DLL as [`ComVisible`](http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.comvisibleattribute.aspx) by applying the attribute to your class. You should then be able to use it through `GetObject`. – user692942 Oct 23 '17 at 21:31
  • Possible duplicate of [C# DLL from VBScript, no regasm](https://stackoverflow.com/questions/19033647/c-sharp-dll-from-vbscript-no-regasm) – user692942 Oct 23 '17 at 22:24

1 Answers1

-1

You are on the right track but that CodeProject link expects you to register the library with COM, which does require elevated privileges.

However, if you add the ComVisible attribute to the class you want to expose, once you have compiled the DLL you should be able to call it through GetObject().

[Guid("13FE32AD-4BF8-495f-AB4D-6C61BD463EA4")]
[ClassInterface(ClassInterfaceType.None)]
[ProgId("Tester.Numbers")]
[ComVisible(true)]
public class Numbers : _Numbers
{
    public Numbers() { }

    public int GetDay()
    {
        return (DateTime.Today.Day);
    }

    public int GetMonth()
    {
        return (DateTime.Today.Month);
    }

    public int GetYear()
    {
        return (DateTime.Today.Year);
    }

    public int DayOfYear()
    {
        return (DateTime.Now.DayOfYear);
    }
} 
user692942
  • 16,398
  • 7
  • 76
  • 175
  • I just tried the modification you posted and received the exact same error when I ran the .vbs file. – Chris D Oct 23 '17 at 21:47
  • @ChrisD you're certain you compiled it *(fresh build)* for 32 bit and ran your VBScript through the 32 bit subsystem or vice versa? – user692942 Oct 23 '17 at 21:55
  • I know that my Visual Studio program is 32 bit and I'm pretty sure the DLL would compile in 32 bit mode by default. I definitely didn't see or modify any settings to enable 64 bit compiling. And, I made sure to test the .vbs file in both the 32 and 64 bit versions of wscript.exe. – Chris D Oct 23 '17 at 22:01
  • @ChrisD I would double check that assumption, go to the Build tab of your project properties to make sure it is compiling to x86. – user692942 Oct 23 '17 at 22:05
  • It doesn't have anything to do with [ComVisible], the OP surely used the project setting. This is about getting the registry keys created. – Hans Passant Oct 23 '17 at 22:08
  • @HansPassant Why?, the whole point of `GetObject()` is to allow you to access an automation object by its physical path and not have to rely on the registry. Registering the COM via the registry defeats the purpose, in which case you would use `CreateObject()` instead. Don't get me wrong, registering COM DLLs via the registry is definitely the right way to do it, but this is a viable option for this circumstance. – user692942 Oct 23 '17 at 22:13
  • Well, because GetObject() isn't going to work on a DLL created in the C# language. The point of the question. – Hans Passant Oct 23 '17 at 22:17
  • @HansPassant If thats true, i'd be surprised. Unfortunately i'm not in a position to test this right now. – user692942 Oct 23 '17 at 22:20
  • @Lankymart I made sure my build was set to compile to x86 and re-tested. I received the same error. – Chris D Oct 24 '17 at 14:39
  • @HansPassant Lankymart is right regarding the registry. Altering that is not an option for me due to our network security. Since you've stated that what I want cannot be accomplished using C#, I've edited my original question to be language agnostic. Truthfully, I am much more concerned about determining whether or not it can be done vs. what programming language is used. – Chris D Oct 24 '17 at 14:48
  • @ChrisD can confirm I'm having the same issue, but interestingly when I try something like `Scripting.FilesystemObject` the error is slightly different - `VBScript runtime error: File name or class name not found during Automation operation: 'GetObject'`. Will keep testing. – user692942 Oct 24 '17 at 14:50