プロセス間通信(IPC)の方法の1つとして、
SendMessage(センドメッセージ)とPostMessage(ポストメッセージ)があります。
この2つについて、話していきましょう。
プロセス間通信(IPC)とは
プロセス間通信(Interprocess Communication) 略して、IPCです。
複数のプロセスがデータをやりとりする仕組みの事をプロセス間通信と言います。
パソコン内でアプリ間が会話する為の方法だと思ってください。
プロセス間通信の技法は上記のような方法があります。
先日行ったソケット(Socket)もプロセス間通信の1つです。
今回は、メッセージを使いたいと思います。
SendMessageとPostMessageについて
今回使うSendMessageとPostMessageは、フォーム間でやり取りをします。
フォームとフォームが送受信を行う仕組みです。
どんな時に使うかというと、アプリAとアプリBがあったとします。
アプリAのボタンが押された時に、押された事をアプリBに教える時に使います。
これだと、使い道無くない??って思う人がいるかもしれませんが、
確かにそんなに使うことはありませんwww
ただ、会社内で部署が分かれており、各々の部署でアプリを作られている時、
メッセージを貰えたら、処理できる仕組みを作っていれば、
各々の部署のアプリの変更は、メッセージを送ってもらう事のみで済みます。
SendMessageとPostMessageの違い
大きな違いは、非同期処理か同期処理かの違いです。
SendMessageは、送信後、送信相手の処理が終わるまで、次の処理にいきません。
PostMessageは、送信後、次の処理に行きます。その為、受信相手と同期処理になります。
メリット/デメリットはありますが、用途に合わせて使いましょう。
SendMessageとPostMessage ソフト作成(GUI)
【Send】ボタンではSendMessageを使い、
テキストボックスに入力されている文字列を送信します。
【Post】ボタンではPostMessageを使い、
テキストボックスに入力されている文字列を送信します。
SendMessageとPostMessage ソフト作成(DLLImport)
SendMessage/PostMessageでは、『User32.dll』の中の関数を使います。
using System.Runtime.InteropServices; //DLLImportを使うために namespace ProcessConnect { public partial class frmSend : Form { //ウィンドウを探す用のメソッド [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); //送信するためのメソッド(数値) [DllImport("User32.dll", EntryPoint = "PostMessage")] public static extern Int32 PostMessage(Int32 hWnd, Int32 Msg, Int32 wParam, ref COPYDATASTRUCT lParam); //送信するためのメソッド(文字も可能) [DllImport("User32.dll", EntryPoint = "PostMessage")] public static extern Int32 PostMessage(Int32 hWnd, Int32 Msg, Int32 wParam, Int32 lParam); //文字列を送信する時に使う構造体 public struct COPYDATASTRUCT { public IntPtr dwData; //送信する32ビット値 public int cbData; //lpDataのバイト数 public string lpData; //送信するデータへのポインタ(0も可能) }
構造体は送信側、受信側両方に必要になります。
DLLImportは送信側だけに必要です。
SendMessageとPostMessage ソフト作成(送信部)
流れとしては、フォームのウィンドウハンドルを取得します。
次に、テキストボックスの入力値が【数値】であるか確認して、
数値の場合は、数値を送信し、文字列の場合は、構造体を送信します。
【Send】ボタンの処理です。
private void btnSend_Click(object sender, EventArgs e)
{
int hWnd = FindWindow(null, "受信フォーム");
if (hWnd == 0)
{
//ハンドルが取得できなかった
MessageBox.Show("相手Windowのハンドルが取得できません");
return;
}
if (int.TryParse(txtMessage.Text,out int mes))
{
//数値を送信
int result = SendMessage(hWnd, SMSG_NUM, mes, mes * 2);
}
else
{
//文字として送信
COPYDATASTRUCT cds = new COPYDATASTRUCT();
cds.dwData = (IntPtr)0;
cds.lpData = txtMessage.Text;
cds.cbData = cds.lpData.Length + 1; //長さをセット
//文字列を送る
int result = SendMessage(hWnd, SMSG_STR, 0, ref cds);
}
}
【Post】ボタンの処理です。
private void btnPost_Click(object sender, EventArgs e)
{
int hWnd = FindWindow(null, "受信フォーム");
if (hWnd == 0)
{
//ハンドルが取得できなかった
MessageBox.Show("相手Windowのハンドルが取得できません");
return;
}
if (int.TryParse(txtMessage.Text, out int mes))
{
//数値を送信
int result = PostMessage(hWnd, PMSG_NUM, mes, mes * 2);
}
else
{
//文字として送信
PstMes_T = new COPYDATASTRUCT(); ;
PstMes_T.dwData = (IntPtr)0;
PstMes_T.lpData = txtMessage.Text;
PstMes_T.cbData = PstMes_T.lpData.Length + 1; //長さをセット
//文字列を送る
int result = PostMessage(hWnd, PMSG_STR, 0, ref PstMes_T);
}
}
これで送信部の完成です。
SendMessageとPostMessage ソフト作成(受信部)
次に受信部を作っていきます。
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case SMSG_NUM:
case PMSG_NUM:
//数値が送信されて来た
string typ = (m.Msg == SMSG_NUM) ? "SendMesNum" : "PostMesNum";
txtRecieve.Text = "["+ typ + "] " + (m.WParam + "-" + m.LParam);
break;
case SMSG_STR:
case PMSG_STR:
//文字が送信されて来た
typ = (m.Msg == SMSG_STR) ? "SendMesStr" : "PostMesStr";
COPYDATASTRUCT mystr = new COPYDATASTRUCT();
Type mytype = mystr.GetType();
mystr = (COPYDATASTRUCT)m.GetLParam(mytype);
txtRecieve.Text = "["+ typ + "] " + (mystr.lpData);
break;
}
base.WndProc(ref m);
}
ウィンドウプロシージャをオーバーライドします。
メッセージの番号に応じて、処理を分けます。
public const Int32 SMSG_NUM = 9999;
public const Int32 SMSG_STR = 9990;
public const Int32 PMSG_NUM = 8888;
public const Int32 PMSG_STR = 8880;
上記定義したメッセージ番号を受信したときに、受信内容を表示するように作りました。
まとめ
各パタンで実行してみました。
文字列をポストメッセージで送る事ができませんでした。
原因が分からず、できる方法を調べてみたいと思います。
ちなみに1度メッセージを送信で切れていれば、例外は発生しませんが、
最初から文字列のPostMessageを送信した場合は、例外が発生します。
構造体の定義を変更すれば、解決するような気がします。
解決した時にまたアップしたいと思います。
業務でプログラミング(C#/VB/Python)を作っている。
挫折を何回も繰り返し、幾度の壁を乗り越えてきた。
乗り越えてきた事を忘れないように記録に残す。
同じ思いをしている人への情報提供になれたらと思う。
基本は初心者に向けたプログラムの情報を提供する。
コメント