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
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 {
};
};