プロセス間通信 プロセス間通信 (SendMessage) プロセス間通信とは 同一コンピューター上で起動して居るアプリケーション間でデータを受け渡し度い事は時々有る Framework には リモート処理 と謂う方法でデータの受け渡しを行なう方法が有る 此処では 此の方法では無く 従来の方法の API を使用したプロセス間通信を紹介する 此の方法は 送信側は API の SendMessage で送り 受信側は WndProc のメッセージループで受け取る事に成る 難しい事は余り無いのだが 文字列の送受信では構造体の COPYDATASTRUCT を使うので 此の処理が少々面倒で有る 送信側仕様 先ず相手のアプリケーション名を入力して 送るメッセージと送る数値を 2 個入力して 送信ボタンを押すと 相手にメッセージが投げられる物とする コードの説明宣言 API は全部で 3 個使用する 先ず相手の Window のハンドルを取得する FindWindow と 相手に数値を送る SendMessage と 文字列を送る SendMessage で有る SendMessage は 同じ名前の関数で有るが 引数の形が異なる 始めの関数は 引数として 1 番目に相手の Window のハンドルを 2 番目 3 番目に数値を持つ 一方 2 番目の SendMessage は 1 番目は同じで有るが 2 番目は 0 を 3 番目には COPYDATASTRUCT と謂う構造体を持つ COPYDATASTRUCT は 値渡しではなく 参照渡し (ref) なので 注意され度い -1-
Visual Basic ' COPYDATASTRUCT 構造体 Public Structure COPYDATASTRUCT Public dwdata As Int32 ' 送信するビット値 Public cbdata As Int32 ' lpdata のバイト数 Public lpdata As String ' 送信するデータへのポインタ (0 も可能 ) End Structure Public Const WM_COPYDATA As Int32 = &H4A Public Const WM_USER As Int32 = &H400 "user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _ Private Shared Function FindWindow( _ ByVal lpclassname As String, _ ByVal lpwindowname As String) As IntPtr End Function "user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _ Public Shared Function SendMessage( _ ByVal hwnd As IntPtr, _ ByVal wmsg As Int32, _ ByVal wparam As Int32, _ ByVal lparam As Int32) As Integer End Function "user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _ Public Shared Function SendMessage( _ ByVal hwnd As IntPtr, _ ByVal wmsg As Int32, _ ByVal wparam As Int32, _ ByRef lparam As COPYDATASTRUCT) As Integer End Function C# [DllImport("User32.dll", EntryPoint = "FindWindow")] public static extern Int32 FindWindow(String lpclassname, String lpwindowname); [DllImport("User32.dll", EntryPoint = "SendMessage")] public static extern Int32 SendMessage(Int32 hwnd, Int32 Msg, Int32 wparam, ref COPYDATASTRUCT lparam); [DllImport("User32.dll", EntryPoint = "SendMessage")] public static extern Int32 SendMessage(Int32 hwnd, Int32 Msg, Int32 wparam, Int32 lparam); public const Int32 WM_COPYDATA = 0x4A; public const Int32 WM_USER = 0x400; -2-
// COPYDATASTRUCT 構造体 public struct COPYDATASTRUCT public Int32 dwdata; // 送信する 32 ビット値 public Int32 cbdata; // lpdata のバイト数 public string lpdata; // 送信するデータへのポインタ (0 も可能 ) データの送信 Visual Basic ' 送信ボタン押下 Private Sub butsend_click(byval sender As System.Object, _ ByVal e As System.EventArgs) Handles butsend.click Dim result As Int32 = 0 ' 相手のウィンドウハンドルを取得する Dim hwnd As Int32 = FindWindow(Nothing, txtname.text) If hwnd = 0 Then ' ハンドルが取得出来なかった MessageBox.Show(" 相手 Window のハンドルが取得出来ません ") Return End If ' 文字列メッセージを送信する If txtmessage.text <> String.Empty Then ' 送信データを Byte 配列に格納 Dim bytearry() As Byte = System.Text.Encoding.Default.GetBytes(txtMessage.Text) Dim len As Int32 = bytearry.length Dim cds As COPYDATASTRUCT cds.dwdata = 0 ' 使用しない cds.lpdata = txtmessage.text ' テキストのポインターをセット cds.cbdata = len + 1 ' 長さをセット ' 文字列を送る result = SendMessage(hWnd, WM_COPYDATA, 0, cds) End If ' 数値メッセージを送信する If txtint1.text <> String.Empty And txtint2.text <> String.Empty Then Dim int1 As Int32 = 0 Dim int2 As Int32 = 0 Try ' 数値に正しく変換出来るか? int1 = CType(txtInt1.Text, Int32) int2 = CType(txtInt2.Text, Int32) Catch -3-
MessageBox.Show(" 入力された数値が正しく有りません ") Return End Try ' 数値を送る result = SendMessage(hWnd, WM_USER, int1, int2) End If End Sub C# // 送信ボタン押下 private void butsend_click(object sender, EventArgs e) Int32 result = 0; // 相手のウィンドウハンドルを取得する Int32 hwnd = FindWindow(null, txtname.text); if (hwnd == 0) // ハンドルが取得出来なかった MessageBox.Show(" 相手 Window のハンドルが取得出来ません "); return; // 文字列メッセージを送信する if (txtmessage.text!= string.empty) // 送信データを Byte 配列に格納 byte[] bytearry = System.Text.Encoding.Default.GetBytes(txtMessage.Text); Int32 len = bytearry.length; COPYDATASTRUCT cds; cds.dwdata = 0; // 使用しない cds.lpdata = txtmessage.text; // テキストのポインターをセット cds.cbdata = len + 1; // 長さをセット // 文字列を送る result = SendMessage(hWnd, WM_COPYDATA, 0, ref cds); // 数値メッセージを送信する if (txtint1.text!= string.empty && txtint2.text!= string.empty) Int32 int1 = 0; Int32 int2 = 0; try // 数値に正しく変換出来るか? int1 = int.parse(txtint1.text); int2 = int.parse(txtint2.text); -4-
catch MessageBox.Show(" 入力された数値が正しく有りません "); return; // 数値を送る result = SendMessage(hWnd, WM_USER, int1, int2); サンプルコード :sendmessagesendc.lzh sendmessagesendvb.lzh 受信側のコード 受信側のコードは簡単で有る.NET では 簡単に Form に送られて来るメッセージをフックする事が出来る 其れには Form クラスの WndProc メソッドを 自分のフォームでオーバーライドすれば良い 後はメッセージの種類に依り 数値データか 文字データかを判断して 数値データで有れば 其の儘 文字にして表示する 文字列の場合は WinProc には 引数と仕て System.Windows.Forms.Message 構造体が参照で渡されて来るので 此の参照データから Message 構造体が持つ GetLParam メソッドで LParam を取得し OPYDATASTRUCT でキャストして文字列を取り出す 仕様 フォームの構造は簡単で 送られたデータを表示する丈で有る Visual Basic Public Class FomGetMessage ' COPYDATASTRUCT 構造体 Public Structure COPYDATASTRUCT Public dwdata As IntPtr ' 送信するビット値 Public cbdata As Int32 ' lpdata のバイト数 Public lpdata As String ' 送信するデータへのポインタ (0 も可能 ) End Structure -5-
Public Const WM_COPYDATA As Int32 = &H4A Public Const WM_USER As Int32 = &H400 Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message) Select Case m.msg Case WM_USER ' 数値が送信されて来た txtint1.text = m.wparam.tostring() txtint2.text = m.lparam.tostring() Case WM_COPYDATA ' 文字が送信されて来た Dim mystr As COPYDATASTRUCT = New COPYDATASTRUCT() Dim mytype As Type = mystr.gettype() mystr = CType(m.GetLParam(mytype), COPYDATASTRUCT) txtmessage.text = mystr.lpdata End Select MyBase.WndProc(m) End Sub ' テキストボックスのクリア Private Sub butcls_click(byval sender As System.Object, _ ByVal e As System.EventArgs) Handles butcls.click txtmessage.text = String.Empty txtint1.text = String.Empty txtint2.text = String.Empty End Sub End Class C# using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; namespace getmessagec public partial class FomGetMessage : Form // COPYDATASTRUCT 構造体 public struct COPYDATASTRUCT public Int32 dwdata; // 送信する 32 ビット値 public Int32 cbdata; // lpdata のバイト数 public string lpdata; // 送信するデータへのポインタ (0 も可能 ) -6-
public const int WM_COPYDATA = 0x4A; public const int WM_USER = 0x400; public FomGetMessage() InitializeComponent(); protected override void WndProc(ref Message m) switch (m.msg) case WM_USER: // 数値が送信されて来た txtint1.text = m.wparam.tostring(); txtint2.text = m.lparam.tostring(); break; case WM_COPYDATA: // 文字が送信されて来た COPYDATASTRUCT mystr = new COPYDATASTRUCT(); Type mytype = mystr.gettype(); mystr = (COPYDATASTRUCT)m.GetLParam(mytype); txtmessage.text = mystr.lpdata ; break; base.wndproc(ref m); // テキストボックスのクリア private void butcls_click(object sender, EventArgs e) txtmessage.text = string.empty; txtint1.text = string.empty; txtint2.text = string.empty; サンプルコード :sendmessagegetc.lzh sendmessagegetvb.lzh -7-