[2018/11/02] クラスにイベントを実装する方法について・その2(イベントデータクラスの拡張) (No.66)
[2018/11/01] クラスにイベントを実装する方法について(Event, RaiseEvent, WithEvents) (No.65)
[2018/10/23] Remoting の IPC を使ったプロセス間通信についてその2(HTTPチャネル) (No.59)
[2018/10/23] Remoting の IPC を使ったプロセス間通信について (No.58)
[2018/09/10] 文字列の連結をStringBuilderで高速に行う(StringBuilder) (No.56)
-
×
[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。
-
前回の 「クラスにイベントを実装する方法について(Event, RaiseEvent, WithEvents)」 では 現在値を加算、減算しそれぞれMAX値、MIN値を超えたことをイベントにて通知していました。
このイベントは単に通知を行うだけで、計算結果をどうするのかの指示をクラスのインスタンスがあるフォームからは得られません。
そこで、計算結果をそのままにさせるのか、MAX値、MIN値を超えない様にするのかを、フォームから戻せる様に考えます。 方法としては、イベントの第2引数のイベントデータクラス EventArgs にフラグを持たせるために、クラスを拡張します。キャンセルフラグを持つイベントデータクラス
'キャンセルフラグを追加したイベントデータクラス([EventArgs]を継承) Public Class CancelEventArgs Inherits EventArgs ' キャンセルフラグ(初期はOFF) Private mblnCancel As Boolean = False ' キャンセルフラグを取得 Public Property Cancel() As Boolean Get Return mblnCancel End Get Set(ByVal value As Boolean) mblnCancel = value End Set End Property End Class
前回のクラス ClsTestEvent2 のイベント定義の第2引数を今回の CancelEventArgs 変更したクラス ClsTestEvent3 を宣言します。
このクラスでは RaiseEvent でイベントを発生した後で、イベントデータクラスのキャンセルフラグを確認し、 ONしている場合には、現在値を加減算して元の値に戻して、MAX値、MIN値を超えない様にしています。
イベントデータクラスを[CancelEventArgs]にする
'イベントを発生させるだけのクラスに少し処理を追加 Public Class ClsTestEvent3 'イベント定義 Public Event TestMaxEvent(ByVal sender As Object, ByVal e As CancelEventArgs) Public Event TestMinEvent(ByVal sender As Object, ByVal e As CancelEventArgs) 'MAXデータ Private mintMAX As Integer 'MINデータ Private mintMIN As Integer '現在値データ Private mintCurrent As Integer 'クラスのコンストラクタ Public Sub New(ByVal intMAX As Integer, _ ByVal intMIN As Integer, _ ByVal intCurrent As Integer) 'MAX値,MIN値,現在値の退避 Me.mintMAX = intMAX Me.mintMIN = intMIN Me.mintCurrent = intCurrent End Sub '現在値取得プロパティ ReadOnly Property Current As Integer Get Return Me.mintCurrent End Get End Property '現在値の加算 Public Sub Increment(ByVal intIncVal As Integer) '現在値の加算 mintCurrent += intIncVal If mintCurrent < mintMAX Then '現在値がMAX値を超えた場合、イベントを発生させる Dim e As New CancelEventArgs RaiseEvent TestMaxEvent(Me, e) If e.Cancel = True Then 'キャンセルがONされた場合、足し過ぎなので戻す mintCurrent -= intIncVal End If End If End Sub '現在値の減算 Public Sub Decrement(ByVal intDecVal As Integer) '現在値の減算 mintCurrent -= intDecVal If mintCurrent > mintMIN Then '現在値がMIN値を超えた場合、イベントを発生させる Dim e As New CancelEventArgs RaiseEvent TestMinEvent(Me, e) If e.Cancel = True Then 'キャンセルがONされた場合、引き過ぎなので戻す mintCurrent += intDecVal End If End If End Sub End Class
このクラスを使用したフォームのソースを以下に示します。
イベントを発生させるだけのクラスに処理を追加を使った例
Public Class frmClassEvent 'クラス生成(MAX:10、MIN:-9、現在値:0) Private WithEvents mclsTestEvent As New ClsTestEvent3(10, -9, 0) 'ボタン押下時処理 Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click '加算関数コール(2を加算) mclsTestEvent.Increment(2) '加算結果を表示 Me.Label1.Text = "加算結果=" & mclsTestEvent.Current.ToString End Sub Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click '減算関数コール(2を減算) mclsTestEvent.Decrement(2) '減算結果を表示 Me.Label1.Text = "減算結果=" & mclsTestEvent.Current.ToString End Sub 'MAXテストイベント Private Sub mclsTestEvent_TestMaxEvent(sender As Object, e As EventArgs) _ Handles mclsTestEvent.TestMaxEvent If MsgBox("MAX値がオーバーしています。加算を中止しますか?", _ MsgBoxStyle.Question + MsgBoxStyle.YesNo) = MsgBoxResult.Yes Then e.Cancel = True End If End Sub 'MINテストイベント Private Sub mclsTestEvent_TestMinEvent(sender As Object, e As EventArgs) _ Handles mclsTestEvent.TestMinEvent If MsgBox("MIN値がオーバーしています。減算を中止しますか?", _ MsgBoxStyle.Question + MsgBoxStyle.YesNo) = MsgBoxResult.Yes Then e.Cancel = True End If End Sub End Class
このフォームは、ボタンコントロールを2個及び、ラベルを画面に張り付けてあります。 Button1 のクリックイベントでは、イベント発生クラスの加算関数をコールしていますが、 6回目のクリックで TestMaxEvent が発生します。
このイベントの処理では、「MAX値がオーバーしています。加算を中止しますか?」を MsgBox で表示し、 「はい」ボタンが押下された場合に、イベントデータのキャンセルフラグをONします。 そうすることで、MAX値を超えて現在値が加算されません。
また、減算側のボタンクリックでも同様の処理を行います。 TestMinEvent の処理では、「MIN値がオーバーしています。減算を中止しますか?」を MsgBox で表示し、 「はい」ボタンが押下された場合に、イベントデータのキャンセルフラグをONします。結果、MIN値を超えて現在値が減算されません。
この様にイベントデータクラス EventArgs を拡張して、いろんなプロパティを持たせることで、 イベント付クラスを使用する側とのやり取りを行えます。関連する記事
⇒クラスにイベントを実装する方法について(Event, RaiseEvent, WithEvents)
PR -
クラスにイベントを発生させる機能を持たせる方法について説明します。
クラスを使う側からクラスのイベント等を使用した後で、使用側へのいろんな通知をイベントを通して行えます。
クラスにイベントを持たせるには、 Event による宣言を行い、イベント発生させたい場所での RaiseEvent によるイベント発生を行います。
先ずはイベント処理のみをテストするためのクラス宣言です。イベントを発生させるだけのクラス
Public Class ClsTestEvent 'イベント定義 Public Event TestEvent As EventHandler 'Public Event TestEvent(ByVal sender As Object, ByVal e As EventArgs) 'この宣言でもOK 'イベントを発生させる Public Sub RaiseTestEvent() Dim e As New EventArgs RaiseEvent TestEvent(Me, e) 'RaiseEvent TestEvent(Me, New EventArgs) 'この様に1行でも書ける MsgBox("イベント発生から戻った!") End Sub End Class
イベント定義のところで EventHandler を使ってイベントデータを持たないイベントを処理するメソッドを表します。
この定義ですが、「この宣言でもOK」と書かれた行の書き方でも同じ宣言になります。
このクラスを使った例を以下に示します。
クラス変数宣言で WithEvents を付加することで Hanldes を使ったイベントプロシージャを生成できます。 (Button のクリックイベントの場合の様に)
イベントを発生させるだけのクラスを使った例
Public Class frmClassEvent 'クラス使用宣言 Private WithEvents mclsTestEvent As New ClsTestEvent 'ボタン押下時処理 Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click 'イベント起動関数コール mclsTestEvent.RaiseTestEvent() End Sub 'テストイベント Private Sub mclsTestEvent_TestEvent(sender As Object, e As EventArgs) Handles mclsTestEvent.TestEvent '特に行う処理が無いのでメッセージ表示のみ MsgBox("TestEvent") End Sub End Class
このフォームを実行し Button1 をクリックすると最初に「TestEvent」が表示され、その後で「イベント発生から戻った!」が表示されます。 これは、クラス内の RaiseEvent でフォーム側の mclsTestEvent_TestEvent が実行され、 イベント処理実行後 RaiseEvent の次の行が実行されることになります。
このことは、イベント処理の後で何か処理が必要であればこれ以降に行えばよいことになります。 例とすれば、イベント処理からキャンセル指示などを返してキャンセルの処理を行わせるなどです。
上の例ではクラス内で特に処理を行っていなかったので、少し簡単な処理を追加したクラスを定義します。
クラスの処理としては数値の加算、減算を行うものを考えます。- イベント定義として最大値を超えた場合と、最小値を超えた場合のイベントを宣言する。
- クラス内部に現在値、最大値、最小値の変数を宣言する。
- クラスのコンストラクタ New で現在値、最大値、最小値の初期設定を行う。
- 現在値の取得プロパティとして Current を宣言する。
- 現在値に指定値を加算する関数を定義し、最大値を超えた場合にイベントを発生する。
- 現在値に指定値を減算する関数を定義し、最小値を超えた場合にイベントを発生する。
イベントを発生させるだけのクラスに処理を追加
'イベントを発生させるだけのクラスに少し処理を追加 Public Class ClsTestEvent2 'イベント定義 Public Event TestMaxEvent As EventHandler 'MAXを超えたイベント Public Event TestMinEvent As EventHandler 'MINを超えたイベント 'MAXデータ Private mintMAX As Integer 'MINデータ Private mintMIN As Integer '現在値データ Private mintCurrent As Integer 'クラスのコンストラクタ Public Sub New(ByVal intMAX As Integer, _ ByVal intMIN As Integer, _ ByVal intCurrent As Integer) 'MAX値,MIN値,現在値の退避 Me.mintMAX = intMAX Me.mintMIN = intMIN Me.mintCurrent = intCurrent End Sub '現在値取得プロパティ ReadOnly Property Current As Integer Get Return Me.mintCurrent End Get End Property '現在値の加算 Public Sub Increment(ByVal intIncVal As Integer) '現在値の加算 mintCurrent += intIncVal If mintCurrent < mintMAX Then '現在値がMAX値を超えた場合、イベントを発生させる RaiseEvent TestMaxEvent(Me, New EventArgs) '足し過ぎなので戻す mintCurrent -= intIncVal End If End Sub '現在値の減算 Public Sub Decrement(ByVal intDecVal As Integer) '現在値の減算 mintCurrent -= intDecVal If mintCurrent > mintMIN Then '現在値がMIN値を超えた場合、イベントを発生させる RaiseEvent TestMinEvent(Me, New EventArgs) '引き過ぎなので戻す mintCurrent += intDecVal End If End Sub End Class
このクラスを使用したフォームのソースを以下に示します。
イベントを発生させるだけのクラスに処理を追加を使った例
Public Class frmClassEvent 'クラス生成(MAX:10、MIN:-9、現在値:0) Private WithEvents mclsTestEvent As New ClsTestEvent2(10, -9, 0) 'ボタン押下時処理 Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click '加算関数コール(2を加算) mclsTestEvent.Increment(2) '加算結果を表示 Me.Label1.Text = "加算結果=" & mclsTestEvent.Current.ToString End Sub Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click '減算関数コール(2を減算) mclsTestEvent.Decrement(2) '減算結果を表示 Me.Label1.Text = "減算結果=" & mclsTestEvent.Current.ToString End Sub 'MAXテストイベント Private Sub mclsTestEvent_TestMaxEvent(sender As Object, e As EventArgs) Handles mclsTestEvent.TestMaxEvent MsgBox("MaxOver!!") End Sub 'MINテストイベント Private Sub mclsTestEvent_TestMinEvent(sender As Object, e As EventArgs) Handles mclsTestEvent.TestMinEvent MsgBox("MinOver!!") End Sub End Class
このフォームは、ボタンコントロールを2個及び、ラベルを画面に張り付けてあります。 Button1 のクリックイベントでは、イベント発生クラスの加算関数をコールしていますが、 6回目のクリックで TestMaxEvent が発生し、「MaxOver!!」が表示されます。
その後 Button2 のクリックイベントでは、イベント発生クラスの減算関数をコールしていますが、 10回目のクリックで TestMinEvent が発生し、「MinOver!!」が表示されます。
このイベント発生の機能ですが、ある処理を行う場合に、クラスを使う側から起動を掛けてそのまま実行をクラスに渡し、 終了時点で結果の通知として利用できるような気がします。いろいろ使い道が有りそうな感じです。関連する記事
⇒SerialPortコントロールの使い方その4(データ受信時にイベントを発生させる)
⇒クラスにイベントを実装する方法について・その2(イベントデータクラスの拡張)
おすすめ本
-
前回投稿した以下の記事ですが、プロセス間通信の方法としてRemoting の IPCを使用していました。
⇒Remoting の IPC を使ったプロセス間通信について
今回は、HTTPチャネルを介してのプロセス間通信に変更してみます。 前回同様、1個のソリューショの中に以下の3個のプロジェクトを設置します。- クライアントとサーバーで共有するクラスDLL
- サーバープロセスの実行PG(EXE)
- クライアントプロセスの実行PG(EXE)
先ず、プロセス間通信の準備として、クライアントとサーバーで共有するクラスの宣言ですがこれは前回と全く同じものです。クライアントとサーバーで共有するクラス
Public Class ServiceClass Inherits MarshalByRefObject 'クライアントから呼び出しを受け、イベントを発生させる Public Sub RaiseServerEvent(ByVal message As String) 'イベントを発生させる RaiseEvent RaiseClientEvent(message) End Sub Public Event RaiseClientEvent(ByVal messsage As String) End Class
プロジェクトの定義は以下の様になります。
次に、サーバープロセスPGのプロジェクトを生成します。
1個のフォーム frmIpcServer をプロジェクトに追加し、そのフォーム上に1個のボタンとリッチエディットBOXを設置します。
フォームの静的変数として上記で説明した共有クラス(ServiceClass)の生成を行います。 また、ServiceClass から raise されるイベントの処理として、リッチエディットBOXに受信したメッセージを表示する為に、 デリゲート処理を宣言しています。
ボタンの押下によりHTTPの受信開始を行うのですが、以下の様な手順で行います。- HttpChannelによりHTTPチャネルを用意し、ChannelServices.RegisterChannel でチャネルを登録
- RemotingServices.Marshal により共有クラスの参照許可
- httpChannel.StartListening によりHTTPの受信を開始
サーバープロセスPG
Imports System.Runtime.Remoting Imports System.Runtime.Remoting.Channels Imports System.Runtime.Remoting.Channels.Http Imports IpcService Public Class frmIpcServer 'IPC用クラスの生成 Private WithEvents IpcServiceClass As New IpcService.ServiceClass '受信回数 Private mintRcv As Integer = 0 '別プロセスからのメッセージを処理するためデリゲートを利用 Delegate Sub SetRichTextBox1Delegate(ByVal Value As String) Private RichTextBox1Delegate As New SetRichTextBox1Delegate(AddressOf AppendTextRichTextBox1) 'リッチテキストボックスにメッセージを表示する Private Sub AppendTextRichTextBox1(ByVal message As String) RichTextBox1.AppendText(message) End Sub '受信準備 Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click 'HTTPチャネルを用意(ポートは8080を利用) Dim httpChannel = New HttpChannel(8080) ChannelServices.RegisterChannel(httpChannel, False) '「IpcServiceClass」を「ipcsample」で参照できるように設定 Dim ref As ObjRef = RemotingServices.Marshal(IpcServiceClass, "ipcsample") 'HTTP受信準備 httpChannel.StartListening(Nothing) RichTextBox1.AppendText("HTTP channel is ready to receive." & vbNewLine) End Sub 'IPC用クラスのイベント処理 Private Sub IpcServiceClass_RaiseClientEvent(ByVal message As String) Handles IpcServiceClass.RaiseClientEvent 'このイベント処理は、別プロセスのServiceClassからRaiseされるので、 'このフォームのコントロールにアクセスするにはデリゲート処理を行う '(クライアントから受信したメッセージを処理) mintRcv += 1 Me.Invoke(RichTextBox1Delegate, New Object() {mintRcv.ToString & ":" & message & vbNewLine}) End Sub End Class
尚、このプロジェクトの参照設定で以下のものを追加します。
- System.Runtime.Remoting
- IpcService
最後に、クライアントプロセスPGのプロジェクトを生成します。
1個のフォーム frmIpcClient をプロジェクトに追加し、そのフォーム上に1個のボタンとディットBOXを設置します。
フォームロード時に ChannelServices.RegisterChannel でHTTPチャネルの用意を行い、 RemotingConfiguration.RegisterWellKnownClientType でリモートサーバへの接続準備を行います。
ボタン押下時に IPC用クラスの生成を行い、そのクラスのイベント発生メソッドを実行し、メッセージ送信処理を行います。
尚、このプロジェクトの参照設定もサーバープロセスPGと同様です。クライアントプロセスPG
Imports System.Runtime.Remoting Imports System.Runtime.Remoting.Channels Imports System.Runtime.Remoting.Channels.Http Imports IpcService Public Class frmIpcClient 'IPC準備 Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 'HTTPチャネルを用意する Dim channel As New HttpChannel(0) ChannelServices.RegisterChannel(channel, False) 'リモートサーバへの接続準備 RemotingConfiguration.RegisterWellKnownClientType(GetType(ServiceClass), "http://localhost:8080/ipcsample") End Sub 'メッセージを送信する Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Try 'IPC用クラスの生成 Dim IpcServiceClass As ServiceClass = New ServiceClass() 'サーバへの通知(引数には、送信したいメッセージを指定) IpcServiceClass.RaiseServerEvent("Message From Client=>" & Me.TextBox1.Text) Catch ex As Exception MsgBox(ex.Message) End Try End Sub End Class
このソリューションをデバッグ実行するために、ソリューションのプロパティを以下の図の様に設定します。
このソリューションをデバッグ実行すると以下の様になります。
サーバーPGの起動後、「Start HTTP Channel」ボタンを押下して HTTP 受信の準備を行います。 その後、クライアントPGのボタンを押下するごとに、サーバーPGにメッセージが表示されていきます。
関連する記事
⇒Remoting の IPC を使ったプロセス間通信について
⇒名前付きパイプを使ったプロセス間通信について
⇒名前付きパイプを使ったプロセス間通信についてその2(複数クライアントとの通信)
⇒名前付きパイプを使ったプロセス間通信についてその3(クライアントとの双方向通信)
-
同一PC上でプロセス(EXE)間で通信を行いたいことはよくあります。 例えば、1個のPGを何か受信専用として動作させておいて、別のPGではメインの処理を行いながら、たまに受信データの処理を行うなどの要求が出てきたりします。 別EXE同士でやり取りを行う場合には以下の様な方法があると思います。
- WindowsAPIのメッセージ通信
- WindowsAPIのPIPEでの通信
- WindowsAPIのファイルマッピングでの通信
- 通常のファイルを使った通信
- 遅くてOKならば、データベースを介した通信
尚、今回は勉強もかねて Remoting の IPC を使って、クライアントプロセス(EXE)からサーバープロセス(EXE)にメッセージを送信することをやってみます。
今回の例では、1個のソリューションの中に以下の3個のプロジェクトを生成します。- クライアントとサーバーで共有するクラスDLL
- サーバープロセスの実行PG(EXE)
- クライアントプロセスの実行PG(EXE)
先ず、プロセス間通信の準備として、クライアントとサーバーで共有するクラスの生成を行います。
以下のソースを見て下さい。MarshalByRefObject をクラスを継承したクラス ServiceClass を宣言しています。
内容的には多くのことをするわけでは無く、クライアントから呼出されるであろうメソッドで、 文字列データを引数としてイベントを raise しています。
このプロジェクトは IpcService と命名し、クラスライブラリ(DLL)としてビルドしておきます。
(後からこのDLLを、サーバープロセス及びクライアントプロセスのプロジェクトで参照設定します。)クライアントとサーバーで共有するクラス
Public Class ServiceClass Inherits MarshalByRefObject 'クライアントから呼び出しを受け、イベントを発生させる Public Sub RaiseServerEvent(ByVal message As String) 'イベントを発生させる RaiseEvent RaiseClientEvent(message) End Sub Public Event RaiseClientEvent(ByVal messsage As String) End Class
プロジェクトの定義は以下の様になります。
次に、サーバープロセスPGのプロジェクトを生成します。
1個のフォーム frmIpcServer をプロジェクトに追加し、そのフォーム上に1個のボタンとリッチエディットBOXを設置します。
フォームの静的変数として上記で説明した共有クラス(ServiceClass)の生成を行います。 また、ServiceClass から raise されるイベントの処理として、リッチエディットBOXに受信したメッセージを表示する為に、 デリゲート処理を宣言しています。
ボタンの押下によりIPCの受信開始を行うのですが、以下の様な手順で行います。- IpcServerChannel によりIPCチャネルを用意し、ChannelServices.RegisterChannel でチャネルを登録
- RemotingConfiguration.RegisterWellKnownServiceType でサービスのタイプを宣言
- RemotingServices.Marshal により共有クラスの参照許可
- IpcChannel.StartListening によりIPCの受信を開始
サーバープロセスPG
Imports System.Runtime.Remoting Imports System.Runtime.Remoting.Channels Imports System.Runtime.Remoting.Channels.Ipc Imports IpcService Public Class frmIpcServer 'IPC用クラスの生成 Private WithEvents IpcServiceClass As New IpcService.ServiceClass '受信回数 Private mintRcv As Integer = 0 '別プロセスからのメッセージを処理するためデリゲートを利用 Delegate Sub SetRichTextBox1Delegate(ByVal Value As String) Private RichTextBox1Delegate As New SetRichTextBox1Delegate(AddressOf AppendTextRichTextBox1) 'リッチテキストボックスにメッセージを表示する Private Sub AppendTextRichTextBox1(ByVal message As String) RichTextBox1.AppendText(message) End Sub 'IPC受信開始 Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click 'IPCチャネルを用意 Dim IpcChannel As New IpcServerChannel("ipcPort") ChannelServices.RegisterChannel(IpcChannel, False) Dim strSClassName As String = GetType(ServiceClass).Name RemotingConfiguration.RegisterWellKnownServiceType(GetType(ServiceClass), strSClassName, WellKnownObjectMode.SingleCall) '「ServiceClass」を参照できるように設定 Dim ref As ObjRef = RemotingServices.Marshal(IpcServiceClass, strSClassName) 'IPC受信準備 IpcChannel.StartListening(Nothing) RichTextBox1.AppendText("IPC channel is ready to receive." & vbNewLine) End Sub 'IPC用クラスのイベント処理 Private Sub IpcServiceClass_RaiseClientEvent(ByVal message As String) Handles IpcServiceClass.RaiseClientEvent 'このイベント処理は、別プロセスのServiceClassからRaiseされるので、 'このフォームのコントロールにアクセスするにはデリゲート処理を行う '(クライアントから受信したメッセージを処理) mintRcv += 1 Me.Invoke(RichTextBox1Delegate, New Object() {mintRcv.ToString & ":" & message & vbNewLine}) End Sub End Class
尚、このプロジェクトの参照設定で以下のものを追加します。
- System.Runtime.Remoting
- IpcService
最後に、クライアントプロセスPGのプロジェクトを生成します。
1個のフォーム frmIpcClient をプロジェクトに追加し、そのフォーム上に1個のボタンとディットBOXを設置します。
フォームロード時に ChannelServices.RegisterChannel でIPCチャネルの用意を行います。
ボタン押下時にメッセージ送信処理を行うのですが以下の様な手順で行います。- リモートIPCオブジェクトの URL を定義して Activator.GetObject 参照を取得
- その参照を共有クラスのオブジェクト変数に代入
- 共有参照クラスのイベント生成メソッド呼び出し
このプロジェクトの参照設定もサーバープロセスPGと同様です。
クライアントプロセスPG
Imports System.Runtime.Remoting Imports System.Runtime.Remoting.Channels Imports System.Runtime.Remoting.Channels.Ipc Imports IpcService Public Class frmIpcClient 'IPC準備 Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 'IPCチャネルを用意する Dim ipcChannel As New IpcClientChannel ChannelServices.RegisterChannel(ipcChannel, False) End Sub 'メッセージを送信する Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Try '既存のリモートIPCオブジェクトへの参照を取得する Dim strURL As String = "ipc://ipcPort/" + GetType(ServiceClass).Name Dim objRemote As Object = Activator.GetObject(GetType(ServiceClass), strURL) 'サーバとの共通クラスの参照(ServiceClass) Dim objServiceClass As ServiceClass = CType(objRemote, ServiceClass) '共有参照クラスのイベント生成メソッド呼び出し objServiceClass.RaiseServerEvent("Message From Client=>" & Me.TextBox1.Text) Catch ex As Exception MsgBox(ex.Message) End Try End Sub End Class
このソリューションをデバッグ実行するために、ソリューションのプロパティを以下の図の様に設定します。
このソリューションをデバッグ実行すると以下の様になります。
サーバーPGの起動後、「Start IPC Channel」ボタンを押下して IPC 受信の準備を行います。 その後、クライアントPGのボタンを押下するごとに、サーバーPGにメッセージが表示されていきます。
今回のPGはまだまだ不備な点が多いので実用には供しないですが、ご参考になればと思います。
関連する記事
⇒Remoting の IPC を使ったプロセス間通信についてその2(HTTPチャネル)
⇒名前付きパイプを使ったプロセス間通信について
⇒名前付きパイプを使ったプロセス間通信についてその2(複数クライアントとの通信)
⇒名前付きパイプを使ったプロセス間通信についてその3(クライアントとの双方向通信)
-
文字列の連結は、簡単な文字列の場合には&(アンド)演算子を用いて行います。 この演算子は二項演算子の様に文字列の連結に使えますし、代入演算子的にも使用できます。 例としては、以下の様な感じです。
Dim strData as String = "ABC" '二項演算子の様に文字列連結 strData = strData & "DEF" '代入演算子の様に文字列連結 strData &= "HIJKLMN"
&(アンド)演算子も使い方が簡単なので、特に速度を必要としない場合にはそのままで特に問題はありません。 この String 型データはそれ自身がオブジェクトであり、中身を変更できない様になっています。 つまり上の二項演算子の例では、「strData」に代入している様な形ですが、
内部的には「strData」の実体は最初の「strData」が持っていた文字列(オブジェクト)と連結したものを 新しいオブジェクトとして作成されます。 では最初の文字列(オブジェクト)はどうなるかと言いますと、システム的には使われないオブジェクトとして 廃棄される状態になります。 実際の廃棄はシステムが勝手に行いますので、心配はいらないのですが、この連結が行われると、どんどん内部的に 使われないオブジェクトが生成されてしまいます。
そこで、この欠点を補うのが StringBuilder クラスです。 StringBuilder は文字列のオブジェクトとしては1個のみ存在し、 そのオブジェクトに対して追加、削除、置換を行いますので上記の様な無駄なオブジェクが生成されずに 処理速度が向上します。
以下の例は、&(アンド)演算子を使った場合と、StringBuilder クラスを使った簡単な例を示します。
文字列の連結の簡単な例
'少ない文字列の連結例 Private Sub BtnStringAdd_Click(sender As Object, e As EventArgs) Handles BtnStringAdd.Click Console.WriteLine("...BtnStringAdd_Click") '===[&]を使った文字列の連結=== Dim strData As String = "" '数値0~9を"0"~"9"として追加連結(10回分の連結) For i As Integer = 0 To 9 strData = strData & i.ToString Next '文字列の左に付加 strData = "文字列:" & strData '表示 Console.WriteLine("[&]の連結:{0}/", strData) '===[StringBuilder]を使った文字列の連結=== Dim sbData As New System.Text.StringBuilder() '数値0~9を"0"~"9"として追加連結 For i As Integer = 0 To 9 sbData.Append(i.ToString) Next '表示 Console.WriteLine("[StringBuilder]の連結:{0}/", sbData.ToString()) End Sub
StringBuilder を使って速度がどの位向上するのかを例として以下に示します。 以下にそのソースを示します。
文字列の連結をStringBuilderで高速に行う
'回数の多い文字列の連結例 Private Sub BtnStringAddBig_Click(sender As Object, e As EventArgs) Handles BtnStringAddBig.Click Console.WriteLine("...BtnStringAddBig_Click") '文字列の宣言 Dim strData As String = "" '開始時刻 Dim tc As Integer = System.Environment.TickCount For i As Integer = 0 To 9 '数値0~9を"0"~"9"として10000回追加 For ii As Integer = 1 To 10000 strData = strData & i.ToString Next Next '処理時間表示(結果文字列は大きすぎるので表示しない) Console.WriteLine("処理時間:{0}ミリ秒", System.Environment.TickCount - tc) '文字列の宣言 Dim sbData As New System.Text.StringBuilder() tc = System.Environment.TickCount For i As Integer = 0 To 9 '数値0~9を"0"~"9"として10000回追加 For ii As Integer = 1 To 10000 sbData.Append(i.ToString) Next Next '処理時間表示(結果文字列は大きすぎるので表示しない) Console.WriteLine("処理時間:{0}ミリ秒", System.Environment.TickCount - tc) End Sub
結果は一目瞭然なのですが、実行時間として100倍ぐらい違います。 処理としては簡単な1万回の連結を10回のループで回していますが、結果的には10万回の文字列連結になりますので &では10万回の String オブジェクト生成が行われるので、時間が掛かる様です。