开发者

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

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...


Louis.fr on msdn social helped me out - the trick is to tell the marshaller how to marshal the parameter like this:

public void UseFoo(int x, [MarshalAs(UnmanagedType.IDispatch)] IFoo f) { f.Bar(); }


Try changing the C# interface to take a ref parameter.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜