2012-06-24 28 views
9

Tôi muốn tạo đối tượng COM trong C# và sử dụng nó thông qua IDispatch từ JScript. Phần đó khá đơn giản.Tạo COM/ActiveXObject trong C#, sử dụng từ JScript, với sự kiện đơn giản

Tôi cũng muốn triển khai các cuộc gọi lại đơn giản trên đối tượng COM, tương tự như sự kiện được hiển thị bởi đối tượng XmlHttpRequest có thể sử dụng trong trình duyệt. mô hình cho phép Javascript để đính kèm xử lý sự kiện như thế này:

var xmlhttp = new ActiveXObject("MSXML.XMLHTTP"); 
xmlhttp.onReadyStateChange = function() { 
    ... 
}; 

Tôi muốn mã JScript client-side của tôi trông như thế này:

var myObject = new ActiveXObject("MyObject.ProgId"); 
myObject.onMyCustomEvent = function(..args here..) { 
    ... 
}; 

gì mã C# như thế nào? Tôi muốn các trường hợp chung - Tôi muốn để có thể vượt qua các đối số trở lại Javascript fn.


Tôi đã xem How can I make an ActiveX control written with C# raise events in JavaScript when clicked?, nhưng câu trả lời có vẻ thực sự phức tạp để triển khai và phức tạp khi sử dụng.


Từ this article, có vẻ như sự kiện XMLHttpRequest không phải là sự kiện COM. Các onreadystatechange là một tài sản của loại IDispatch. Khi các trình khách kịch bản thiết lập thuộc tính đó cho một hàm, JScript sắp xếp nó như một đối tượng IDispatch.

Vấn đề duy nhất còn lại là sau đó gọi IDispatch từ C#.

Trả lời

14

Vì đó là COM, hãy bắt đầu bằng cách xác định giao diện. Hãy giữ nó đơn giản.

[Guid("a5ee0756-0cbb-4cf1-9a9c-509407d5eed6")] 
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] 
public interface IGreet 
{ 
    [DispId(1)] 
    string Hello(string name); 

    [DispId(2)] 
    Object onHello { get; set; } 
} 

Sau đó, việc thực hiện:

[ProgId("Cheeso.Greet")] 
[ComVisible(true)] 
[Guid("bebcfaff-d2f4-4447-ac9f-91bf63b770d8")] 
[ClassInterface(ClassInterfaceType.None)] 
public partial class Greet : IGreet 
{ 
    public Object onHello { get; set; } 

    public String Hello(string name) 
    { 
     var r = FireEvent(); 
     return "Why, Hello, " + name + "!!!" + r; 
    } 
} 

Bí quyết chính là phương pháp FireEvent. Điều này làm việc cho tôi.

private string FireEvent() 
    { 
     if (onHello == null) return " (N/A)"; 
     onHello 
      .GetType() 
      .InvokeMember 
      ("", 
      BindingFlags.InvokeMethod, 
      null, 
      onHello, 
      new object [] {}); 

     return "ok"; 
    } 

Compile rằng tất cả lại với nhau, đăng ký nó với regasm:

%NET64%\regasm.exe Cheeso.Greet.dll /register /codebase 

... Và sau đó sử dụng nó từ JScript như thế này:

var greet = new ActiveXObject("Cheeso.Greet"), response; 
greet.onHello = function() { 
    WScript.Echo("onHello (Javascript) invoked."); 
}; 
response = greet.Hello("Fred"); 
WScript.Echo("response: " + response); 

Nó hoạt động.

Bạn cũng có thể gọi nó là từ VBScript:

Sub onHello() 
    WScript.Echo("onHello (VBScript) invoked.") 
End Sub 

Dim greet 
Set greet = WScript.CreateObject("Cheeso.Greet") 
greet.onHello = GetRef("onHello") 
Dim response 
response = greet.Hello("Louise") 
WScript.Echo("response: " & response) 

Để vượt qua các tham số về từ C# để JScript với cách tiếp cận này, tôi nghĩ rằng đối tượng cần phải được IDispatch, nhưng tất nhiên bạn có thể gửi lại đơn giản các giá trị được sắp xếp như chuỗi, int, v.v. được sắp xếp như bạn mong đợi. Ví dụ: sửa đổi mã C# để gửi lại tham chiếu đến chính nó và số 42.

 onHello 
      .GetType() 
      .InvokeMember 
      ("", 
      BindingFlags.InvokeMethod, 
      null, 
      onHello, 
      new object [] { this, 42 }); 

Sau đó, bạn có thể nhận được rằng trong JScript như vậy:

greet.onHello = function(arg, num) { 
    WScript.Echo("onHello (Javascript) invoked."); 
    WScript.Echo(" num = " + num + " stat=" + arg.status); 
}; 

Hoặc trong VBScript như vậy:

Sub onHello (obj, num) 
    WScript.Echo("onHello (VBScript) invoked. status=" & obj.status) 
    WScript.Echo(" num= " & num) 
End Sub 

NB: Bạn có thể xác định JScript chức năng xử lý sự kiện của bạn để chấp nhận ít args hơn được gửi bởi đối tượng C# khi gọi "sự kiện". Theo kinh nghiệm của tôi, bạn cần thiết kế trình xử lý sự kiện trong VBScript để chấp nhận đúng số lượng đối số chính xác.

+0

Đây là cuộc gọi bị ràng buộc muộn, không phải là sự kiện. Sử dụng thuộc tính [ComSourceInterfaces] để hiển thị các sự kiện .NET. –

+3

Chính xác. Nó không phải là một sự kiện COM ở tất cả, nhưng nó chắc chắn là đơn giản để xây dựng và sử dụng hơn dây lên các sự kiện COM cho kịch bản hạn chế này - một đối tượng và một người dùng của đối tượng đó. Và trên thực tế, mặc dù nó không phải là một sự kiện COM, các lập trình viên hiểu chính xác nó để đáp ứng nhu cầu của họ về "một sự kiện" cho một đối tượng có thể viết được. Đây là lý do tại sao XMLHttpRequest sử dụng cách tiếp cận, tôi giả sử, cho 'onreadystatechange'. Điều đó nữa, là "không ** một sự kiện **" nhưng chắc chắn nó được hiểu là một sự kiện của hàng triệu dev. Định nghĩa cụ thể của COM về thuật ngữ "sự kiện" không liên quan đến một số mục đích. – Cheeso

+0

Khi tạo ActiveXObject trong JScript, có phải '' Cheeso.Greet "' xuất phát từ 'ProjId', tên DLL,' Namespace.ClassName' hoặc ở một nơi khác hoàn toàn không? Không có vấn đề gì tôi cố gắng tôi dường như luôn luôn nhận được "Tự động hóa máy chủ không thể tạo đối tượng". –

2

Wow, wow! Có thể dễ dàng?

using System; 
using System.EnterpriseServices; 

[assembly: ApplicationName("Calculator")] 
[assembly: ApplicationActivation(ActivationOption.Library)] 
public class Calculator : ServicedComponent 
{ 
    public int Add(int x, int y){ return (x + y); } 
} 

sau đó sử dụng các build lệnh

sn -k Calculator.snk   
csc /t:library Calculator.cs 
regsvcs Calculator.dll 

On JScript (WSH):

c = new ActiveXObject("Calculator"); 
WScript.Echo(typeof(c)); // output: object 
WScript.Echo(c.Add(4,1)); // output: 5 

nguồn: msdn

Thưởng thức!

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