- 何かしら情報を受信しないと終わらない
- すべての受信が終わるまで、受信メッセージを取得する方法が無い
という問題がありました。そこで
- 待機ループし、終了フラグを監視する
- イベントを発行する機構を実装する
- IDisposableをインプリメント
することにしました。
以下、メールスロットを送受信するクラスです。
/// <summary>
/// メールスロットの操作を行います。
/// </summary>
public class MailSlot : IDisposable
{
#region Win32 API宣言
[DllImport("kernel32.dll")]
static extern SafeFileHandle CreateMailslot(
string lpName, //メールスロット名
uint nMaxMessageSize, //最大メッセージサイズ
uint lReadTimeout, //み取りタイムアウトの間隔
IntPtr lpSecurityAttributes); //継承オプション
[DllImport("kernel32.dll")]
static extern bool GetMailslotInfo(
SafeFileHandle hMailslot, //メールスロットのハンドル
ref uint lpMaxMessageSize, //最大メッセージサイズ
ref uint lpNextSize, //次のメッセージのサイズ
ref uint lpMessageCount, //メッセージ数
ref uint lpReadTimeout); //読み取りタイムアウトの間隔
[DllImport("kernel32.dll")]
static extern bool SetMailslotInfo(
SafeFileHandle hMailslot, //メールスロットのハンドル
uint lReadTimeout); //読み取りタイムアウトの間隔
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool CloseHandle(SafeFileHandle hMailslot);
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
private static extern SafeFileHandle CreateFile(
string lpFileName, // ファイル名
DesiredAccess dwDesiredAccess, // アクセスモード
ShareMode dwShareMode, // 共有モード
int lpSecurityAttributes, // セキュリティ記述子
CreationDisposition dwCreationDisposition, // 作成方法
FlagsAndAttributes dwFlagsAndAttributes, // ファイル属性
IntPtr hTemplateFile); // テンプレートファイルのハンドル
#endregion
#region 列挙体
private enum DesiredAccess : uint
{
GENERIC_READ = 0x80000000,
GENERIC_WRITE = 0x40000000,
GENERIC_EXECUTE = 0x20000000
}
private enum ShareMode : uint
{
FILE_SHARE_READ = 0x00000001,
FILE_SHARE_WRITE = 0x00000002,
FILE_SHARE_DELETE = 0x00000004
}
private enum CreationDisposition : uint
{
CREATE_NEW = 1,
CREATE_ALWAYS = 2,
OPEN_EXISTING = 3,
OPEN_ALWAYS = 4,
TRUNCATE_EXISTING = 5
}
private enum FlagsAndAttributes : uint
{
FILE_ATTRIBUTE_ARCHIVE = 0x00000020,
FILE_ATTRIBUTE_ENCRYPTED = 0x00004000,
FILE_ATTRIBUTE_HIDDEN = 0x00000002,
FILE_ATTRIBUTE_NORMAL = 0x00000080,
FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x00002000,
FILE_ATTRIBUTE_OFFLINE = 0x00001000,
FILE_ATTRIBUTE_READONLY = 0x00000001,
FILE_ATTRIBUTE_SYSTEM = 0x00000004,
FILE_ATTRIBUTE_TEMPORARY = 0x00000100
}
private enum MailSlotStatus : uint
{
MAILSLOT_NO_MESSAGE = 0xffffffff,
}
#endregion
/// <summary>
/// 受信イベントハンドラーのdelegate
/// </summary>
/// <param name="sender">送信元</param>
/// <param name="e">イベントオブジェクト</param>
public delegate void ReceiveEventHandler(object sender, ReceiveEventArgs e);
//イベントハンドラー
public event ReceiveEventHandler receive;
private SafeFileHandle slotHandle = null;
/// <summary>
/// メールスロットスロットハンドル
/// </summary>
public SafeFileHandle SlotHandle
{
get { return slotHandle; }
set { slotHandle = value; }
}
private bool receiveLoop = true;
/// <summary>
/// 受信ループ
/// </summary>
public bool ReceiveLoop
{
get { return receiveLoop; }
set { receiveLoop = value; }
}
/// <summary>
/// コンストラクタ
/// </summary>
public MailSlot()
{
}
/// <summary>
/// メールスロットオープン
/// </summary>
/// <param name="slot">メールスロット名</param>
/// <param name="maxMessageSize">最大メッセージ数</param>
/// <param name="readTimeout">タイムアウト</param>
public void Open(string slotName, uint maxMessageSize, uint readTimeout)
{
// メールスロットをオープンし、ハンドルをプロパティに保存
SlotHandle = CreateMailslot(slotName, maxMessageSize, readTimeout, (IntPtr)0);
}
/// <summary>
/// メールスロットクローズ
/// </summary>
public void Close()
{
// SlotHandleのnull判定がマルチスレッドでも正しく動作するようロックする
lock (this)
{
if (SlotHandle != null)
{
//メールスロットを開放する
CloseHandle(SlotHandle);
SlotHandle = null;
}
}
}
/// <summary>
/// メールスロット受信待ち
/// </summary>
public void ReadMailSlot()
{
try
{
//受信待機フラグがたっている間ループする
while (ReceiveLoop)
{
//メールスロットの件数をチェックする
uint msgMaxCnt = 1;
uint nextSize = 0;
uint msgCnt = 0;
uint timeout = 0;
//メールスロット情報取得
if (!GetMailslotInfo(SlotHandle, ref msgMaxCnt, ref nextSize, ref msgCnt, ref timeout))
{
System.Diagnostics.Debug.WriteLine("GetMailslotInfo失敗!!");
continue;
}
//メールスロット読み取り
if (msgCnt > 0 && nextSize != (uint)MailSlotStatus.MAILSLOT_NO_MESSAGE)
{
// スロットを読み取る
FileStream fs = new FileStream(SlotHandle, FileAccess.Read);
byte[] buf = new byte[msgMaxCnt];
int len = fs.Read(buf, 0, buf.Length);
//イベント発火
ReceiveEventArgs e = new ReceiveEventArgs(Encoding.UTF8.GetString(buf, 0, len));
OnReceive(e);
//処理終了フラグの確認
if (e.ReceiveEnd)
{
ReceiveLoop = false;
}
//fs.Close();
//break;
}
else
{
//待機する
Thread.Sleep(500);
}
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
System.Diagnostics.Debug.WriteLine(ex.StackTrace);
throw ex;
}
}
/// <summary>
/// 受信イベント
/// </summary>
/// <param name="e">イベントオブジェクト</param>
protected virtual void OnReceive(ReceiveEventArgs e)
{
if (receive != null)
{
receive(this, e);
}
}
#region IDisposable メンバ
/// <summary>
/// 資源の解放
/// </summary>
public void Dispose()
{
Close();
}
#endregion
/// <summary>
/// メッセージの送信
/// </summary>
/// <param name="slot">送信先スロット名</param>
/// <param name="message">送信する文字列</param>
public static void WriteMailSlot(string slot, string message)
{
try
{
//メールスロットを開く
SafeFileHandle fileHandle = CreateFile(slot,
DesiredAccess.GENERIC_READ | DesiredAccess.GENERIC_WRITE,
ShareMode.FILE_SHARE_READ | ShareMode.FILE_SHARE_WRITE,
0,
CreationDisposition.OPEN_EXISTING,
FlagsAndAttributes.FILE_ATTRIBUTE_NORMAL,
(IntPtr)0);
// 指定の文字列を出力する
using (FileStream fs = new FileStream(fileHandle, FileAccess.Write))
{
byte[] msg = Encoding.UTF8.GetBytes(message);
fs.Write(msg, 0, msg.Length);
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
System.Diagnostics.Debug.WriteLine(ex.StackTrace);
throw ex;
}
}
}
/// メールスロットの操作を行います。
/// </summary>
public class MailSlot : IDisposable
{
#region Win32 API宣言
[DllImport("kernel32.dll")]
static extern SafeFileHandle CreateMailslot(
string lpName, //メールスロット名
uint nMaxMessageSize, //最大メッセージサイズ
uint lReadTimeout, //み取りタイムアウトの間隔
IntPtr lpSecurityAttributes); //継承オプション
[DllImport("kernel32.dll")]
static extern bool GetMailslotInfo(
SafeFileHandle hMailslot, //メールスロットのハンドル
ref uint lpMaxMessageSize, //最大メッセージサイズ
ref uint lpNextSize, //次のメッセージのサイズ
ref uint lpMessageCount, //メッセージ数
ref uint lpReadTimeout); //読み取りタイムアウトの間隔
[DllImport("kernel32.dll")]
static extern bool SetMailslotInfo(
SafeFileHandle hMailslot, //メールスロットのハンドル
uint lReadTimeout); //読み取りタイムアウトの間隔
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool CloseHandle(SafeFileHandle hMailslot);
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
private static extern SafeFileHandle CreateFile(
string lpFileName, // ファイル名
DesiredAccess dwDesiredAccess, // アクセスモード
ShareMode dwShareMode, // 共有モード
int lpSecurityAttributes, // セキュリティ記述子
CreationDisposition dwCreationDisposition, // 作成方法
FlagsAndAttributes dwFlagsAndAttributes, // ファイル属性
IntPtr hTemplateFile); // テンプレートファイルのハンドル
#endregion
#region 列挙体
private enum DesiredAccess : uint
{
GENERIC_READ = 0x80000000,
GENERIC_WRITE = 0x40000000,
GENERIC_EXECUTE = 0x20000000
}
private enum ShareMode : uint
{
FILE_SHARE_READ = 0x00000001,
FILE_SHARE_WRITE = 0x00000002,
FILE_SHARE_DELETE = 0x00000004
}
private enum CreationDisposition : uint
{
CREATE_NEW = 1,
CREATE_ALWAYS = 2,
OPEN_EXISTING = 3,
OPEN_ALWAYS = 4,
TRUNCATE_EXISTING = 5
}
private enum FlagsAndAttributes : uint
{
FILE_ATTRIBUTE_ARCHIVE = 0x00000020,
FILE_ATTRIBUTE_ENCRYPTED = 0x00004000,
FILE_ATTRIBUTE_HIDDEN = 0x00000002,
FILE_ATTRIBUTE_NORMAL = 0x00000080,
FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x00002000,
FILE_ATTRIBUTE_OFFLINE = 0x00001000,
FILE_ATTRIBUTE_READONLY = 0x00000001,
FILE_ATTRIBUTE_SYSTEM = 0x00000004,
FILE_ATTRIBUTE_TEMPORARY = 0x00000100
}
private enum MailSlotStatus : uint
{
MAILSLOT_NO_MESSAGE = 0xffffffff,
}
#endregion
/// <summary>
/// 受信イベントハンドラーのdelegate
/// </summary>
/// <param name="sender">送信元</param>
/// <param name="e">イベントオブジェクト</param>
public delegate void ReceiveEventHandler(object sender, ReceiveEventArgs e);
//イベントハンドラー
public event ReceiveEventHandler receive;
private SafeFileHandle slotHandle = null;
/// <summary>
/// メールスロットスロットハンドル
/// </summary>
public SafeFileHandle SlotHandle
{
get { return slotHandle; }
set { slotHandle = value; }
}
private bool receiveLoop = true;
/// <summary>
/// 受信ループ
/// </summary>
public bool ReceiveLoop
{
get { return receiveLoop; }
set { receiveLoop = value; }
}
/// <summary>
/// コンストラクタ
/// </summary>
public MailSlot()
{
}
/// <summary>
/// メールスロットオープン
/// </summary>
/// <param name="slot">メールスロット名</param>
/// <param name="maxMessageSize">最大メッセージ数</param>
/// <param name="readTimeout">タイムアウト</param>
public void Open(string slotName, uint maxMessageSize, uint readTimeout)
{
// メールスロットをオープンし、ハンドルをプロパティに保存
SlotHandle = CreateMailslot(slotName, maxMessageSize, readTimeout, (IntPtr)0);
}
/// <summary>
/// メールスロットクローズ
/// </summary>
public void Close()
{
// SlotHandleのnull判定がマルチスレッドでも正しく動作するようロックする
lock (this)
{
if (SlotHandle != null)
{
//メールスロットを開放する
CloseHandle(SlotHandle);
SlotHandle = null;
}
}
}
/// <summary>
/// メールスロット受信待ち
/// </summary>
public void ReadMailSlot()
{
try
{
//受信待機フラグがたっている間ループする
while (ReceiveLoop)
{
//メールスロットの件数をチェックする
uint msgMaxCnt = 1;
uint nextSize = 0;
uint msgCnt = 0;
uint timeout = 0;
//メールスロット情報取得
if (!GetMailslotInfo(SlotHandle, ref msgMaxCnt, ref nextSize, ref msgCnt, ref timeout))
{
System.Diagnostics.Debug.WriteLine("GetMailslotInfo失敗!!");
continue;
}
//メールスロット読み取り
if (msgCnt > 0 && nextSize != (uint)MailSlotStatus.MAILSLOT_NO_MESSAGE)
{
// スロットを読み取る
FileStream fs = new FileStream(SlotHandle, FileAccess.Read);
byte[] buf = new byte[msgMaxCnt];
int len = fs.Read(buf, 0, buf.Length);
//イベント発火
ReceiveEventArgs e = new ReceiveEventArgs(Encoding.UTF8.GetString(buf, 0, len));
OnReceive(e);
//処理終了フラグの確認
if (e.ReceiveEnd)
{
ReceiveLoop = false;
}
//fs.Close();
//break;
}
else
{
//待機する
Thread.Sleep(500);
}
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
System.Diagnostics.Debug.WriteLine(ex.StackTrace);
throw ex;
}
}
/// <summary>
/// 受信イベント
/// </summary>
/// <param name="e">イベントオブジェクト</param>
protected virtual void OnReceive(ReceiveEventArgs e)
{
if (receive != null)
{
receive(this, e);
}
}
#region IDisposable メンバ
/// <summary>
/// 資源の解放
/// </summary>
public void Dispose()
{
Close();
}
#endregion
/// <summary>
/// メッセージの送信
/// </summary>
/// <param name="slot">送信先スロット名</param>
/// <param name="message">送信する文字列</param>
public static void WriteMailSlot(string slot, string message)
{
try
{
//メールスロットを開く
SafeFileHandle fileHandle = CreateFile(slot,
DesiredAccess.GENERIC_READ | DesiredAccess.GENERIC_WRITE,
ShareMode.FILE_SHARE_READ | ShareMode.FILE_SHARE_WRITE,
0,
CreationDisposition.OPEN_EXISTING,
FlagsAndAttributes.FILE_ATTRIBUTE_NORMAL,
(IntPtr)0);
// 指定の文字列を出力する
using (FileStream fs = new FileStream(fileHandle, FileAccess.Write))
{
byte[] msg = Encoding.UTF8.GetBytes(message);
fs.Write(msg, 0, msg.Length);
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
System.Diagnostics.Debug.WriteLine(ex.StackTrace);
throw ex;
}
}
}
以下、受信イベントオブジェクトクラスです。
/// <summary>
/// 受信イベントオブジェクト
/// </summary>
public class ReceiveEventArgs : EventArgs
{
private string message;
/// <summary>
/// 受信メッセージ
/// </summary>
public string Message
{
get { return message; }
}
private bool receiveEnd = false;
/// <summary>
/// 受信終了フラグ
/// </summary>
public bool ReceiveEnd
{
get { return receiveEnd; }
set { receiveEnd = value; }
}
/// <summary>
/// コンストラクタ
/// </summary>
/// <param name="msg">メッセージ</param>
public ReceiveEventArgs(string msg)
{
message = msg;
}
}
/// 受信イベントオブジェクト
/// </summary>
public class ReceiveEventArgs : EventArgs
{
private string message;
/// <summary>
/// 受信メッセージ
/// </summary>
public string Message
{
get { return message; }
}
private bool receiveEnd = false;
/// <summary>
/// 受信終了フラグ
/// </summary>
public bool ReceiveEnd
{
get { return receiveEnd; }
set { receiveEnd = value; }
}
/// <summary>
/// コンストラクタ
/// </summary>
/// <param name="msg">メッセージ</param>
public ReceiveEventArgs(string msg)
{
message = msg;
}
}
使うほうはこんな感じ。
/// <summary>
/// 受信ボタン押下
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnMLReceive2_Click(object sender, EventArgs e)
{
using (MailSlot slot = new MailSlot())
{
//イベントを設定後、スロットをオープンし受信ループに入る
slot.receive += new MailSlot.ReceiveEventHandler(slot_receive2);
slot.Open(txtMQPath.Text, 512, 0xffff);
slot.ReadMailSlot();
// スロットをクローズする
slot.Close();
}
}
/// <summary>
/// 受信イベント
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void slot_receive2(object sender, ReceiveEventArgs e)
{
//受信したメッセージを画面に表示
txtMQRecieve.AppendText(e.Message);
txtMQRecieve.AppendText(Environment.NewLine);
//以下の文字列が着たら受信待機をやめる
if (e.Message == "TERMINATE")
{
//MailSlot.ReadMailSlotが終了する
e.ReceiveEnd = true;
}
}
/// 受信ボタン押下
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnMLReceive2_Click(object sender, EventArgs e)
{
using (MailSlot slot = new MailSlot())
{
//イベントを設定後、スロットをオープンし受信ループに入る
slot.receive += new MailSlot.ReceiveEventHandler(slot_receive2);
slot.Open(txtMQPath.Text, 512, 0xffff);
slot.ReadMailSlot();
// スロットをクローズする
slot.Close();
}
}
/// <summary>
/// 受信イベント
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void slot_receive2(object sender, ReceiveEventArgs e)
{
//受信したメッセージを画面に表示
txtMQRecieve.AppendText(e.Message);
txtMQRecieve.AppendText(Environment.NewLine);
//以下の文字列が着たら受信待機をやめる
if (e.Message == "TERMINATE")
{
//MailSlot.ReadMailSlotが終了する
e.ReceiveEnd = true;
}
}
0 件のコメント:
コメントを投稿