2012-06-24 10 views
9

Chciałbym utworzyć obiekt COM w języku C# i używać go przez IDispatch z JScript. Ta część jest całkiem prosta.Utwórz COM/ActiveXObject w języku C#, użyj języka JScript, z prostym zdarzeniem

Chcę również zaimplementować proste wywołania zwrotne na obiekcie COM, podobne do zdarzenia odsłoniętego przez obiekt XmlHttpRequest, który jest użyteczny w przeglądarce. Model ten pozwala JavaScript, aby dołączyć obsługi zdarzeń tak:

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

Chcę, aby mój klient-side kod JScript, aby wyglądać tak:

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

Co oznacza kod C# look like? Chciałbym ogólną sprawę - chciałbym móc przekazać argumenty do skryptu JavaScript fn.


Widziałem How can I make an ActiveX control written with C# raise events in JavaScript when clicked?, ale odpowiedzi wyglądają naprawdę skomplikowane do wykonania, i skomplikowane w użyciu.


Od this article, wydaje się, że zdarzenia XMLHttpRequest nie są zdarzeniami COM. onreadystatechange jest własnością typu IDispatch. Kiedy klienci skryptu ustawiają tę właściwość na funkcję, JScript marszałkuje ją jako obiekt IDispatch.

Jedyny problem, jaki pozostaje, to wywołanie IDispatch z C#.

Odpowiedz

14

Ponieważ jest to COM, zacznij od zdefiniowania interfejsu. Trzymajmy to prosto.

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

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

Następnie realizacja:

[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; 
    } 
} 

Głównym sztuczka jest metoda FireEvent. To działało dla mnie.

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

     return "ok"; 
    } 

kompilacji, że wszyscy razem, zarejestrować go z regasm:

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

... A następnie używać go z JScript tak:

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

to działa.

Można również zadzwonić z 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) 

przekazać parametry z powrotem z C# JScript z tym podejściem, myślę, że obiekty muszą być IDispatch, ale oczywiście można odesłać proste wartości marszałka jako ciąg, int i tak dalej, które są zbierane zgodnie z oczekiwaniami.

Na przykład zmodyfikuj kod C#, aby odesłać odwołanie do siebie i numer 42.

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

Następnie można dostać w JScript tak:

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

Albo w VBScript tak:

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

Uwaga: Można zdefiniować JScript funkcję obsługi zdarzenia, aby zaakceptować mniej argumentów niż wysyłanych przez obiekt C# podczas wywoływania "zdarzenia". Z mojego doświadczenia wynika, że ​​należy zaprojektować procedurę obsługi zdarzeń w VBScript, aby jawnie zaakceptować poprawną liczbę argumentów.

+0

To jest połączenie z opóźnieniem, a nie wydarzenie. Użyj atrybutu [ComSourceInterfaces], aby ujawnić zdarzenia .NET. –

+3

Dokładnie. W ogóle nie jest to wydarzenie COM, ale z pewnością jest łatwiejsze do zbudowania i wykorzystania niż okablowanie zdarzeń COM dla tego ograniczonego scenariusza - jednego obiektu i jednego użytkownika tego obiektu. I faktycznie, choć nie jest to wydarzenie COM, programiści poprawnie rozumieją to, aby zaspokoić ich potrzeby "zdarzenia" dla skryptowalnego obiektu. Właśnie dlatego XMLHttpRequest używa podejścia, jak przypuszczam, dla 'onreadystatechange'. To też nie jest "wydarzenie **", ale z pewnością jest rozumiane jako wydarzenie milionów twórców. Specyficzna definicja terminu "zdarzenie" COM nie ma znaczenia dla niektórych celów. – Cheeso

+0

Podczas tworzenia obiektu ActiveXObject w JScript, '' Cheeso.Greet "' pochodzi z 'ProjId', nazwa biblioteki DLL,' Namespace.ClassName' lub zupełnie gdzieś indziej? Bez względu na to, co próbuję, wydaje mi się, że zawsze otrzymuję komunikat "Serwer automatyzacji nie może utworzyć obiektu". –

2

Wow, wow! Może być łatwe?

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

następnie wykorzystać te komendy budować

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

Na JScript (WSH):

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

źródło: msdn

Enjoy!

Powiązane problemy