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

考虑下面给出的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 

但这个function相同的 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中出现这个问题。

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

我正在使用Visual Studio 2005,.net 2在WinXP SP3上运行,并且能够在VirtualBox上完全全新安装TinyXP(两者都使用Windows Script Host 5.7)以及使用Windows 7 Ultimate进行重现.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 

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

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

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