问题描述
考虑下面给出的 C# 中与自动化兼容的 COM 库.它遵循一个常见的 COM 模式,即有一个可见的工厂协同类 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 运行时错误:'foo' 为空或不是对象":
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,但将其构造函数标记为内部,以防止客户端能够共同创建它,但这并不优雅.
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(均使用 Windows Script Host 5.7)和 Windows 上全新安装 TinyXP 时重现该问题7 Ultimate 使用 .net SDKs 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
推荐答案
当针对从 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 中使用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!