2010-09-14 24 views
5

Hãy xem xét thư viện COM tương thích tự động hóa trong C#, được đưa ra dưới đây. Nó tuân theo một mô hình COM phổ biến của việc có một nhà máy có thể nhìn thấy coclass FooFactory triển khai ICreateFoos tạo ra một đối tượng kiểu IFoo. FooFactory là chỉ có cốc trong thư viện kiểu. (Mẫu nhà máy đặc biệt hữu ích với COM, vì nó không cho phép các nhà xây dựng tham số hóa).Tại sao lớp C# COM này có thể sử dụng được từ VBScript chứ không phải JScript?

Trong đoạn mã dưới đây, tôi thấy rằng tôi không thể truy cập vào giao diện IFoo trở về từ JScripttrừ khi tôi làm cho lớp FooImpl ComVisible (bởi uncommenting dòng nhận xét, điều này làm cho nó xuất hiện như một coclass trong loại thư viện). Không có vấn đề như vậy khi truy cập từ VBscript.

Đó là, tôi có thể chạy VBScript này:

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

Nhưng điều này chức năng giống hệt JScript thất bại, với các lỗi "C: \ temp \ jstest \ jstest.js (4, 1) Microsoft JScript lỗi thời gian chạy: 'foo' là null hoặc không phải là đối tượng ":

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

Nếu tôi bỏ ghi chú dòng, tôi có thể thấy rằng null == foo là sai.

Tại sao điều này lại xảy ra? Nó là một lỗi? Lưu ý rằng tôi nghĩ rằng đây là một vấn đề là sự kết hợp giữa JScript và C# /. Thực hiện cụ thể (có thể là IDispatch), vì tôi có các máy chủ COM tương tự khác - được triển khai trong C++ - không thể hiện vấn đề này từ JScript.

Sự cố sẽ biến mất nếu tôi bỏ ghi chú trong mã bên dưới, làm cho FooImpl hiển thị dưới dạng kén - nhưng tôi đặc biệt không muốn làm điều này vì tôi không muốn hiển thị chi tiết triển khai. Một cách giải quyết dường như là để làm cho FooImpl ComVisible, nhưng đánh dấu nội bộ của nó là xây dựng, ngăn cản các khách hàng có thể CoCreate nó, nhưng đó là hầu như không thanh lịch.

Tôi đang chạy trên WinXP SP3 với Visual Studio 2005, .net 2 và đã có thể tạo lại sự cố trên cài đặt hoàn toàn mới của TinyXP trên VirtualBox (cả với Windows Script Host 5.7) và cả trên Windows 7 Ultimate sử dụng .net SDK 2.0, 3.0, 3.5 và 4.0 (WSH 5.8). Tất cả các hệ điều hành đều là 32 bit.

Mã thư viện:

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

Bạn có thể biên dịch và đăng ký (bạn có thể phải chạy như admin regasm) này với

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

BTW - vui lòng nhận xét nếu bạn đã cố gắng tái tạo vấn đề này và đã thành công/không thực hiện được. – bacar

+0

Sao chép với VS2010 (C# express) và Windows XP SP3. – arx

Trả lời

5

Khi QueryInterface được gọi là chống lại các đối tượng IFoo trở về từ CreateFoo cho IDispatch GUID nó trả về E_NOINTERFACEtrừ khi ComVisible được đặt cho lớp triển khai thực tế.

Khi JScript chuẩn bị để gọi phương thức Foo nó gọi QueryInterface nhiều lần, kể cả với GUID cụ thể này, và kể từ một lỗi chính là lãi suất không cố gắng sử dụng Invoke.

Khi VBScript chuẩn bị để gọi Foo phương pháp nó không kiểm tra giao diện hỗ trợ IDispatch. QueryInterface được gọi, một lần, với GUID cho IDispatchEx nhưng có vẻ như chỉ đơn giản giả định IDispatch sẽ được hỗ trợ.

+2

Lưu ý: vbscript đủ thông minh để nhận ra rằng giao diện trả về (IFoo) mở rộng IDispatch và vì vậy nó không cần gọi QueryInterface. Nếu cùng một đối tượng được trả về như một IUnknown chứ không phải là một IFoo thì VB * sẽ * gọi QueryInterface với IDispatch'd GUID. –

Các vấn đề liên quan