2010-09-14 19 views
5

Considere la biblioteca COM compatible con automatización en C#, que se proporciona a continuación. Sigue un patrón COM común de tener un colass de fábrica visible FooFactory que implementa ICreateFoos que crea un objeto de tipo IFoo. FooFactory es el solo colass en la biblioteca de tipos. (El patrón de fábrica es particularmente útil con COM, ya que no permite constructores parametrizados).¿Por qué es esta clase C# COM utilizable desde VBScript pero no JScript?

En el código de abajo, yo estoy encontrando que no puedo acceder a la interfaz IFoo regresar de JScripta menos que ponga la clase FooImpl ComVisible (descomentando líneas de comentarios, lo que hace que aparezca como un coclase en el tipo de biblioteca). No hay tal problema accediendo a esto desde VBscript.

Es decir, puedo ejecutar este VBScript:

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

Pero esto funcionalmente idéntica JScript falla, el error "C: \ temp \ jstest \ jstest.js (4, 1) Microsoft JScript error de ejecución: 'foo' es nulo o no un objeto ":

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

Si elimine la línea, puedo ver que nula == foo es falso.

¿Por qué sucede esto? ¿Es un error? Tenga en cuenta que creo que este es un problema, es una combinación de JScript y la implementación específica de C# /. Net (posiblemente de IDispatch), porque tengo otros servidores COM similares - implementados en C++ - que no presentan este problema de JScript.

El problema desaparece si descomenta las líneas comentadas en el código siguiente, haciendo que FooImpl sea visible como un coclass, pero específicamente no quiero hacer esto ya que no quiero exponer los detalles de implementación. Una solución alternativa parece ser hacer FooImpl ComVisible, pero marcar su constructor interno, lo que impide que los clientes puedan CoCreate, pero eso no es muy elegante.

Estoy ejecutando WinXP SP3 con Visual Studio 2005, .net 2, y he podido reproducir el problema en una instalación completamente nueva de TinyXP en un VirtualBox (ambos con Windows Script Host 5.7), y también en Windows 7 Ultimate usando .net SDKs 2.0, 3.0, 3.5 y 4.0 (WSH 5.8). Todos los sistemas operativos eran de 32 bits.

El código de la biblioteca:

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

puede compilar y registrar (puede que tenga que ejecutar como administrador para Regasm) esto con

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

BTW - por favor coméntenos si ha intentado reproducir este problema y ha tenido éxito o no lo ha hecho. – bacar

+0

Reproducido con VS2010 (C# express) y Windows XP SP3. – arx

Respuesta

5

Cuando QueryInterface se llama contra el objeto IFoo regresó de CreateFoo para IDispatch GUID devuelve E_NOINTERFACEa menos que ComVisible esté configurado para la clase de implementación real.

Cuando JScript prepara para llamar al método Foo que llama a QueryInterface varias veces, incluyendo específica con este GUID, y dado que es un error retornos no intenta utilizar Invoke.

Cuando VBScript prepara para llamar al método Foono verificación de la interfaz admite IDispatch. QueryInterface se llama, una vez, con el GUID para IDispatchEx pero parece simplemente suponer que IDispatch será compatible.

+2

Nota: vbscript es lo suficientemente inteligente como para darse cuenta de que la interfaz devuelta (IFoo) extiende IDispatch y por lo tanto no necesita llamar a QueryInterface. Si el mismo objeto se devuelve como un IUnknown en lugar de un IFoo, VB * does * llama a QueryInterface con IDispatch'd GUID. –

Cuestiones relacionadas