2010-09-14 10 views
5

Betrachten Sie die automatisierungskompatible COM-Bibliothek in C#, wie unten angegeben. Es folgt ein gemeinsames COM-Muster mit einer sichtbaren Factory-Co-Klasse FooFactory, die ICreateFoos implementiert und ein Objekt vom Typ IFoo erzeugt. FooFactory ist die einzige Co-Klasse in der Typbibliothek. (Das Factory-Muster ist besonders nützlich bei COM, da parametrisierte Konstruktoren nicht berücksichtigt werden).Warum ist diese C# COM-Klasse aus VBScript, aber nicht aus JScript verwendbar?

In dem folgenden Code, ich finde, dass ich nicht die zurück IFoo Schnittstelle von jscript, wenn ich die FooImpl Klasse ComVisible machen zugreifen kann (von kommentierten Zeilen uncommenting; dies bewirkt, dass sie als Co-Klasse in der erscheinen Typbibliothek). Es gibt kein Problem beim Zugriff von VBScript.

Das heißt, kann ich diese VBScript ausführen:

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

Aber diese funktional identisch JScript fehlschlägt, mit dem Fehler „C: \ temp \ jstest \ jstest.js (4, 1) Microsoft JScript Laufzeitfehler: ‚foo‘ ist null oder kein Objekt ":

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

Wenn ich die Zeile Kommentar-, kann ich sehen, dass null == foo falsch ist.

Warum passiert das? Ist es ein Fehler? Beachten Sie, dass dies ein Problem ist, eine Kombination aus JScript und der C#/.net-spezifischen Implementierung (möglicherweise von IDispatch), weil ich andere ähnliche COM-Server - in C++ implementiert - habe, die dieses Problem von JScript nicht aufweisen.

Das Problem verschwindet, wenn ich die kommentierten Zeilen im Code unten auskommentieren, wodurch FooImpl als Co-Klasse sichtbar gemacht wird - aber ich möchte dies nicht tun, da ich die Implementierungsdetails nicht offenlegen will. Ein Workaround scheint zu sein, FooImpl ComVisible zu machen, aber seinen Konstruktor intern zu markieren, was Clients daran hindert, CoCreate zu erstellen, aber das ist nicht elegant.

Ich bin auf WinXP SP3 mit Visual Studio 2005, .net 2 ausgeführt und konnte das Problem bei einer völlig neuen Installation von TinyXP auf einer VirtualBox (beide mit Windows Script Host 5.7) reproduzieren, und auch auf Windows 7 Ultimate mit .net SDK 2.0, 3.0, 3.5 und 4.0 (WSH 5.8). Alle Betriebssysteme waren 32-Bit.

Der Bibliothekscode:

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

Sie können kompilieren und registrieren (Sie müssen als Admin regasm laufen) diese mit

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

BTW - bitte kommentieren Sie, wenn Sie versucht haben, dieses Problem zu reproduzieren und es geschafft hat/fehlgeschlagen. – bacar

+0

Reproduziert mit VS2010 (C# Express) und Windows XP SP3. – arx

Antwort

5

Wenn Query-Interface aufgerufen wird, gegen das IFoo Objekt zurückgegeben aus CreateFoo für die IDispatch-GUID zurückgegeben E_NOINTERFACE, es sei denn, ComVisible ist für die tatsächliche implementierende Klasse festgelegt.

Wenn jscript die Foo Methode ruft Query-Interface mehrmals anrufen bereitet, auch mit diesem speziellen GUID, und da ein Fehler zurückkehrt ist es nicht versucht, Invoke zu verwenden.

Wenn Vbscript bereitet es die Foo Methode aufzurufen ist nicht Prüfung der Schnittstelle IDispatch unterstützt. QueryInterface wird einmal mit der GUID für IDispatchEx aufgerufen, aber es scheint einfach anzunehmen, dass IDispatch unterstützt wird.

+2

Hinweis: VBScript ist intelligent genug, um zu erkennen, dass die zurückgegebene Schnittstelle (IFoo) IDispatch erweitert und daher QueryInterface nicht aufrufen muss. Wenn dasselbe Objekt als ein IUnknown lieber als ein IFoo zurückgegeben wird, ruft VB * QueryInterface mit IDispatch'd GUID auf. –