为什么这个 C# COM 类可以从 VBScript 使用,但不能从 JScript 使用? [英] Why is this C# COM class usable from VBScript but not JScript?

查看:25
本文介绍了为什么这个 C# COM 类可以从 VBScript 使用,但不能从 JScript 使用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Consider the automation-compatible COM library in C#, given below. It follows a common COM pattern of having a visible factory coclass FooFactory implementing ICreateFoos which creates an object of type IFoo. FooFactory is the only coclass in the type library. (The factory pattern is particularly useful with COM, as it does not allow for parameterized constructors).

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

In the code below, I'm finding that I cannot access the returned IFoo interface from jscript unless I make the FooImpl class ComVisible (by uncommenting commented lines; this causes it to appear as a coclass in the type library). There is no such problem accessing this from VBscript.

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

That is, I can run this VBScript:

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

但是这个功能相同 JScript 失败,出现错误C: empjstestjstest.js(4, 1) Microsoft JScript runtime error: 'foo' is null or not an object":

But this functionally identical JScript fails, with the error "C: empjstestjstest.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 是假的.

If I uncomment the line, I can see that null==foo is false.

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

Why does this happen? Is it a bug? Note that I think this is a problem is a combination of JScript and the C#/.net-specific implementation (possibly of IDispatch), because I have other similar COM servers - implemented in C++ - that do not exhibit this problem from JScript.

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

The problem goes away if I uncomment the commented lines in the code below, making FooImpl visible as a coclass - but I specifically do not want to do this as I don't want to expose implementation details. A workaround seems to be to make FooImpl ComVisible, but mark its constructor internal, which prevents clients from being able to CoCreate it, but that's hardly elegant.

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

I'm running on WinXP SP3 with Visual Studio 2005, .net 2, and have been able to reproduce the issue on a completely fresh install of TinyXP on a VirtualBox (both with Windows Script Host 5.7), and also on Windows 7 Ultimate using .net SDKs 2.0, 3.0, 3.5 and 4.0 (WSH 5.8). All OSes were 32-bit.

库代码:

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

推荐答案

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

When QueryInterface is called against the IFoo object returned from CreateFoo for the IDispatch GUID it returns E_NOINTERFACE unless ComVisible is set for the actual implementing class.

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

When jscript prepares to call the Foo method it calls QueryInterface several times, including with this specific GUID, and since an error is returns it doesn't try to use Invoke.

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

When vbscript prepares to call the Foo method it does not check the interface supports IDispatch. QueryInterface is called, once, with the GUID for IDispatchEx but it seems to simply assume IDispatch will be supported.

这篇关于为什么这个 C# COM 类可以从 VBScript 使用,但不能从 JScript 使用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆