为什么这个C#COM类可以从VBScript而不是JScript中使用?

时间:2010-09-14 18:55:21

标签: c# com vbscript ole javascript

考虑C#中与自动化兼容的COM库,如下所示。它遵循一个常见的COM模式,即有一个可见的工厂coclass FooFactory实现ICreateFoos,它创建一个IFoo类型的对象。 FooFactory是类型库中仅 coclass。 (工厂模式对COM特别有用,因为它不允许参数化构造函数。)

在下面的代码中,我发现我无法从 jscript 访问返回的IFoo接口,除非我将FooImpl类设为ComVisible (通过取消注释注释行;这个使它在类型库中显示为coclass)。 从VBscript 访问它没有这样的问题。

也就是说,我可以运行这个VBScript:

set ff = CreateObject("jstest.FooFactory")
set foo = ff.CreateFoo(0)
foo.Foo

但是这个功能完全相同的 JScript失败了,错误“C:\ temp \ jstest \ jstest.js(4,1)Microsoft JScript运行时错误:'foo'为null或者不是对象“:

var ff = new ActiveXObject("jstest.FooFactory");
var foo = ff.CreateFoo(0)
//WScript.Stdout.WriteLine(null==foo)
foo.Foo();

如果我取消注释该行,我可以看到null == foo为false。

为什么会这样?这是一个错误吗?请注意,我认为这是一个问题,是JScript和C#/ .net特定实现(可能是IDispatch)的组合,因为我有其他类似的COM服务器 - 用C ++实现 - 不会从JScript中出现这个问题。 / p>

如果我取消注释下面代码中的注释行,使得FooImpl作为coclass可见,问题就消失了 - 但我特别不希望这样做,因为我不想暴露实现细节。一个解决方法似乎是使FooImpl ComVisible,但标记其构造函​​数内部,这阻止客户端能够CoCreate它,但这不是很优雅。

我正在使用Visual Studio 2005,.net 2在WinXP SP3上运行,并且能够在VirtualBox上完全全新安装TinyXP(都使用Windows Script Host 5.7)以及Windows上重现问题7终极使用.net SDKs 2.0,3.0,3.5和4.0(WSH 5.8)。所有操作系统都是32位。

图书馆代码:

using System;
using System.Runtime.InteropServices;

[assembly: ComVisible(false)]

namespace jstest
{
    [ComVisible(true)]
    public interface ICreateFoos
    {
        IFoo CreateFoo(int importantNumber);
    }

    [ComVisible(true)]
    public interface IFoo
    {
        void Foo();
    }

    [ComVisible(true)]
    public class FooFactory : ICreateFoos
    {
        public IFoo CreateFoo(int importantNumber)
        {   // in *this* version, we don't use importantNumber yet
            return new FooImpl();
        }
    }

    //[ComVisible(true)]
    public class FooImpl : IFoo
    {
        public void Foo()
        {
            Console.WriteLine("Foo");
        }
    }
}

您可以使用

编译和注册(您可能需要以管理员身份运行到regasm)
csc /target:library jstest.cs
regasm /codebase jstest.dll

1 个答案:

答案 0 :(得分:6)

当针对IDispatch GUID从IFoo返回的CreateFoo对象调用QueryInterface时,它返回E_NOINTERFACE ,除非为实际的实现类设置了 ComVisible。

jscript 准备调用Foo方法时,它会多次调用QueryInterface,包括使用此特定GUID,并且由于返回错误,因此不会尝试使用{{1 }}

vbscript 准备调用Invoke方法时,检查界面是否支持Foo。使用IDispatchEx的GUID调用QueryInterface一次,但它似乎只是假设支持IDispatch。

相关问题