c# - 为什么这个 C# COM 类可用于 VBScript 而不是 JScript?

标签 c# com vbscript ole javascript

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

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

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

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

但是这个功能相同的 JScript 失败了,错误是“C:\temp\jstest\jstest.js(4, 1) Microsoft JScript runtime error: 'foo' is null or not an object ":

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 作为一个组件类可见 - 但我特别不想这样做,因为我不想公开实现细节。一种解决方法似乎是使 FooImpl ComVisible,但将其构造函数标记为内部,这会阻止客户端能够 CoCreate 它,但这并不优雅。

我在带有 Visual Studio 2005、.net 2 的 WinXP SP3 上运行,并且能够在 VirtualBox(均使用 Windows Script Host 5.7)和 Windows 上全新安装 TinyXP 时重现该问题7 Ultimate 使用 .net SDK 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");
        }
    }
}

您可以编译并注册(您可能必须以管理员身份运行才能重新登录)

csc /target:library jstest.cs
regasm /codebase jstest.dll

最佳答案

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

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

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

关于c# - 为什么这个 C# COM 类可用于 VBScript 而不是 JScript?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3712005/

相关文章:

c# - Field "account"&"card"永远不会被赋值,默认为Null

.NET:如何确定对象是否为 COM 对象?

vbscript - 如何将带有空格和引号的命令作为单个参数传递给 CScript?

c# - ASP.NET Core 中的 ValidateInput(bool)

c# - launchProfile.json 中的 "dotnet run"默认配置文件设置是什么?

C# .NET SqlDependency

c++ - 在遗留 Win32 应用程序中实现 COM 事件接收器

c++ - 如何在 C++ 中单独给定一个 ProgID 来实例化一个类?

vbscript - 使用现代数组填充 VBscript 数组

vbscript - 预计语句结束 (vbscript)