What's the correct way to pass parameters from VBScript to COM interface implemented in C#?

Posted by nopopem on Stack Overflow See other posts from Stack Overflow or by nopopem
Published on 2010-06-07T15:30:55Z Indexed on 2010/06/08 8:32 UTC
Read the original article Hit count: 218

Filed under:
|
|

I'm trying to expose a fairly simple C# class to COM which should be usable from VBScript (among others). Some objects need to be created via COM calls and will be used in furter calls later on. The definition of the exposed classes and interfaces looks like this:

namespace Test 
{
  [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
  public interface IComInterface
  {
      IFoo CreateFoo();
      void UseFoo(int x, IFoo f);
  }

  [ClassInterface(ClassInterfaceType.None)]
  public sealed class CComInterface : IComInterface
  {
      public CComInterface() {}
      public IFoo CreateFoo() { return new Foo(); }
      public void UseFoo(int x, IFoo f) { f.Bar(); }
  }

  [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
  public interface IFoo
  {
      void Bar();
  }

  [ClassInterface(ClassInterfaceType.None)]
  public class Foo : IFoo
  {
      internal Foo() {}
      public void Bar() {}
  } 
}

The simplest thinkable COM client in VBScript does this:

Dim ci
Set ci = WScript.CreateObject("Test.CComInterface")
Dim foo
Set foo = ci.CreateFoo
foo.Bar
ci.UseFoo 0, foo

While the call to Bar succeeds, calling UseFoo fails with "Error 5: invalid procedure call or invalid argument"

The generated IDL seems ok to me:

dispinterface IComInterface {
    properties:
    methods:
        [id(0x60020003)]
        IFoo* CreateFoo();
        [id(0x60020004)]
        void UseFoo(
                        [in] long x, 
                        [in] IFoo* f);
};

The vbs call succeeds when I wrap the second parameter in parentheses like this:

ci.UseFoo 0, (foo)

As far as I understand (I'm no VBScript expert however) this forces the reference to foo to be passed by value, i.e. a copy of the reference is being made.

How can I change the interface so that it can be called with the foo reference directly? Since this will be a public interface used by customers I don't like the idea of having to explain why all the objects created need to be passed back in an extra pair of parentheses...

© Stack Overflow or respective owner

Related posts about c#

Related posts about com