9

C#でCOMオブジェクトを作成し、JScriptからIDispatchを介して使用したいと思います。その部分は非常に単純です。

また、ブラウザーで使用可能なXmlHttpRequestオブジェクトによって公開されるイベントと同様に、COMオブジェクトに単純なコールバックを実装したいと思います。このモデルにより、Javascriptは次のようなイベントハンドラーをアタッチできます。

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

クライアント側のJScriptコードを次のようにしたいと思います。

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

C#コードはどのように見えますか?一般的なケースが欲しいのですが、引数をJavascriptfnに戻せるようにしたいと思います。


クリックしたときにJavaScriptでC#レイズイベントで記述されたActiveXコントロールを作成するにはどうすればよいですか?、しかし、そこにある答えは、実装するのが本当に複雑で、使用するのが複雑に見えます。


この記事から、XMLHttpRequestイベントはCOMイベントではないようです。はonreadystatechangeタイプのプロパティですIDispatch。スクリプトクライアントがそのプロパティを関数に設定すると、JScriptはそれをIDispatchオブジェクトとしてマーシャリングします。

残っている唯一の問題は、C#からIDispatchを呼び出すことです。

4

2 に答える 2

15

COM であるため、インターフェイスを定義することから始めます。シンプルにしましょう。

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

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

次に、実装:

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

主なトリックはFireEvent方法です。これは私にとってはうまくいきました。

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

        return "ok";
    }

それをまとめてコンパイルし、regasm に登録します。

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

...そして、次のように JScript から使用します。

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

できます。

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)

このアプローチで C# から JScript にパラメーターを戻すには、オブジェクトが IDispatch である必要があると思いますが、もちろん、期待どおりにマーシャリングされた string や int などとしてマーシャリングされた単純な値を送り返すことができます。

たとえば、C# コードを変更して、それ自体への参照と数値 42 を送り返すようにします。

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

次に、次のように jscript で取得できます。

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

または、VBScript では次のようになります。

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

注意: 「イベント」を呼び出すときに C# オブジェクトによって送信される引数よりも少ない引数を受け入れるように、jscript イベント ハンドラー関数を定義できます。私の経験では、正しい数の引数を明示的に受け入れるように VBScript でイベント ハンドラーを設計する必要があります。

于 2012-06-24T05:22:56.347 に答える
2

うわー、うわー!簡単かも?

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

次に、これらのビルドコマンドを使用します

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

jscript (wsh) の場合:

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

ソース: msdn

楽しみ!

于 2015-02-15T12:59:21.707 に答える