Question

I have a class defined in VBSript:

Class Foo
  Public i
End Class

of which I want to pass an instance to a COM object written in C#:

Dim oCOMTEST : Set oCOMTEST = CreateObject("COMTests.Class1")

Dim oFoo : Set oFoo = new Foo
oFoo.i = 42
Call oCOMTEST.M(oFoo)

The method M is defined as:

public void M(ref object foo)

Currently the method expects an object but I would rather have the method take a C#-equivalent type of Foo. Among others I have tried changing object to Foo, with

[StructLayout(LayoutKind.Sequential)]
public class Foo
{
  [MarshalAs(UnmanagedType.U4)]
  public int i;
}

but without success. Therefore my question is:

How does the marshaled C# version of the VBScript type Foo look like?

--

This is my minimal test case.

using System.Runtime.InteropServices;

namespace COMTests
{
  [ComVisible(true)]
  [Guid("4624071F-2D98-4ECC-8898-558F4D24EEC9")]
  [InterfaceType(ComInterfaceType.InterfaceIsDual)]
  public interface IClass1
  {
    void M(ref object foo);
  }

  [ComVisible(true)]
  [Guid("9F2B6958-742F-4E5D-A5F3-D6BDC6C841DB")]
  [ClassInterface(ClassInterfaceType.None)]
  [ProgId("COMTests.Class1")]
  public class Class1 : IClass1
  {
    public void M(ref object foo)
    {
      System.Diagnostics.Debugger.Launch();
    }
  }
}

And the following VBScript:

Dim oCOMTEST : Set oCOMTEST = CreateObject("COMTests.Class1")

Dim oFoo : Set oFoo = new Foo
oFoo.i = 42
Call oCOMTEST.M(oFoo)

Class Foo
  Public i
End Class
Was it helpful?

Solution

The VBScript class is not a full COM object because it has no IID (interface ID) associated with it. So, I may be wrong, but I don't think you can have it match a .NET class or interface (many attributes such as ComImport expect an associated Guid attribute). It could work if Foo was created from a "real" COM object. In the background, I believe the VBScript's Foo object implements IDispatch only, so it's by nature very dynamic.

However, you can still use its properties and metods quite easily with the c# dynamic pseudo-type keyword, for example, the following code should work fine:

[ComVisible(true)]
[Guid("9F2B6958-742F-4E5D-A5F3-D6BDC6C841DB")]
[ProgId("COMTests.Class1")]
public class Class1
{
    public void M(dynamic foo)
    {
        Console.WriteLine("foo:" + foo.i);
    }
}

PS: You do not need the interface or the ref attribute in this context. With my code above, this is what will get created automatically by .NET (in IDL terms, a bit simplified for readability):

[
  uuid(E66DC08B-A63A-41A8-B63D-15ED6F4569AB),
  version(1.0),
]
library ClassLibrary1
{
    interface _Class1;

    [
      uuid(9F2B6958-742F-4E5D-A5F3-D6BDC6C841DB),
      version(1.0),
    ]
    coclass Class1 {
        [default] interface _Class1;
        interface _Object;
    };

    [
      odl,
      uuid(F56AF0FC-D93B-399E-8FBD-9B72CF50D7D9),
      hidden,
      dual,
      oleautomation,
    ]
    interface _Class1 : IDispatch {
    };
};
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top