2010-09-14 8 views
5

Considerare la libreria COM compatibile con l'automazione in C#, riportata di seguito. Segue un modello COM comune di avere una coclasse di fabbrica visibile FooFactory che implementa ICreateFoos che crea un oggetto di tipo IFoo. FooFactory è la solo coclasse nella libreria dei tipi. (Il pattern factory è particolarmente utile con COM, poiché non consente costruttori parametrizzati).Perché questa classe COM C# è utilizzabile da VBScript ma non da JScript?

Nel codice qui sotto, ho constatato che non posso accedere all'interfaccia IFoo tornato da JScripta meno che io faccio la classe FooImpl ComVisible (decommentando righe di commento, questo fa sì che appaia come una coclasse nella digita libreria). Non c'è alcun problema con l'accesso da VBscript.

Cioè, posso correre questo VBScript:

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

Ma questo funzionalmente identici JScript non riesce, con l'errore "C: \ temp \ jstest \ jstest.js (4, 1) Microsoft JScript errore di runtime: 'foo' è null o non un oggetto ":

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

Se decommentare la linea, posso vedere che nulla == foo è falso.

Perché succede? E 'un errore? Notare che penso che questo sia un problema sia una combinazione di JScript e l'implementazione specifica di C#/.net (possibilmente di IDispatch), perché ho altri server COM simili - implementati in C++ - che non presentano questo problema da JScript.

Il problema scompare se annullo le righe commentate nel codice sottostante, rendendo FooImpl visibile come una coclasse - ma in particolare non voglio farlo perché non voglio esporre dettagli di implementazione. Una soluzione sembra essere quella di rendere FooImpl ComVisible, ma contrassegnare il suo costruttore interno, che impedisce ai client di essere in grado di creare CoCreate, ma non è elegante.

Sono in esecuzione su WinXP SP3 con Visual Studio 2005, .net 2 e sono stato in grado di riprodurre il problema su un'installazione completamente nuova di TinyXP su un VirtualBox (entrambi con Windows Script Host 5.7) e anche su Windows 7 Ultimate utilizza .net SDK 2.0, 3.0, 3.5 e 4.0 (WSH 5.8). Tutti i sistemi operativi erano a 32 bit.

Il codice libreria:

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

è possibile compilare e registrare (potrebbe essere necessario eseguire come amministratore per regasm) questo con

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

BTW - si prega di commentare se si è tentato di riprodurre questo problema ed è riuscito/non è riuscito a farlo. – bacar

+0

Riprodotto con VS2010 (C# express) e Windows XP SP3. – arx

risposta

5

Quando QueryInterface viene chiamato contro l'oggetto IFoo tornato da CreateFoo per il GUID IDispatch restituisce E_NOINTERFACEa meno che ComVisible sia impostato per la classe di implementazione effettiva.

Quando jscript si prepara a chiamare il metodo Foo chiama QueryInterface più volte, anche con questo specifico GUID, e dal momento che un errore è rendimenti non tenta di utilizzare Invoke.

Quando VBScript si prepara a chiamare il metodo Foo esso non controllo l'interfaccia supporta IDispatch. QueryInterface viene chiamato, una volta, con il GUID per IDispatchEx, ma sembra semplicemente supporre che IDispatch sarà supportato.

+2

Nota: vbscript è abbastanza intelligente da comprendere che l'interfaccia restituita (IFoo) estende IDispatch e quindi non ha bisogno di chiamare QueryInterface. Se lo stesso oggetto viene restituito come IUnknown anziché IFoo, VB * fa * chiama QueryInterface con GUID IDispatch'd. –

Problemi correlati