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

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

问题描述

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



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



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

  set ff = CreateObject(jstest.FooFactory)
set foo = ff.CreateFoo(0)
foo.Foo
但是这个 JScript失败,错误为C:\ temp \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' jstest\jstest.js(4,1)Microsoft JScript运行时错误:'foo'为空或不是对象:

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



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



为什么会发生这种情况?这是一个错误?注意,我认为这是一个问题是JScript和C#/。net特定实现(可能是IDispatch)的组合,因为我有其他类似的COM服务器 - 实现在C + +没有展现这个问题从JScript。 / p>

如果我取消注释下面的代码中注释的行,使FooImpl可视为一个coclass - 但我特别不想这样做,因为我不想要公开实现细节。一个解决方法似乎是使FooImpl ComVisible,但标记其构造函​​数内部,这阻止客户端CoCreate它,但这是几乎不优雅。



在WinXP SP3与Visual Studio 2005,.net 2,并已能够重现的问题,在一个完全全新安装的TinyXP在VirtualBox(与Windows Script Host 5.7),以及在Windows 7旗舰版使用.net SDKs 2.0 ,3.0,3.5和4.0(WSH 5.8)。所有操作系统均为32位。



库代码:

 使用系统; 
using System.Runtime.InteropServices;

[assembly:ComVisible(false)]

命名空间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 *版本,我们不使用importantNumber而
return new FooImpl();
}
}

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

您可以编译和注册您可能必须以管理员身份运行regasm)

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


解决方案

对于IDispatch GUID,它返回 E_NOINTERFACE CreateFoo 返回的code> 除非为实际实现类设置了ComVisible。



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



vbscript 准备调用 Foo 方法时, / strong>检查接口支持 IDispatch 。 QueryInterface被调用一次,带有IDispatchEx的GUID,但似乎只是假定IDispatch将被支持。


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).

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.

That is, I can run this VBScript:

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

But this functionally identical JScript fails, with the error "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();

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

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.

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.

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.

The library code:

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");
        }
    }
}

You can compile and register (you may have to run as admin to regasm) this with

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

解决方案

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.

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.

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天全站免登陆