Я пытаюсь представить довольно простой класс C # для COM, который должен использоваться из VBScript (среди прочих).
Некоторые объекты необходимо создавать с помощью COM-вызовов и позже они будут использоваться в последующих вызовах. Определение доступных классов и интерфейсов выглядит следующим образом:
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() {}
}
}
Самый простой мыслимый COM-клиент в VBScript делает это:
Dim ci
Set ci = WScript.CreateObject("Test.CComInterface")
Dim foo
Set foo = ci.CreateFoo
foo.Bar
ci.UseFoo 0, foo
В то время как вызов Bar завершается успешно, вызов UseFoo завершается с ошибкой «Ошибка 5: неверный вызов процедуры или неверный аргумент»
Сгенерированный IDL мне кажется нормальным:
dispinterface IComInterface {
properties:
methods:
[id(0x60020003)]
IFoo* CreateFoo();
[id(0x60020004)]
void UseFoo(
[in] long x,
[in] IFoo* f);
};
Вызов vbs завершается успешно, когда я заключаю в скобки второй параметр следующим образом:
ci.UseFoo 0, (foo)
Насколько я понимаю (однако я не эксперт по VBScript), это заставляет ссылку на foo передаваться по значению, т. Е. Создается копия ссылки.
Как я могу изменить интерфейс так, чтобы он мог вызываться напрямую с помощью ссылки на foo? Так как это будет общедоступный интерфейс, используемый клиентами, мне не нравится идея объяснения, почему все созданные объекты должны быть возвращены в дополнительной паре скобок ...