C#での自PC内プロセス間通信

【追記】

WCF(Windows Communication Foundation)にて
プロセス間通信するサンプルを書いてみました(Windowsサービス~Winフォーム間 ローカルPCリモートPC対応)
参考にどぞー

C#での自PC内プロセス間通信(WCF版:Windowsサービスにて実装)@ぎんゆぅ~さん


またまた,必要に迫られて実装をば...

最初,Localhostに対して,ソケットで通信しようかと思いましたが…
Net Frameworkに,便利なクラスが追加されているそうで

    IpcServerChannelクラス
    IpcClientChannelクラス
を使えば,さくっとプロセス間通信,実装できましたです

なお,こちらのページを参考にしました
あわせて,御確認ください

[C#][Program]C# .NETリモーティングを使ったプロセス間通信@tetsuarossa
[C#][Program]C# .NETリモーティングを使ったプロセス間通信 その2@tetsuarossa

tetsuarossaさま,サンクスです 🙂




【追記:09/04/15】

ここに記載したコード,サンプルプロジェクトとして,丸ごとアップしておきます
ダウンロードは,こちら@C#
ご自由にお使いくださいませ!

なお,バグってたら,すまんでごわす :mrgreen:




1.System.Runtime.Remotingを参照設定(サーバ側クライアント側両方で,です)
2.下記コードを Using追加する(サーバ側クライアント側両方で,です)
なお,RemoteTranceObjectネームスペースが情報共有クラスとなります
using System.Runtime.Remoting.Channels.Ipc;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting;
using RemoteTranceObject;
3.情報共有を行うRemoteTranceObjectネームスペースの定義
サーバー,クライアント,同一の定義が必要です.
この部分だけ,クラスDLLにして,参照設定しちゃうほうが,あとあと管理が楽かも?
今回は制御モード(int)と,怪しい文字列(string)をクライアント側からサーバ側へ伝送させます
namespace RemoteTranceObject  //共有オブジェクト(サーバー/クライアントで全く同一内容で定義してください)
{
    public class ClassFileInfo : MarshalByRefObject
    {
        public class ClassFileInfoEventArg : EventArgs            //情報を引き渡すイベント引数クラス
        {
            private int m_mode = 0;                    //モード
            private string m_FileName = "";            //文字列
            public int Mode { get { return m_mode; } set {m_mode = value;}}
            public string FileName { get { return m_FileName; } set {m_FileName = value;}}
            public ClassFileInfoEventArg(int tmpMode, string tmpfName)
            {
                m_mode = tmpMode;
                m_FileName = tmpfName;
            }
        }

        public delegate void CallEventHandler(ClassFileInfoEventArg e);
        public event CallEventHandler OnTrance;
        public void DataTrance(int tmpmode, string tmpfname)
        {
            if (OnTrance != null)
            {
                OnTrance(new ClassFileInfoEventArg(tmpmode, tmpfname));
            }
        }
        
    }
}
4.サーバー側の実装
普通のWindowsフォームアプリのプロジェクト作って
ラベル1個と,リストボックス1個を貼り付けました
クライアントから送られてきた情報は,リストボックスに追加されていきます
namespace ProTestServer
{
    public partial class Form1 : Form
    {
        private ClassFileInfo m_msg;
        //コンストラクタ
        public Form1()
        {
            InitializeComponent();
        }

        //フォームロード
        private void Form1_Load(object sender, EventArgs e)
        {
            //このチャネル生成系は一度通せばいいっぽい

            // IPC Channelを作成
            IpcServerChannel servChannel = new IpcServerChannel("processtrancetest");
            // リモートオブジェクトを登録
            ChannelServices.RegisterChannel(servChannel, true);
            //// ChannelのURIを表示
            label1.Text = servChannel.GetChannelUri();

            // イベントを登録
            m_msg = new ClassFileInfo();

            m_msg.OnTrance += new ClassFileInfo.CallEventHandler(m_msg_OnTrance);
            RemotingServices.Marshal(m_msg, "message", typeof(ClassFileInfo));
        }

        //クライアントから転送されてきた情報をリストボックスに表示
        void m_msg_OnTrance(ClassFileInfo.ClassFileInfoEventArg e)
        {
            string st;
            switch(e.Mode)
            {
                case 1:
                    st = "モード1";
                    break;
                case 2:
                    st = "モード2";
                    break;
                case 3:
                    st = "モード3";
                    break;
                default:
                    st = "???";
                    break;
            }


            listBox1.Items.Add(st + " , " + e.FileName);
        }
    }
}
5.クライアント側の実装 こちらも普通のWindowsフォームアプリにて
ラジオボタン3つ,テキストボックス1個,ボタン1個を貼り付けてください
ボタンを押すたびに,サーバ側へ情報伝送します
あと,3つのラジオボタンのTagプロパティに1~3の数値を設定してあります
namespace ProTestClient
{
    public partial class Form1 : Form
    {
        private int m_mode;
        private ClassFileInfo m_msg = null;
        //コンストラクタ
        public Form1()
        {
            InitializeComponent();
            m_mode = 1;
        }

        //フォームロード
        private void Form1_Load(object sender, EventArgs e)
        {
            //このチャネル生成系は一度通せばいいっぽい
            
            // IPC Channel を作成
            IpcClientChannel clientChannel = new IpcClientChannel();
            // リモートオブジェクトを登録
            ChannelServices.RegisterChannel(clientChannel, true);
            // オブジェクトを作成
            m_msg = (ClassFileInfo)Activator.GetObject(typeof (ClassFileInfo), "ipc://processtrancetest/message");
        }

        //ラジオボタンでモードを設定
        private void rdbClick(object sender, EventArgs e)
        {

            string st = (sender as RadioButton).Tag as string;
            m_mode = int.Parse(st);

        }

        //ボタンを押すたびに,モードと入力文字をサーバ側へ送信
        private void button1_Click(object sender, EventArgs e)
        {
            string st = textBox1.Text;
            if (st == "")
            {
                st = "空文字";
            }

            m_msg.DataTrance(m_mode, st);                //サーバーへ伝送
        }

    }
}
クライアント側 ClassFileInfo.DataTrance() を呼び出すたびに
サーバ側で,デリゲートが呼び出される仕組みです

情報共有クラスにプロパティを追加すれば
サーバ側で,設定した値をクライアントでも,読み出せるはず,です(汗

また,私自身がどこかで使うかもしれないので
ここに記載しておきますです…


12件のフィードバック

  1. 通りすがり より:

    ありがとうございました。とても参考になりました。 😉
    なかなか form 形式での sample が見つからなかったので。
    蛇足かもしれませんが 2 の所の using System.Runtime.Remoting の部分で、ソリューションエクスプローラで各 exe の参照設定に System.Runtime.Remotingを追加しないと私の場合ビルドエラーになってしまいました。
    重ねてありがとうございます。参考になりました。

  2. くまさん より:

    >>通りすがり さま

    ようこそ!
    参考になったみたいで,よかったです

    参照設定の件,(1)にちょろっと,書いてありますです
    見落とされたかな?? 😉


    また,面白そうなコードが出てきたら,ここに記載していきますです 🙂

  3. たけぞ より:

    Tag値のとり方がわからず、ここへたどり着きました。ありがとうございましたー。

  4. くまさん より:

    >>たけぞ さま

    助けになったみたいで,よかったです
    また,面白いTipsを書ければと思いますです♪

  5. 通りすがり2 より:

    とてもシンプルでわかりやすいサンプルありがとうございました。使わせていただきます!

  6. くまさん より:

    >>通りすがり2 さま

    どうぞどうぞ!ガンガンお使いくださいませ!!
    いいモノが出来上がるのを,期待していますです

  7. ちょっと立ち寄りました より:

    🙁
    クライアントからデータを送信しましたぁ~
    サーバー側がうごいてるみたいなので、
    送信はできてるみたいなのですが

    サーバー側で下記のエラーが発生して停止しました。


    listBox1.Items.Add(st + ” , ” + e.FileName);
    有効でないスレッド間の操作:コントロールが
    作成されたスレッド以外のスレッドから
    コントロール’listBox1’がアクセスされました

    そのあとクライアント側で
    m_msg.DataTrance(m_mode, st);
    のところでも上記と同じメッセージが発生して停止しました。

  8. くまさん より:

    >>ちょっと立ち寄りました さま

    あら?
    IPCを使ったプロセス通信,いつの間にか,スレッド化されちゃった??

    最近,IPCでの実装,やってないからなぁ(汗

    一応このエラーは,スレッド内での,Windows Formコントロールへのプロパティやらメソッド操作のエラーです

    こちらのページを確認して,スレッド対応化をやってみてください
    ワーカースレッドからWindowsコントロールのプロパティをいじりたいとき@ぎんゆぅ~さん

    もし,スレッド対応化が,わけわからないときは,ご連絡ください
    こっちの手の空いた時に,サンプルを書き換えてみますです♪

    お願いしますわん♥

  9. ちょっと立ち寄りました より:

    Form1_Load の先頭行で
    Form1.CheckForIllegalCrossThreadCalls = false;

    を呼んでみるとみため正常に動きます。


    もう一つはリストボックスをスレッドセーフにするため

    delegate void ListBoxDelegate(string text);
    internal void AddText(string text) {
    listBox1.Items.Add(text);
    }

    を追加して
    listBox1.Items.Add(st + ” , ” + e.FileName);
    この部分を以下のように変更する
    Invoke(new ListBoxDelegate(AddText), st + ” , ” + e.FileName);
    では、さようなら 😛

  10. くまさん より:

    >>ちょっと立ち寄りました さま

    おっ!
    何とか動いたみたいですね

    よかったよかった!!

    IPCなプロセス間通信
    スレッドセーフ化の対応が必要みたいなので,ご注意くださいませ!>後から来られる方♪

  11. 匿名 より:

    素晴らしいです。
    すごく参考に、というか勉強になりました。
    ありがとうございます!

  12. くまさん より:

    >>匿名 さま

    ありがとうございます

    古い技術になりつつありますが,このプロセス間通信,お手軽に使えるんで
    うちでもちょこちょこ利用してますです

    また何かありましたら,よろしくです

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください